##// END OF EJS Templates
ui: check for progress singleton when clearing progress bar (issue5684)...
Mark Thomas -
r34346:0e4bed5c stable
parent child Browse files
Show More
@@ -1,1787 +1,1790 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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import collections
10 import collections
11 import contextlib
11 import contextlib
12 import errno
12 import errno
13 import getpass
13 import getpass
14 import inspect
14 import inspect
15 import os
15 import os
16 import re
16 import re
17 import signal
17 import signal
18 import socket
18 import socket
19 import subprocess
19 import subprocess
20 import sys
20 import sys
21 import tempfile
21 import tempfile
22 import traceback
22 import traceback
23
23
24 from .i18n import _
24 from .i18n import _
25 from .node import hex
25 from .node import hex
26
26
27 from . import (
27 from . import (
28 color,
28 color,
29 config,
29 config,
30 configitems,
30 configitems,
31 encoding,
31 encoding,
32 error,
32 error,
33 formatter,
33 formatter,
34 progress,
34 progress,
35 pycompat,
35 pycompat,
36 rcutil,
36 rcutil,
37 scmutil,
37 scmutil,
38 util,
38 util,
39 )
39 )
40
40
41 urlreq = util.urlreq
41 urlreq = util.urlreq
42
42
43 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
43 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
44 _keepalnum = ''.join(c for c in map(pycompat.bytechr, range(256))
44 _keepalnum = ''.join(c for c in map(pycompat.bytechr, range(256))
45 if not c.isalnum())
45 if not c.isalnum())
46
46
47 # The config knobs that will be altered (if unset) by ui.tweakdefaults.
47 # The config knobs that will be altered (if unset) by ui.tweakdefaults.
48 tweakrc = """
48 tweakrc = """
49 [ui]
49 [ui]
50 # The rollback command is dangerous. As a rule, don't use it.
50 # The rollback command is dangerous. As a rule, don't use it.
51 rollback = False
51 rollback = False
52
52
53 [commands]
53 [commands]
54 # Make `hg status` emit cwd-relative paths by default.
54 # Make `hg status` emit cwd-relative paths by default.
55 status.relative = yes
55 status.relative = yes
56
56
57 [diff]
57 [diff]
58 git = 1
58 git = 1
59 """
59 """
60
60
61 samplehgrcs = {
61 samplehgrcs = {
62 'user':
62 'user':
63 """# example user config (see 'hg help config' for more info)
63 """# example user config (see 'hg help config' for more info)
64 [ui]
64 [ui]
65 # name and email, e.g.
65 # name and email, e.g.
66 # username = Jane Doe <jdoe@example.com>
66 # username = Jane Doe <jdoe@example.com>
67 username =
67 username =
68
68
69 # uncomment to disable color in command output
69 # uncomment to disable color in command output
70 # (see 'hg help color' for details)
70 # (see 'hg help color' for details)
71 # color = never
71 # color = never
72
72
73 # uncomment to disable command output pagination
73 # uncomment to disable command output pagination
74 # (see 'hg help pager' for details)
74 # (see 'hg help pager' for details)
75 # paginate = never
75 # paginate = never
76
76
77 [extensions]
77 [extensions]
78 # uncomment these lines to enable some popular extensions
78 # uncomment these lines to enable some popular extensions
79 # (see 'hg help extensions' for more info)
79 # (see 'hg help extensions' for more info)
80 #
80 #
81 # churn =
81 # churn =
82 """,
82 """,
83
83
84 'cloned':
84 'cloned':
85 """# example repository config (see 'hg help config' for more info)
85 """# example repository config (see 'hg help config' for more info)
86 [paths]
86 [paths]
87 default = %s
87 default = %s
88
88
89 # path aliases to other clones of this repo in URLs or filesystem paths
89 # path aliases to other clones of this repo in URLs or filesystem paths
90 # (see 'hg help config.paths' for more info)
90 # (see 'hg help config.paths' for more info)
91 #
91 #
92 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
92 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
93 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
93 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
94 # my-clone = /home/jdoe/jdoes-clone
94 # my-clone = /home/jdoe/jdoes-clone
95
95
96 [ui]
96 [ui]
97 # name and email (local to this repository, optional), e.g.
97 # name and email (local to this repository, optional), e.g.
98 # username = Jane Doe <jdoe@example.com>
98 # username = Jane Doe <jdoe@example.com>
99 """,
99 """,
100
100
101 'local':
101 'local':
102 """# example repository config (see 'hg help config' for more info)
102 """# example repository config (see 'hg help config' for more info)
103 [paths]
103 [paths]
104 # path aliases to other clones of this repo in URLs or filesystem paths
104 # path aliases to other clones of this repo in URLs or filesystem paths
105 # (see 'hg help config.paths' for more info)
105 # (see 'hg help config.paths' for more info)
106 #
106 #
107 # default = http://example.com/hg/example-repo
107 # default = http://example.com/hg/example-repo
108 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
108 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
109 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
109 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
110 # my-clone = /home/jdoe/jdoes-clone
110 # my-clone = /home/jdoe/jdoes-clone
111
111
112 [ui]
112 [ui]
113 # name and email (local to this repository, optional), e.g.
113 # name and email (local to this repository, optional), e.g.
114 # username = Jane Doe <jdoe@example.com>
114 # username = Jane Doe <jdoe@example.com>
115 """,
115 """,
116
116
117 'global':
117 'global':
118 """# example system-wide hg config (see 'hg help config' for more info)
118 """# example system-wide hg config (see 'hg help config' for more info)
119
119
120 [ui]
120 [ui]
121 # uncomment to disable color in command output
121 # uncomment to disable color in command output
122 # (see 'hg help color' for details)
122 # (see 'hg help color' for details)
123 # color = never
123 # color = never
124
124
125 # uncomment to disable command output pagination
125 # uncomment to disable command output pagination
126 # (see 'hg help pager' for details)
126 # (see 'hg help pager' for details)
127 # paginate = never
127 # paginate = never
128
128
129 [extensions]
129 [extensions]
130 # uncomment these lines to enable some popular extensions
130 # uncomment these lines to enable some popular extensions
131 # (see 'hg help extensions' for more info)
131 # (see 'hg help extensions' for more info)
132 #
132 #
133 # blackbox =
133 # blackbox =
134 # churn =
134 # churn =
135 """,
135 """,
136 }
136 }
137
137
138
138
139 class httppasswordmgrdbproxy(object):
139 class httppasswordmgrdbproxy(object):
140 """Delays loading urllib2 until it's needed."""
140 """Delays loading urllib2 until it's needed."""
141 def __init__(self):
141 def __init__(self):
142 self._mgr = None
142 self._mgr = None
143
143
144 def _get_mgr(self):
144 def _get_mgr(self):
145 if self._mgr is None:
145 if self._mgr is None:
146 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
146 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
147 return self._mgr
147 return self._mgr
148
148
149 def add_password(self, *args, **kwargs):
149 def add_password(self, *args, **kwargs):
150 return self._get_mgr().add_password(*args, **kwargs)
150 return self._get_mgr().add_password(*args, **kwargs)
151
151
152 def find_user_password(self, *args, **kwargs):
152 def find_user_password(self, *args, **kwargs):
153 return self._get_mgr().find_user_password(*args, **kwargs)
153 return self._get_mgr().find_user_password(*args, **kwargs)
154
154
155 def _catchterm(*args):
155 def _catchterm(*args):
156 raise error.SignalInterrupt
156 raise error.SignalInterrupt
157
157
158 # unique object used to detect no default value has been provided when
158 # unique object used to detect no default value has been provided when
159 # retrieving configuration value.
159 # retrieving configuration value.
160 _unset = object()
160 _unset = object()
161
161
162 class ui(object):
162 class ui(object):
163 def __init__(self, src=None):
163 def __init__(self, src=None):
164 """Create a fresh new ui object if no src given
164 """Create a fresh new ui object if no src given
165
165
166 Use uimod.ui.load() to create a ui which knows global and user configs.
166 Use uimod.ui.load() to create a ui which knows global and user configs.
167 In most cases, you should use ui.copy() to create a copy of an existing
167 In most cases, you should use ui.copy() to create a copy of an existing
168 ui object.
168 ui object.
169 """
169 """
170 # _buffers: used for temporary capture of output
170 # _buffers: used for temporary capture of output
171 self._buffers = []
171 self._buffers = []
172 # _exithandlers: callbacks run at the end of a request
172 # _exithandlers: callbacks run at the end of a request
173 self._exithandlers = []
173 self._exithandlers = []
174 # 3-tuple describing how each buffer in the stack behaves.
174 # 3-tuple describing how each buffer in the stack behaves.
175 # Values are (capture stderr, capture subprocesses, apply labels).
175 # Values are (capture stderr, capture subprocesses, apply labels).
176 self._bufferstates = []
176 self._bufferstates = []
177 # When a buffer is active, defines whether we are expanding labels.
177 # When a buffer is active, defines whether we are expanding labels.
178 # This exists to prevent an extra list lookup.
178 # This exists to prevent an extra list lookup.
179 self._bufferapplylabels = None
179 self._bufferapplylabels = None
180 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
180 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
181 self._reportuntrusted = True
181 self._reportuntrusted = True
182 self._knownconfig = configitems.coreitems
182 self._knownconfig = configitems.coreitems
183 self._ocfg = config.config() # overlay
183 self._ocfg = config.config() # overlay
184 self._tcfg = config.config() # trusted
184 self._tcfg = config.config() # trusted
185 self._ucfg = config.config() # untrusted
185 self._ucfg = config.config() # untrusted
186 self._trustusers = set()
186 self._trustusers = set()
187 self._trustgroups = set()
187 self._trustgroups = set()
188 self.callhooks = True
188 self.callhooks = True
189 # Insecure server connections requested.
189 # Insecure server connections requested.
190 self.insecureconnections = False
190 self.insecureconnections = False
191 # Blocked time
191 # Blocked time
192 self.logblockedtimes = False
192 self.logblockedtimes = False
193 # color mode: see mercurial/color.py for possible value
193 # color mode: see mercurial/color.py for possible value
194 self._colormode = None
194 self._colormode = None
195 self._terminfoparams = {}
195 self._terminfoparams = {}
196 self._styles = {}
196 self._styles = {}
197
197
198 if src:
198 if src:
199 self._exithandlers = src._exithandlers
199 self._exithandlers = src._exithandlers
200 self.fout = src.fout
200 self.fout = src.fout
201 self.ferr = src.ferr
201 self.ferr = src.ferr
202 self.fin = src.fin
202 self.fin = src.fin
203 self.pageractive = src.pageractive
203 self.pageractive = src.pageractive
204 self._disablepager = src._disablepager
204 self._disablepager = src._disablepager
205 self._tweaked = src._tweaked
205 self._tweaked = src._tweaked
206
206
207 self._tcfg = src._tcfg.copy()
207 self._tcfg = src._tcfg.copy()
208 self._ucfg = src._ucfg.copy()
208 self._ucfg = src._ucfg.copy()
209 self._ocfg = src._ocfg.copy()
209 self._ocfg = src._ocfg.copy()
210 self._trustusers = src._trustusers.copy()
210 self._trustusers = src._trustusers.copy()
211 self._trustgroups = src._trustgroups.copy()
211 self._trustgroups = src._trustgroups.copy()
212 self.environ = src.environ
212 self.environ = src.environ
213 self.callhooks = src.callhooks
213 self.callhooks = src.callhooks
214 self.insecureconnections = src.insecureconnections
214 self.insecureconnections = src.insecureconnections
215 self._colormode = src._colormode
215 self._colormode = src._colormode
216 self._terminfoparams = src._terminfoparams.copy()
216 self._terminfoparams = src._terminfoparams.copy()
217 self._styles = src._styles.copy()
217 self._styles = src._styles.copy()
218
218
219 self.fixconfig()
219 self.fixconfig()
220
220
221 self.httppasswordmgrdb = src.httppasswordmgrdb
221 self.httppasswordmgrdb = src.httppasswordmgrdb
222 self._blockedtimes = src._blockedtimes
222 self._blockedtimes = src._blockedtimes
223 else:
223 else:
224 self.fout = util.stdout
224 self.fout = util.stdout
225 self.ferr = util.stderr
225 self.ferr = util.stderr
226 self.fin = util.stdin
226 self.fin = util.stdin
227 self.pageractive = False
227 self.pageractive = False
228 self._disablepager = False
228 self._disablepager = False
229 self._tweaked = False
229 self._tweaked = False
230
230
231 # shared read-only environment
231 # shared read-only environment
232 self.environ = encoding.environ
232 self.environ = encoding.environ
233
233
234 self.httppasswordmgrdb = httppasswordmgrdbproxy()
234 self.httppasswordmgrdb = httppasswordmgrdbproxy()
235 self._blockedtimes = collections.defaultdict(int)
235 self._blockedtimes = collections.defaultdict(int)
236
236
237 allowed = self.configlist('experimental', 'exportableenviron')
237 allowed = self.configlist('experimental', 'exportableenviron')
238 if '*' in allowed:
238 if '*' in allowed:
239 self._exportableenviron = self.environ
239 self._exportableenviron = self.environ
240 else:
240 else:
241 self._exportableenviron = {}
241 self._exportableenviron = {}
242 for k in allowed:
242 for k in allowed:
243 if k in self.environ:
243 if k in self.environ:
244 self._exportableenviron[k] = self.environ[k]
244 self._exportableenviron[k] = self.environ[k]
245
245
246 @classmethod
246 @classmethod
247 def load(cls):
247 def load(cls):
248 """Create a ui and load global and user configs"""
248 """Create a ui and load global and user configs"""
249 u = cls()
249 u = cls()
250 # we always trust global config files and environment variables
250 # we always trust global config files and environment variables
251 for t, f in rcutil.rccomponents():
251 for t, f in rcutil.rccomponents():
252 if t == 'path':
252 if t == 'path':
253 u.readconfig(f, trust=True)
253 u.readconfig(f, trust=True)
254 elif t == 'items':
254 elif t == 'items':
255 sections = set()
255 sections = set()
256 for section, name, value, source in f:
256 for section, name, value, source in f:
257 # do not set u._ocfg
257 # do not set u._ocfg
258 # XXX clean this up once immutable config object is a thing
258 # XXX clean this up once immutable config object is a thing
259 u._tcfg.set(section, name, value, source)
259 u._tcfg.set(section, name, value, source)
260 u._ucfg.set(section, name, value, source)
260 u._ucfg.set(section, name, value, source)
261 sections.add(section)
261 sections.add(section)
262 for section in sections:
262 for section in sections:
263 u.fixconfig(section=section)
263 u.fixconfig(section=section)
264 else:
264 else:
265 raise error.ProgrammingError('unknown rctype: %s' % t)
265 raise error.ProgrammingError('unknown rctype: %s' % t)
266 u._maybetweakdefaults()
266 u._maybetweakdefaults()
267 return u
267 return u
268
268
269 def _maybetweakdefaults(self):
269 def _maybetweakdefaults(self):
270 if not self.configbool('ui', 'tweakdefaults'):
270 if not self.configbool('ui', 'tweakdefaults'):
271 return
271 return
272 if self._tweaked or self.plain('tweakdefaults'):
272 if self._tweaked or self.plain('tweakdefaults'):
273 return
273 return
274
274
275 # Note: it is SUPER IMPORTANT that you set self._tweaked to
275 # Note: it is SUPER IMPORTANT that you set self._tweaked to
276 # True *before* any calls to setconfig(), otherwise you'll get
276 # True *before* any calls to setconfig(), otherwise you'll get
277 # infinite recursion between setconfig and this method.
277 # infinite recursion between setconfig and this method.
278 #
278 #
279 # TODO: We should extract an inner method in setconfig() to
279 # TODO: We should extract an inner method in setconfig() to
280 # avoid this weirdness.
280 # avoid this weirdness.
281 self._tweaked = True
281 self._tweaked = True
282 tmpcfg = config.config()
282 tmpcfg = config.config()
283 tmpcfg.parse('<tweakdefaults>', tweakrc)
283 tmpcfg.parse('<tweakdefaults>', tweakrc)
284 for section in tmpcfg:
284 for section in tmpcfg:
285 for name, value in tmpcfg.items(section):
285 for name, value in tmpcfg.items(section):
286 if not self.hasconfig(section, name):
286 if not self.hasconfig(section, name):
287 self.setconfig(section, name, value, "<tweakdefaults>")
287 self.setconfig(section, name, value, "<tweakdefaults>")
288
288
289 def copy(self):
289 def copy(self):
290 return self.__class__(self)
290 return self.__class__(self)
291
291
292 def resetstate(self):
292 def resetstate(self):
293 """Clear internal state that shouldn't persist across commands"""
293 """Clear internal state that shouldn't persist across commands"""
294 if self._progbar:
294 if self._progbar:
295 self._progbar.resetstate() # reset last-print time of progress bar
295 self._progbar.resetstate() # reset last-print time of progress bar
296 self.httppasswordmgrdb = httppasswordmgrdbproxy()
296 self.httppasswordmgrdb = httppasswordmgrdbproxy()
297
297
298 @contextlib.contextmanager
298 @contextlib.contextmanager
299 def timeblockedsection(self, key):
299 def timeblockedsection(self, key):
300 # this is open-coded below - search for timeblockedsection to find them
300 # this is open-coded below - search for timeblockedsection to find them
301 starttime = util.timer()
301 starttime = util.timer()
302 try:
302 try:
303 yield
303 yield
304 finally:
304 finally:
305 self._blockedtimes[key + '_blocked'] += \
305 self._blockedtimes[key + '_blocked'] += \
306 (util.timer() - starttime) * 1000
306 (util.timer() - starttime) * 1000
307
307
308 def formatter(self, topic, opts):
308 def formatter(self, topic, opts):
309 return formatter.formatter(self, self, topic, opts)
309 return formatter.formatter(self, self, topic, opts)
310
310
311 def _trusted(self, fp, f):
311 def _trusted(self, fp, f):
312 st = util.fstat(fp)
312 st = util.fstat(fp)
313 if util.isowner(st):
313 if util.isowner(st):
314 return True
314 return True
315
315
316 tusers, tgroups = self._trustusers, self._trustgroups
316 tusers, tgroups = self._trustusers, self._trustgroups
317 if '*' in tusers or '*' in tgroups:
317 if '*' in tusers or '*' in tgroups:
318 return True
318 return True
319
319
320 user = util.username(st.st_uid)
320 user = util.username(st.st_uid)
321 group = util.groupname(st.st_gid)
321 group = util.groupname(st.st_gid)
322 if user in tusers or group in tgroups or user == util.username():
322 if user in tusers or group in tgroups or user == util.username():
323 return True
323 return True
324
324
325 if self._reportuntrusted:
325 if self._reportuntrusted:
326 self.warn(_('not trusting file %s from untrusted '
326 self.warn(_('not trusting file %s from untrusted '
327 'user %s, group %s\n') % (f, user, group))
327 'user %s, group %s\n') % (f, user, group))
328 return False
328 return False
329
329
330 def readconfig(self, filename, root=None, trust=False,
330 def readconfig(self, filename, root=None, trust=False,
331 sections=None, remap=None):
331 sections=None, remap=None):
332 try:
332 try:
333 fp = open(filename, u'rb')
333 fp = open(filename, u'rb')
334 except IOError:
334 except IOError:
335 if not sections: # ignore unless we were looking for something
335 if not sections: # ignore unless we were looking for something
336 return
336 return
337 raise
337 raise
338
338
339 cfg = config.config()
339 cfg = config.config()
340 trusted = sections or trust or self._trusted(fp, filename)
340 trusted = sections or trust or self._trusted(fp, filename)
341
341
342 try:
342 try:
343 cfg.read(filename, fp, sections=sections, remap=remap)
343 cfg.read(filename, fp, sections=sections, remap=remap)
344 fp.close()
344 fp.close()
345 except error.ConfigError as inst:
345 except error.ConfigError as inst:
346 if trusted:
346 if trusted:
347 raise
347 raise
348 self.warn(_("ignored: %s\n") % str(inst))
348 self.warn(_("ignored: %s\n") % str(inst))
349
349
350 if self.plain():
350 if self.plain():
351 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
351 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
352 'logtemplate', 'statuscopies', 'style',
352 'logtemplate', 'statuscopies', 'style',
353 'traceback', 'verbose'):
353 'traceback', 'verbose'):
354 if k in cfg['ui']:
354 if k in cfg['ui']:
355 del cfg['ui'][k]
355 del cfg['ui'][k]
356 for k, v in cfg.items('defaults'):
356 for k, v in cfg.items('defaults'):
357 del cfg['defaults'][k]
357 del cfg['defaults'][k]
358 for k, v in cfg.items('commands'):
358 for k, v in cfg.items('commands'):
359 del cfg['commands'][k]
359 del cfg['commands'][k]
360 # Don't remove aliases from the configuration if in the exceptionlist
360 # Don't remove aliases from the configuration if in the exceptionlist
361 if self.plain('alias'):
361 if self.plain('alias'):
362 for k, v in cfg.items('alias'):
362 for k, v in cfg.items('alias'):
363 del cfg['alias'][k]
363 del cfg['alias'][k]
364 if self.plain('revsetalias'):
364 if self.plain('revsetalias'):
365 for k, v in cfg.items('revsetalias'):
365 for k, v in cfg.items('revsetalias'):
366 del cfg['revsetalias'][k]
366 del cfg['revsetalias'][k]
367 if self.plain('templatealias'):
367 if self.plain('templatealias'):
368 for k, v in cfg.items('templatealias'):
368 for k, v in cfg.items('templatealias'):
369 del cfg['templatealias'][k]
369 del cfg['templatealias'][k]
370
370
371 if trusted:
371 if trusted:
372 self._tcfg.update(cfg)
372 self._tcfg.update(cfg)
373 self._tcfg.update(self._ocfg)
373 self._tcfg.update(self._ocfg)
374 self._ucfg.update(cfg)
374 self._ucfg.update(cfg)
375 self._ucfg.update(self._ocfg)
375 self._ucfg.update(self._ocfg)
376
376
377 if root is None:
377 if root is None:
378 root = os.path.expanduser('~')
378 root = os.path.expanduser('~')
379 self.fixconfig(root=root)
379 self.fixconfig(root=root)
380
380
381 def fixconfig(self, root=None, section=None):
381 def fixconfig(self, root=None, section=None):
382 if section in (None, 'paths'):
382 if section in (None, 'paths'):
383 # expand vars and ~
383 # expand vars and ~
384 # translate paths relative to root (or home) into absolute paths
384 # translate paths relative to root (or home) into absolute paths
385 root = root or pycompat.getcwd()
385 root = root or pycompat.getcwd()
386 for c in self._tcfg, self._ucfg, self._ocfg:
386 for c in self._tcfg, self._ucfg, self._ocfg:
387 for n, p in c.items('paths'):
387 for n, p in c.items('paths'):
388 # Ignore sub-options.
388 # Ignore sub-options.
389 if ':' in n:
389 if ':' in n:
390 continue
390 continue
391 if not p:
391 if not p:
392 continue
392 continue
393 if '%%' in p:
393 if '%%' in p:
394 s = self.configsource('paths', n) or 'none'
394 s = self.configsource('paths', n) or 'none'
395 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
395 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
396 % (n, p, s))
396 % (n, p, s))
397 p = p.replace('%%', '%')
397 p = p.replace('%%', '%')
398 p = util.expandpath(p)
398 p = util.expandpath(p)
399 if not util.hasscheme(p) and not os.path.isabs(p):
399 if not util.hasscheme(p) and not os.path.isabs(p):
400 p = os.path.normpath(os.path.join(root, p))
400 p = os.path.normpath(os.path.join(root, p))
401 c.set("paths", n, p)
401 c.set("paths", n, p)
402
402
403 if section in (None, 'ui'):
403 if section in (None, 'ui'):
404 # update ui options
404 # update ui options
405 self.debugflag = self.configbool('ui', 'debug')
405 self.debugflag = self.configbool('ui', 'debug')
406 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
406 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
407 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
407 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
408 if self.verbose and self.quiet:
408 if self.verbose and self.quiet:
409 self.quiet = self.verbose = False
409 self.quiet = self.verbose = False
410 self._reportuntrusted = self.debugflag or self.configbool("ui",
410 self._reportuntrusted = self.debugflag or self.configbool("ui",
411 "report_untrusted")
411 "report_untrusted")
412 self.tracebackflag = self.configbool('ui', 'traceback')
412 self.tracebackflag = self.configbool('ui', 'traceback')
413 self.logblockedtimes = self.configbool('ui', 'logblockedtimes')
413 self.logblockedtimes = self.configbool('ui', 'logblockedtimes')
414
414
415 if section in (None, 'trusted'):
415 if section in (None, 'trusted'):
416 # update trust information
416 # update trust information
417 self._trustusers.update(self.configlist('trusted', 'users'))
417 self._trustusers.update(self.configlist('trusted', 'users'))
418 self._trustgroups.update(self.configlist('trusted', 'groups'))
418 self._trustgroups.update(self.configlist('trusted', 'groups'))
419
419
420 def backupconfig(self, section, item):
420 def backupconfig(self, section, item):
421 return (self._ocfg.backup(section, item),
421 return (self._ocfg.backup(section, item),
422 self._tcfg.backup(section, item),
422 self._tcfg.backup(section, item),
423 self._ucfg.backup(section, item),)
423 self._ucfg.backup(section, item),)
424 def restoreconfig(self, data):
424 def restoreconfig(self, data):
425 self._ocfg.restore(data[0])
425 self._ocfg.restore(data[0])
426 self._tcfg.restore(data[1])
426 self._tcfg.restore(data[1])
427 self._ucfg.restore(data[2])
427 self._ucfg.restore(data[2])
428
428
429 def setconfig(self, section, name, value, source=''):
429 def setconfig(self, section, name, value, source=''):
430 for cfg in (self._ocfg, self._tcfg, self._ucfg):
430 for cfg in (self._ocfg, self._tcfg, self._ucfg):
431 cfg.set(section, name, value, source)
431 cfg.set(section, name, value, source)
432 self.fixconfig(section=section)
432 self.fixconfig(section=section)
433 self._maybetweakdefaults()
433 self._maybetweakdefaults()
434
434
435 def _data(self, untrusted):
435 def _data(self, untrusted):
436 return untrusted and self._ucfg or self._tcfg
436 return untrusted and self._ucfg or self._tcfg
437
437
438 def configsource(self, section, name, untrusted=False):
438 def configsource(self, section, name, untrusted=False):
439 return self._data(untrusted).source(section, name)
439 return self._data(untrusted).source(section, name)
440
440
441 def config(self, section, name, default=_unset, untrusted=False):
441 def config(self, section, name, default=_unset, untrusted=False):
442 """return the plain string version of a config"""
442 """return the plain string version of a config"""
443 value = self._config(section, name, default=default,
443 value = self._config(section, name, default=default,
444 untrusted=untrusted)
444 untrusted=untrusted)
445 if value is _unset:
445 if value is _unset:
446 return None
446 return None
447 return value
447 return value
448
448
449 def _config(self, section, name, default=_unset, untrusted=False):
449 def _config(self, section, name, default=_unset, untrusted=False):
450 value = default
450 value = default
451 item = self._knownconfig.get(section, {}).get(name)
451 item = self._knownconfig.get(section, {}).get(name)
452 alternates = [(section, name)]
452 alternates = [(section, name)]
453
453
454 if item is not None:
454 if item is not None:
455 alternates.extend(item.alias)
455 alternates.extend(item.alias)
456
456
457 if default is _unset:
457 if default is _unset:
458 if item is None:
458 if item is None:
459 value = default
459 value = default
460 elif item.default is configitems.dynamicdefault:
460 elif item.default is configitems.dynamicdefault:
461 value = None
461 value = None
462 msg = "config item requires an explicit default value: '%s.%s'"
462 msg = "config item requires an explicit default value: '%s.%s'"
463 msg %= (section, name)
463 msg %= (section, name)
464 self.develwarn(msg, 2, 'warn-config-default')
464 self.develwarn(msg, 2, 'warn-config-default')
465 elif callable(item.default):
465 elif callable(item.default):
466 value = item.default()
466 value = item.default()
467 else:
467 else:
468 value = item.default
468 value = item.default
469 elif (item is not None
469 elif (item is not None
470 and item.default is not configitems.dynamicdefault):
470 and item.default is not configitems.dynamicdefault):
471 msg = ("specifying a default value for a registered "
471 msg = ("specifying a default value for a registered "
472 "config item: '%s.%s' '%s'")
472 "config item: '%s.%s' '%s'")
473 msg %= (section, name, default)
473 msg %= (section, name, default)
474 self.develwarn(msg, 2, 'warn-config-default')
474 self.develwarn(msg, 2, 'warn-config-default')
475
475
476 for s, n in alternates:
476 for s, n in alternates:
477 candidate = self._data(untrusted).get(s, n, None)
477 candidate = self._data(untrusted).get(s, n, None)
478 if candidate is not None:
478 if candidate is not None:
479 value = candidate
479 value = candidate
480 section = s
480 section = s
481 name = n
481 name = n
482 break
482 break
483
483
484 if self.debugflag and not untrusted and self._reportuntrusted:
484 if self.debugflag and not untrusted and self._reportuntrusted:
485 for s, n in alternates:
485 for s, n in alternates:
486 uvalue = self._ucfg.get(s, n)
486 uvalue = self._ucfg.get(s, n)
487 if uvalue is not None and uvalue != value:
487 if uvalue is not None and uvalue != value:
488 self.debug("ignoring untrusted configuration option "
488 self.debug("ignoring untrusted configuration option "
489 "%s.%s = %s\n" % (s, n, uvalue))
489 "%s.%s = %s\n" % (s, n, uvalue))
490 return value
490 return value
491
491
492 def configsuboptions(self, section, name, default=_unset, untrusted=False):
492 def configsuboptions(self, section, name, default=_unset, untrusted=False):
493 """Get a config option and all sub-options.
493 """Get a config option and all sub-options.
494
494
495 Some config options have sub-options that are declared with the
495 Some config options have sub-options that are declared with the
496 format "key:opt = value". This method is used to return the main
496 format "key:opt = value". This method is used to return the main
497 option and all its declared sub-options.
497 option and all its declared sub-options.
498
498
499 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
499 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
500 is a dict of defined sub-options where keys and values are strings.
500 is a dict of defined sub-options where keys and values are strings.
501 """
501 """
502 main = self.config(section, name, default, untrusted=untrusted)
502 main = self.config(section, name, default, untrusted=untrusted)
503 data = self._data(untrusted)
503 data = self._data(untrusted)
504 sub = {}
504 sub = {}
505 prefix = '%s:' % name
505 prefix = '%s:' % name
506 for k, v in data.items(section):
506 for k, v in data.items(section):
507 if k.startswith(prefix):
507 if k.startswith(prefix):
508 sub[k[len(prefix):]] = v
508 sub[k[len(prefix):]] = v
509
509
510 if self.debugflag and not untrusted and self._reportuntrusted:
510 if self.debugflag and not untrusted and self._reportuntrusted:
511 for k, v in sub.items():
511 for k, v in sub.items():
512 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
512 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
513 if uvalue is not None and uvalue != v:
513 if uvalue is not None and uvalue != v:
514 self.debug('ignoring untrusted configuration option '
514 self.debug('ignoring untrusted configuration option '
515 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
515 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
516
516
517 return main, sub
517 return main, sub
518
518
519 def configpath(self, section, name, default=_unset, untrusted=False):
519 def configpath(self, section, name, default=_unset, untrusted=False):
520 'get a path config item, expanded relative to repo root or config file'
520 'get a path config item, expanded relative to repo root or config file'
521 v = self.config(section, name, default, untrusted)
521 v = self.config(section, name, default, untrusted)
522 if v is None:
522 if v is None:
523 return None
523 return None
524 if not os.path.isabs(v) or "://" not in v:
524 if not os.path.isabs(v) or "://" not in v:
525 src = self.configsource(section, name, untrusted)
525 src = self.configsource(section, name, untrusted)
526 if ':' in src:
526 if ':' in src:
527 base = os.path.dirname(src.rsplit(':')[0])
527 base = os.path.dirname(src.rsplit(':')[0])
528 v = os.path.join(base, os.path.expanduser(v))
528 v = os.path.join(base, os.path.expanduser(v))
529 return v
529 return v
530
530
531 def configbool(self, section, name, default=_unset, untrusted=False):
531 def configbool(self, section, name, default=_unset, untrusted=False):
532 """parse a configuration element as a boolean
532 """parse a configuration element as a boolean
533
533
534 >>> u = ui(); s = 'foo'
534 >>> u = ui(); s = 'foo'
535 >>> u.setconfig(s, 'true', 'yes')
535 >>> u.setconfig(s, 'true', 'yes')
536 >>> u.configbool(s, 'true')
536 >>> u.configbool(s, 'true')
537 True
537 True
538 >>> u.setconfig(s, 'false', 'no')
538 >>> u.setconfig(s, 'false', 'no')
539 >>> u.configbool(s, 'false')
539 >>> u.configbool(s, 'false')
540 False
540 False
541 >>> u.configbool(s, 'unknown')
541 >>> u.configbool(s, 'unknown')
542 False
542 False
543 >>> u.configbool(s, 'unknown', True)
543 >>> u.configbool(s, 'unknown', True)
544 True
544 True
545 >>> u.setconfig(s, 'invalid', 'somevalue')
545 >>> u.setconfig(s, 'invalid', 'somevalue')
546 >>> u.configbool(s, 'invalid')
546 >>> u.configbool(s, 'invalid')
547 Traceback (most recent call last):
547 Traceback (most recent call last):
548 ...
548 ...
549 ConfigError: foo.invalid is not a boolean ('somevalue')
549 ConfigError: foo.invalid is not a boolean ('somevalue')
550 """
550 """
551
551
552 v = self._config(section, name, default, untrusted=untrusted)
552 v = self._config(section, name, default, untrusted=untrusted)
553 if v is None:
553 if v is None:
554 return v
554 return v
555 if v is _unset:
555 if v is _unset:
556 if default is _unset:
556 if default is _unset:
557 return False
557 return False
558 return default
558 return default
559 if isinstance(v, bool):
559 if isinstance(v, bool):
560 return v
560 return v
561 b = util.parsebool(v)
561 b = util.parsebool(v)
562 if b is None:
562 if b is None:
563 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
563 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
564 % (section, name, v))
564 % (section, name, v))
565 return b
565 return b
566
566
567 def configwith(self, convert, section, name, default=_unset,
567 def configwith(self, convert, section, name, default=_unset,
568 desc=None, untrusted=False):
568 desc=None, untrusted=False):
569 """parse a configuration element with a conversion function
569 """parse a configuration element with a conversion function
570
570
571 >>> u = ui(); s = 'foo'
571 >>> u = ui(); s = 'foo'
572 >>> u.setconfig(s, 'float1', '42')
572 >>> u.setconfig(s, 'float1', '42')
573 >>> u.configwith(float, s, 'float1')
573 >>> u.configwith(float, s, 'float1')
574 42.0
574 42.0
575 >>> u.setconfig(s, 'float2', '-4.25')
575 >>> u.setconfig(s, 'float2', '-4.25')
576 >>> u.configwith(float, s, 'float2')
576 >>> u.configwith(float, s, 'float2')
577 -4.25
577 -4.25
578 >>> u.configwith(float, s, 'unknown', 7)
578 >>> u.configwith(float, s, 'unknown', 7)
579 7.0
579 7.0
580 >>> u.setconfig(s, 'invalid', 'somevalue')
580 >>> u.setconfig(s, 'invalid', 'somevalue')
581 >>> u.configwith(float, s, 'invalid')
581 >>> u.configwith(float, s, 'invalid')
582 Traceback (most recent call last):
582 Traceback (most recent call last):
583 ...
583 ...
584 ConfigError: foo.invalid is not a valid float ('somevalue')
584 ConfigError: foo.invalid is not a valid float ('somevalue')
585 >>> u.configwith(float, s, 'invalid', desc='womble')
585 >>> u.configwith(float, s, 'invalid', desc='womble')
586 Traceback (most recent call last):
586 Traceback (most recent call last):
587 ...
587 ...
588 ConfigError: foo.invalid is not a valid womble ('somevalue')
588 ConfigError: foo.invalid is not a valid womble ('somevalue')
589 """
589 """
590
590
591 v = self.config(section, name, default, untrusted)
591 v = self.config(section, name, default, untrusted)
592 if v is None:
592 if v is None:
593 return v # do not attempt to convert None
593 return v # do not attempt to convert None
594 try:
594 try:
595 return convert(v)
595 return convert(v)
596 except (ValueError, error.ParseError):
596 except (ValueError, error.ParseError):
597 if desc is None:
597 if desc is None:
598 desc = convert.__name__
598 desc = convert.__name__
599 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
599 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
600 % (section, name, desc, v))
600 % (section, name, desc, v))
601
601
602 def configint(self, section, name, default=_unset, untrusted=False):
602 def configint(self, section, name, default=_unset, untrusted=False):
603 """parse a configuration element as an integer
603 """parse a configuration element as an integer
604
604
605 >>> u = ui(); s = 'foo'
605 >>> u = ui(); s = 'foo'
606 >>> u.setconfig(s, 'int1', '42')
606 >>> u.setconfig(s, 'int1', '42')
607 >>> u.configint(s, 'int1')
607 >>> u.configint(s, 'int1')
608 42
608 42
609 >>> u.setconfig(s, 'int2', '-42')
609 >>> u.setconfig(s, 'int2', '-42')
610 >>> u.configint(s, 'int2')
610 >>> u.configint(s, 'int2')
611 -42
611 -42
612 >>> u.configint(s, 'unknown', 7)
612 >>> u.configint(s, 'unknown', 7)
613 7
613 7
614 >>> u.setconfig(s, 'invalid', 'somevalue')
614 >>> u.setconfig(s, 'invalid', 'somevalue')
615 >>> u.configint(s, 'invalid')
615 >>> u.configint(s, 'invalid')
616 Traceback (most recent call last):
616 Traceback (most recent call last):
617 ...
617 ...
618 ConfigError: foo.invalid is not a valid integer ('somevalue')
618 ConfigError: foo.invalid is not a valid integer ('somevalue')
619 """
619 """
620
620
621 return self.configwith(int, section, name, default, 'integer',
621 return self.configwith(int, section, name, default, 'integer',
622 untrusted)
622 untrusted)
623
623
624 def configbytes(self, section, name, default=_unset, untrusted=False):
624 def configbytes(self, section, name, default=_unset, untrusted=False):
625 """parse a configuration element as a quantity in bytes
625 """parse a configuration element as a quantity in bytes
626
626
627 Units can be specified as b (bytes), k or kb (kilobytes), m or
627 Units can be specified as b (bytes), k or kb (kilobytes), m or
628 mb (megabytes), g or gb (gigabytes).
628 mb (megabytes), g or gb (gigabytes).
629
629
630 >>> u = ui(); s = 'foo'
630 >>> u = ui(); s = 'foo'
631 >>> u.setconfig(s, 'val1', '42')
631 >>> u.setconfig(s, 'val1', '42')
632 >>> u.configbytes(s, 'val1')
632 >>> u.configbytes(s, 'val1')
633 42
633 42
634 >>> u.setconfig(s, 'val2', '42.5 kb')
634 >>> u.setconfig(s, 'val2', '42.5 kb')
635 >>> u.configbytes(s, 'val2')
635 >>> u.configbytes(s, 'val2')
636 43520
636 43520
637 >>> u.configbytes(s, 'unknown', '7 MB')
637 >>> u.configbytes(s, 'unknown', '7 MB')
638 7340032
638 7340032
639 >>> u.setconfig(s, 'invalid', 'somevalue')
639 >>> u.setconfig(s, 'invalid', 'somevalue')
640 >>> u.configbytes(s, 'invalid')
640 >>> u.configbytes(s, 'invalid')
641 Traceback (most recent call last):
641 Traceback (most recent call last):
642 ...
642 ...
643 ConfigError: foo.invalid is not a byte quantity ('somevalue')
643 ConfigError: foo.invalid is not a byte quantity ('somevalue')
644 """
644 """
645
645
646 value = self._config(section, name, default, untrusted)
646 value = self._config(section, name, default, untrusted)
647 if value is _unset:
647 if value is _unset:
648 if default is _unset:
648 if default is _unset:
649 default = 0
649 default = 0
650 value = default
650 value = default
651 if not isinstance(value, bytes):
651 if not isinstance(value, bytes):
652 return value
652 return value
653 try:
653 try:
654 return util.sizetoint(value)
654 return util.sizetoint(value)
655 except error.ParseError:
655 except error.ParseError:
656 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
656 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
657 % (section, name, value))
657 % (section, name, value))
658
658
659 def configlist(self, section, name, default=_unset, untrusted=False):
659 def configlist(self, section, name, default=_unset, untrusted=False):
660 """parse a configuration element as a list of comma/space separated
660 """parse a configuration element as a list of comma/space separated
661 strings
661 strings
662
662
663 >>> u = ui(); s = 'foo'
663 >>> u = ui(); s = 'foo'
664 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
664 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
665 >>> u.configlist(s, 'list1')
665 >>> u.configlist(s, 'list1')
666 ['this', 'is', 'a small', 'test']
666 ['this', 'is', 'a small', 'test']
667 """
667 """
668 # default is not always a list
668 # default is not always a list
669 v = self.configwith(config.parselist, section, name, default,
669 v = self.configwith(config.parselist, section, name, default,
670 'list', untrusted)
670 'list', untrusted)
671 if isinstance(v, bytes):
671 if isinstance(v, bytes):
672 return config.parselist(v)
672 return config.parselist(v)
673 elif v is None:
673 elif v is None:
674 return []
674 return []
675 return v
675 return v
676
676
677 def configdate(self, section, name, default=_unset, untrusted=False):
677 def configdate(self, section, name, default=_unset, untrusted=False):
678 """parse a configuration element as a tuple of ints
678 """parse a configuration element as a tuple of ints
679
679
680 >>> u = ui(); s = 'foo'
680 >>> u = ui(); s = 'foo'
681 >>> u.setconfig(s, 'date', '0 0')
681 >>> u.setconfig(s, 'date', '0 0')
682 >>> u.configdate(s, 'date')
682 >>> u.configdate(s, 'date')
683 (0, 0)
683 (0, 0)
684 """
684 """
685 if self.config(section, name, default, untrusted):
685 if self.config(section, name, default, untrusted):
686 return self.configwith(util.parsedate, section, name, default,
686 return self.configwith(util.parsedate, section, name, default,
687 'date', untrusted)
687 'date', untrusted)
688 if default is _unset:
688 if default is _unset:
689 return None
689 return None
690 return default
690 return default
691
691
692 def hasconfig(self, section, name, untrusted=False):
692 def hasconfig(self, section, name, untrusted=False):
693 return self._data(untrusted).hasitem(section, name)
693 return self._data(untrusted).hasitem(section, name)
694
694
695 def has_section(self, section, untrusted=False):
695 def has_section(self, section, untrusted=False):
696 '''tell whether section exists in config.'''
696 '''tell whether section exists in config.'''
697 return section in self._data(untrusted)
697 return section in self._data(untrusted)
698
698
699 def configitems(self, section, untrusted=False, ignoresub=False):
699 def configitems(self, section, untrusted=False, ignoresub=False):
700 items = self._data(untrusted).items(section)
700 items = self._data(untrusted).items(section)
701 if ignoresub:
701 if ignoresub:
702 newitems = {}
702 newitems = {}
703 for k, v in items:
703 for k, v in items:
704 if ':' not in k:
704 if ':' not in k:
705 newitems[k] = v
705 newitems[k] = v
706 items = newitems.items()
706 items = newitems.items()
707 if self.debugflag and not untrusted and self._reportuntrusted:
707 if self.debugflag and not untrusted and self._reportuntrusted:
708 for k, v in self._ucfg.items(section):
708 for k, v in self._ucfg.items(section):
709 if self._tcfg.get(section, k) != v:
709 if self._tcfg.get(section, k) != v:
710 self.debug("ignoring untrusted configuration option "
710 self.debug("ignoring untrusted configuration option "
711 "%s.%s = %s\n" % (section, k, v))
711 "%s.%s = %s\n" % (section, k, v))
712 return items
712 return items
713
713
714 def walkconfig(self, untrusted=False):
714 def walkconfig(self, untrusted=False):
715 cfg = self._data(untrusted)
715 cfg = self._data(untrusted)
716 for section in cfg.sections():
716 for section in cfg.sections():
717 for name, value in self.configitems(section, untrusted):
717 for name, value in self.configitems(section, untrusted):
718 yield section, name, value
718 yield section, name, value
719
719
720 def plain(self, feature=None):
720 def plain(self, feature=None):
721 '''is plain mode active?
721 '''is plain mode active?
722
722
723 Plain mode means that all configuration variables which affect
723 Plain mode means that all configuration variables which affect
724 the behavior and output of Mercurial should be
724 the behavior and output of Mercurial should be
725 ignored. Additionally, the output should be stable,
725 ignored. Additionally, the output should be stable,
726 reproducible and suitable for use in scripts or applications.
726 reproducible and suitable for use in scripts or applications.
727
727
728 The only way to trigger plain mode is by setting either the
728 The only way to trigger plain mode is by setting either the
729 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
729 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
730
730
731 The return value can either be
731 The return value can either be
732 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
732 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
733 - True otherwise
733 - True otherwise
734 '''
734 '''
735 if ('HGPLAIN' not in encoding.environ and
735 if ('HGPLAIN' not in encoding.environ and
736 'HGPLAINEXCEPT' not in encoding.environ):
736 'HGPLAINEXCEPT' not in encoding.environ):
737 return False
737 return False
738 exceptions = encoding.environ.get('HGPLAINEXCEPT',
738 exceptions = encoding.environ.get('HGPLAINEXCEPT',
739 '').strip().split(',')
739 '').strip().split(',')
740 if feature and exceptions:
740 if feature and exceptions:
741 return feature not in exceptions
741 return feature not in exceptions
742 return True
742 return True
743
743
744 def username(self):
744 def username(self):
745 """Return default username to be used in commits.
745 """Return default username to be used in commits.
746
746
747 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
747 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
748 and stop searching if one of these is set.
748 and stop searching if one of these is set.
749 If not found and ui.askusername is True, ask the user, else use
749 If not found and ui.askusername is True, ask the user, else use
750 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
750 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
751 """
751 """
752 user = encoding.environ.get("HGUSER")
752 user = encoding.environ.get("HGUSER")
753 if user is None:
753 if user is None:
754 user = self.config("ui", "username")
754 user = self.config("ui", "username")
755 if user is not None:
755 if user is not None:
756 user = os.path.expandvars(user)
756 user = os.path.expandvars(user)
757 if user is None:
757 if user is None:
758 user = encoding.environ.get("EMAIL")
758 user = encoding.environ.get("EMAIL")
759 if user is None and self.configbool("ui", "askusername"):
759 if user is None and self.configbool("ui", "askusername"):
760 user = self.prompt(_("enter a commit username:"), default=None)
760 user = self.prompt(_("enter a commit username:"), default=None)
761 if user is None and not self.interactive():
761 if user is None and not self.interactive():
762 try:
762 try:
763 user = '%s@%s' % (util.getuser(), socket.getfqdn())
763 user = '%s@%s' % (util.getuser(), socket.getfqdn())
764 self.warn(_("no username found, using '%s' instead\n") % user)
764 self.warn(_("no username found, using '%s' instead\n") % user)
765 except KeyError:
765 except KeyError:
766 pass
766 pass
767 if not user:
767 if not user:
768 raise error.Abort(_('no username supplied'),
768 raise error.Abort(_('no username supplied'),
769 hint=_("use 'hg config --edit' "
769 hint=_("use 'hg config --edit' "
770 'to set your username'))
770 'to set your username'))
771 if "\n" in user:
771 if "\n" in user:
772 raise error.Abort(_("username %s contains a newline\n")
772 raise error.Abort(_("username %s contains a newline\n")
773 % repr(user))
773 % repr(user))
774 return user
774 return user
775
775
776 def shortuser(self, user):
776 def shortuser(self, user):
777 """Return a short representation of a user name or email address."""
777 """Return a short representation of a user name or email address."""
778 if not self.verbose:
778 if not self.verbose:
779 user = util.shortuser(user)
779 user = util.shortuser(user)
780 return user
780 return user
781
781
782 def expandpath(self, loc, default=None):
782 def expandpath(self, loc, default=None):
783 """Return repository location relative to cwd or from [paths]"""
783 """Return repository location relative to cwd or from [paths]"""
784 try:
784 try:
785 p = self.paths.getpath(loc)
785 p = self.paths.getpath(loc)
786 if p:
786 if p:
787 return p.rawloc
787 return p.rawloc
788 except error.RepoError:
788 except error.RepoError:
789 pass
789 pass
790
790
791 if default:
791 if default:
792 try:
792 try:
793 p = self.paths.getpath(default)
793 p = self.paths.getpath(default)
794 if p:
794 if p:
795 return p.rawloc
795 return p.rawloc
796 except error.RepoError:
796 except error.RepoError:
797 pass
797 pass
798
798
799 return loc
799 return loc
800
800
801 @util.propertycache
801 @util.propertycache
802 def paths(self):
802 def paths(self):
803 return paths(self)
803 return paths(self)
804
804
805 def pushbuffer(self, error=False, subproc=False, labeled=False):
805 def pushbuffer(self, error=False, subproc=False, labeled=False):
806 """install a buffer to capture standard output of the ui object
806 """install a buffer to capture standard output of the ui object
807
807
808 If error is True, the error output will be captured too.
808 If error is True, the error output will be captured too.
809
809
810 If subproc is True, output from subprocesses (typically hooks) will be
810 If subproc is True, output from subprocesses (typically hooks) will be
811 captured too.
811 captured too.
812
812
813 If labeled is True, any labels associated with buffered
813 If labeled is True, any labels associated with buffered
814 output will be handled. By default, this has no effect
814 output will be handled. By default, this has no effect
815 on the output returned, but extensions and GUI tools may
815 on the output returned, but extensions and GUI tools may
816 handle this argument and returned styled output. If output
816 handle this argument and returned styled output. If output
817 is being buffered so it can be captured and parsed or
817 is being buffered so it can be captured and parsed or
818 processed, labeled should not be set to True.
818 processed, labeled should not be set to True.
819 """
819 """
820 self._buffers.append([])
820 self._buffers.append([])
821 self._bufferstates.append((error, subproc, labeled))
821 self._bufferstates.append((error, subproc, labeled))
822 self._bufferapplylabels = labeled
822 self._bufferapplylabels = labeled
823
823
824 def popbuffer(self):
824 def popbuffer(self):
825 '''pop the last buffer and return the buffered output'''
825 '''pop the last buffer and return the buffered output'''
826 self._bufferstates.pop()
826 self._bufferstates.pop()
827 if self._bufferstates:
827 if self._bufferstates:
828 self._bufferapplylabels = self._bufferstates[-1][2]
828 self._bufferapplylabels = self._bufferstates[-1][2]
829 else:
829 else:
830 self._bufferapplylabels = None
830 self._bufferapplylabels = None
831
831
832 return "".join(self._buffers.pop())
832 return "".join(self._buffers.pop())
833
833
834 def write(self, *args, **opts):
834 def write(self, *args, **opts):
835 '''write args to output
835 '''write args to output
836
836
837 By default, this method simply writes to the buffer or stdout.
837 By default, this method simply writes to the buffer or stdout.
838 Color mode can be set on the UI class to have the output decorated
838 Color mode can be set on the UI class to have the output decorated
839 with color modifier before being written to stdout.
839 with color modifier before being written to stdout.
840
840
841 The color used is controlled by an optional keyword argument, "label".
841 The color used is controlled by an optional keyword argument, "label".
842 This should be a string containing label names separated by space.
842 This should be a string containing label names separated by space.
843 Label names take the form of "topic.type". For example, ui.debug()
843 Label names take the form of "topic.type". For example, ui.debug()
844 issues a label of "ui.debug".
844 issues a label of "ui.debug".
845
845
846 When labeling output for a specific command, a label of
846 When labeling output for a specific command, a label of
847 "cmdname.type" is recommended. For example, status issues
847 "cmdname.type" is recommended. For example, status issues
848 a label of "status.modified" for modified files.
848 a label of "status.modified" for modified files.
849 '''
849 '''
850 if self._buffers and not opts.get('prompt', False):
850 if self._buffers and not opts.get('prompt', False):
851 if self._bufferapplylabels:
851 if self._bufferapplylabels:
852 label = opts.get('label', '')
852 label = opts.get('label', '')
853 self._buffers[-1].extend(self.label(a, label) for a in args)
853 self._buffers[-1].extend(self.label(a, label) for a in args)
854 else:
854 else:
855 self._buffers[-1].extend(args)
855 self._buffers[-1].extend(args)
856 elif self._colormode == 'win32':
856 elif self._colormode == 'win32':
857 # windows color printing is its own can of crab, defer to
857 # windows color printing is its own can of crab, defer to
858 # the color module and that is it.
858 # the color module and that is it.
859 color.win32print(self, self._write, *args, **opts)
859 color.win32print(self, self._write, *args, **opts)
860 else:
860 else:
861 msgs = args
861 msgs = args
862 if self._colormode is not None:
862 if self._colormode is not None:
863 label = opts.get('label', '')
863 label = opts.get('label', '')
864 msgs = [self.label(a, label) for a in args]
864 msgs = [self.label(a, label) for a in args]
865 self._write(*msgs, **opts)
865 self._write(*msgs, **opts)
866
866
867 def _write(self, *msgs, **opts):
867 def _write(self, *msgs, **opts):
868 self._progclear()
868 self._progclear()
869 # opencode timeblockedsection because this is a critical path
869 # opencode timeblockedsection because this is a critical path
870 starttime = util.timer()
870 starttime = util.timer()
871 try:
871 try:
872 for a in msgs:
872 for a in msgs:
873 self.fout.write(a)
873 self.fout.write(a)
874 except IOError as err:
874 except IOError as err:
875 raise error.StdioError(err)
875 raise error.StdioError(err)
876 finally:
876 finally:
877 self._blockedtimes['stdio_blocked'] += \
877 self._blockedtimes['stdio_blocked'] += \
878 (util.timer() - starttime) * 1000
878 (util.timer() - starttime) * 1000
879
879
880 def write_err(self, *args, **opts):
880 def write_err(self, *args, **opts):
881 self._progclear()
881 self._progclear()
882 if self._bufferstates and self._bufferstates[-1][0]:
882 if self._bufferstates and self._bufferstates[-1][0]:
883 self.write(*args, **opts)
883 self.write(*args, **opts)
884 elif self._colormode == 'win32':
884 elif self._colormode == 'win32':
885 # windows color printing is its own can of crab, defer to
885 # windows color printing is its own can of crab, defer to
886 # the color module and that is it.
886 # the color module and that is it.
887 color.win32print(self, self._write_err, *args, **opts)
887 color.win32print(self, self._write_err, *args, **opts)
888 else:
888 else:
889 msgs = args
889 msgs = args
890 if self._colormode is not None:
890 if self._colormode is not None:
891 label = opts.get('label', '')
891 label = opts.get('label', '')
892 msgs = [self.label(a, label) for a in args]
892 msgs = [self.label(a, label) for a in args]
893 self._write_err(*msgs, **opts)
893 self._write_err(*msgs, **opts)
894
894
895 def _write_err(self, *msgs, **opts):
895 def _write_err(self, *msgs, **opts):
896 try:
896 try:
897 with self.timeblockedsection('stdio'):
897 with self.timeblockedsection('stdio'):
898 if not getattr(self.fout, 'closed', False):
898 if not getattr(self.fout, 'closed', False):
899 self.fout.flush()
899 self.fout.flush()
900 for a in msgs:
900 for a in msgs:
901 self.ferr.write(a)
901 self.ferr.write(a)
902 # stderr may be buffered under win32 when redirected to files,
902 # stderr may be buffered under win32 when redirected to files,
903 # including stdout.
903 # including stdout.
904 if not getattr(self.ferr, 'closed', False):
904 if not getattr(self.ferr, 'closed', False):
905 self.ferr.flush()
905 self.ferr.flush()
906 except IOError as inst:
906 except IOError as inst:
907 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
907 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
908 raise error.StdioError(inst)
908 raise error.StdioError(inst)
909
909
910 def flush(self):
910 def flush(self):
911 # opencode timeblockedsection because this is a critical path
911 # opencode timeblockedsection because this is a critical path
912 starttime = util.timer()
912 starttime = util.timer()
913 try:
913 try:
914 try:
914 try:
915 self.fout.flush()
915 self.fout.flush()
916 except IOError as err:
916 except IOError as err:
917 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
917 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
918 raise error.StdioError(err)
918 raise error.StdioError(err)
919 finally:
919 finally:
920 try:
920 try:
921 self.ferr.flush()
921 self.ferr.flush()
922 except IOError as err:
922 except IOError as err:
923 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
923 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
924 raise error.StdioError(err)
924 raise error.StdioError(err)
925 finally:
925 finally:
926 self._blockedtimes['stdio_blocked'] += \
926 self._blockedtimes['stdio_blocked'] += \
927 (util.timer() - starttime) * 1000
927 (util.timer() - starttime) * 1000
928
928
929 def _isatty(self, fh):
929 def _isatty(self, fh):
930 if self.configbool('ui', 'nontty'):
930 if self.configbool('ui', 'nontty'):
931 return False
931 return False
932 return util.isatty(fh)
932 return util.isatty(fh)
933
933
934 def disablepager(self):
934 def disablepager(self):
935 self._disablepager = True
935 self._disablepager = True
936
936
937 def pager(self, command):
937 def pager(self, command):
938 """Start a pager for subsequent command output.
938 """Start a pager for subsequent command output.
939
939
940 Commands which produce a long stream of output should call
940 Commands which produce a long stream of output should call
941 this function to activate the user's preferred pagination
941 this function to activate the user's preferred pagination
942 mechanism (which may be no pager). Calling this function
942 mechanism (which may be no pager). Calling this function
943 precludes any future use of interactive functionality, such as
943 precludes any future use of interactive functionality, such as
944 prompting the user or activating curses.
944 prompting the user or activating curses.
945
945
946 Args:
946 Args:
947 command: The full, non-aliased name of the command. That is, "log"
947 command: The full, non-aliased name of the command. That is, "log"
948 not "history, "summary" not "summ", etc.
948 not "history, "summary" not "summ", etc.
949 """
949 """
950 if (self._disablepager
950 if (self._disablepager
951 or self.pageractive):
951 or self.pageractive):
952 # how pager should do is already determined
952 # how pager should do is already determined
953 return
953 return
954
954
955 if not command.startswith('internal-always-') and (
955 if not command.startswith('internal-always-') and (
956 # explicit --pager=on (= 'internal-always-' prefix) should
956 # explicit --pager=on (= 'internal-always-' prefix) should
957 # take precedence over disabling factors below
957 # take precedence over disabling factors below
958 command in self.configlist('pager', 'ignore')
958 command in self.configlist('pager', 'ignore')
959 or not self.configbool('ui', 'paginate')
959 or not self.configbool('ui', 'paginate')
960 or not self.configbool('pager', 'attend-' + command, True)
960 or not self.configbool('pager', 'attend-' + command, True)
961 # TODO: if we want to allow HGPLAINEXCEPT=pager,
961 # TODO: if we want to allow HGPLAINEXCEPT=pager,
962 # formatted() will need some adjustment.
962 # formatted() will need some adjustment.
963 or not self.formatted()
963 or not self.formatted()
964 or self.plain()
964 or self.plain()
965 # TODO: expose debugger-enabled on the UI object
965 # TODO: expose debugger-enabled on the UI object
966 or '--debugger' in pycompat.sysargv):
966 or '--debugger' in pycompat.sysargv):
967 # We only want to paginate if the ui appears to be
967 # We only want to paginate if the ui appears to be
968 # interactive, the user didn't say HGPLAIN or
968 # interactive, the user didn't say HGPLAIN or
969 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
969 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
970 return
970 return
971
971
972 pagercmd = self.config('pager', 'pager', rcutil.fallbackpager)
972 pagercmd = self.config('pager', 'pager', rcutil.fallbackpager)
973 if not pagercmd:
973 if not pagercmd:
974 return
974 return
975
975
976 pagerenv = {}
976 pagerenv = {}
977 for name, value in rcutil.defaultpagerenv().items():
977 for name, value in rcutil.defaultpagerenv().items():
978 if name not in encoding.environ:
978 if name not in encoding.environ:
979 pagerenv[name] = value
979 pagerenv[name] = value
980
980
981 self.debug('starting pager for command %r\n' % command)
981 self.debug('starting pager for command %r\n' % command)
982 self.flush()
982 self.flush()
983
983
984 wasformatted = self.formatted()
984 wasformatted = self.formatted()
985 if util.safehasattr(signal, "SIGPIPE"):
985 if util.safehasattr(signal, "SIGPIPE"):
986 signal.signal(signal.SIGPIPE, _catchterm)
986 signal.signal(signal.SIGPIPE, _catchterm)
987 if self._runpager(pagercmd, pagerenv):
987 if self._runpager(pagercmd, pagerenv):
988 self.pageractive = True
988 self.pageractive = True
989 # Preserve the formatted-ness of the UI. This is important
989 # Preserve the formatted-ness of the UI. This is important
990 # because we mess with stdout, which might confuse
990 # because we mess with stdout, which might confuse
991 # auto-detection of things being formatted.
991 # auto-detection of things being formatted.
992 self.setconfig('ui', 'formatted', wasformatted, 'pager')
992 self.setconfig('ui', 'formatted', wasformatted, 'pager')
993 self.setconfig('ui', 'interactive', False, 'pager')
993 self.setconfig('ui', 'interactive', False, 'pager')
994
994
995 # If pagermode differs from color.mode, reconfigure color now that
995 # If pagermode differs from color.mode, reconfigure color now that
996 # pageractive is set.
996 # pageractive is set.
997 cm = self._colormode
997 cm = self._colormode
998 if cm != self.config('color', 'pagermode', cm):
998 if cm != self.config('color', 'pagermode', cm):
999 color.setup(self)
999 color.setup(self)
1000 else:
1000 else:
1001 # If the pager can't be spawned in dispatch when --pager=on is
1001 # If the pager can't be spawned in dispatch when --pager=on is
1002 # given, don't try again when the command runs, to avoid a duplicate
1002 # given, don't try again when the command runs, to avoid a duplicate
1003 # warning about a missing pager command.
1003 # warning about a missing pager command.
1004 self.disablepager()
1004 self.disablepager()
1005
1005
1006 def _runpager(self, command, env=None):
1006 def _runpager(self, command, env=None):
1007 """Actually start the pager and set up file descriptors.
1007 """Actually start the pager and set up file descriptors.
1008
1008
1009 This is separate in part so that extensions (like chg) can
1009 This is separate in part so that extensions (like chg) can
1010 override how a pager is invoked.
1010 override how a pager is invoked.
1011 """
1011 """
1012 if command == 'cat':
1012 if command == 'cat':
1013 # Save ourselves some work.
1013 # Save ourselves some work.
1014 return False
1014 return False
1015 # If the command doesn't contain any of these characters, we
1015 # If the command doesn't contain any of these characters, we
1016 # assume it's a binary and exec it directly. This means for
1016 # assume it's a binary and exec it directly. This means for
1017 # simple pager command configurations, we can degrade
1017 # simple pager command configurations, we can degrade
1018 # gracefully and tell the user about their broken pager.
1018 # gracefully and tell the user about their broken pager.
1019 shell = any(c in command for c in "|&;<>()$`\\\"' \t\n*?[#~=%")
1019 shell = any(c in command for c in "|&;<>()$`\\\"' \t\n*?[#~=%")
1020
1020
1021 if pycompat.osname == 'nt' and not shell:
1021 if pycompat.osname == 'nt' and not shell:
1022 # Window's built-in `more` cannot be invoked with shell=False, but
1022 # Window's built-in `more` cannot be invoked with shell=False, but
1023 # its `more.com` can. Hide this implementation detail from the
1023 # its `more.com` can. Hide this implementation detail from the
1024 # user so we can also get sane bad PAGER behavior. MSYS has
1024 # user so we can also get sane bad PAGER behavior. MSYS has
1025 # `more.exe`, so do a cmd.exe style resolution of the executable to
1025 # `more.exe`, so do a cmd.exe style resolution of the executable to
1026 # determine which one to use.
1026 # determine which one to use.
1027 fullcmd = util.findexe(command)
1027 fullcmd = util.findexe(command)
1028 if not fullcmd:
1028 if not fullcmd:
1029 self.warn(_("missing pager command '%s', skipping pager\n")
1029 self.warn(_("missing pager command '%s', skipping pager\n")
1030 % command)
1030 % command)
1031 return False
1031 return False
1032
1032
1033 command = fullcmd
1033 command = fullcmd
1034
1034
1035 try:
1035 try:
1036 pager = subprocess.Popen(
1036 pager = subprocess.Popen(
1037 command, shell=shell, bufsize=-1,
1037 command, shell=shell, bufsize=-1,
1038 close_fds=util.closefds, stdin=subprocess.PIPE,
1038 close_fds=util.closefds, stdin=subprocess.PIPE,
1039 stdout=util.stdout, stderr=util.stderr,
1039 stdout=util.stdout, stderr=util.stderr,
1040 env=util.shellenviron(env))
1040 env=util.shellenviron(env))
1041 except OSError as e:
1041 except OSError as e:
1042 if e.errno == errno.ENOENT and not shell:
1042 if e.errno == errno.ENOENT and not shell:
1043 self.warn(_("missing pager command '%s', skipping pager\n")
1043 self.warn(_("missing pager command '%s', skipping pager\n")
1044 % command)
1044 % command)
1045 return False
1045 return False
1046 raise
1046 raise
1047
1047
1048 # back up original file descriptors
1048 # back up original file descriptors
1049 stdoutfd = os.dup(util.stdout.fileno())
1049 stdoutfd = os.dup(util.stdout.fileno())
1050 stderrfd = os.dup(util.stderr.fileno())
1050 stderrfd = os.dup(util.stderr.fileno())
1051
1051
1052 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
1052 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
1053 if self._isatty(util.stderr):
1053 if self._isatty(util.stderr):
1054 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
1054 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
1055
1055
1056 @self.atexit
1056 @self.atexit
1057 def killpager():
1057 def killpager():
1058 if util.safehasattr(signal, "SIGINT"):
1058 if util.safehasattr(signal, "SIGINT"):
1059 signal.signal(signal.SIGINT, signal.SIG_IGN)
1059 signal.signal(signal.SIGINT, signal.SIG_IGN)
1060 # restore original fds, closing pager.stdin copies in the process
1060 # restore original fds, closing pager.stdin copies in the process
1061 os.dup2(stdoutfd, util.stdout.fileno())
1061 os.dup2(stdoutfd, util.stdout.fileno())
1062 os.dup2(stderrfd, util.stderr.fileno())
1062 os.dup2(stderrfd, util.stderr.fileno())
1063 pager.stdin.close()
1063 pager.stdin.close()
1064 pager.wait()
1064 pager.wait()
1065
1065
1066 return True
1066 return True
1067
1067
1068 def atexit(self, func, *args, **kwargs):
1068 def atexit(self, func, *args, **kwargs):
1069 '''register a function to run after dispatching a request
1069 '''register a function to run after dispatching a request
1070
1070
1071 Handlers do not stay registered across request boundaries.'''
1071 Handlers do not stay registered across request boundaries.'''
1072 self._exithandlers.append((func, args, kwargs))
1072 self._exithandlers.append((func, args, kwargs))
1073 return func
1073 return func
1074
1074
1075 def interface(self, feature):
1075 def interface(self, feature):
1076 """what interface to use for interactive console features?
1076 """what interface to use for interactive console features?
1077
1077
1078 The interface is controlled by the value of `ui.interface` but also by
1078 The interface is controlled by the value of `ui.interface` but also by
1079 the value of feature-specific configuration. For example:
1079 the value of feature-specific configuration. For example:
1080
1080
1081 ui.interface.histedit = text
1081 ui.interface.histedit = text
1082 ui.interface.chunkselector = curses
1082 ui.interface.chunkselector = curses
1083
1083
1084 Here the features are "histedit" and "chunkselector".
1084 Here the features are "histedit" and "chunkselector".
1085
1085
1086 The configuration above means that the default interfaces for commands
1086 The configuration above means that the default interfaces for commands
1087 is curses, the interface for histedit is text and the interface for
1087 is curses, the interface for histedit is text and the interface for
1088 selecting chunk is crecord (the best curses interface available).
1088 selecting chunk is crecord (the best curses interface available).
1089
1089
1090 Consider the following example:
1090 Consider the following example:
1091 ui.interface = curses
1091 ui.interface = curses
1092 ui.interface.histedit = text
1092 ui.interface.histedit = text
1093
1093
1094 Then histedit will use the text interface and chunkselector will use
1094 Then histedit will use the text interface and chunkselector will use
1095 the default curses interface (crecord at the moment).
1095 the default curses interface (crecord at the moment).
1096 """
1096 """
1097 alldefaults = frozenset(["text", "curses"])
1097 alldefaults = frozenset(["text", "curses"])
1098
1098
1099 featureinterfaces = {
1099 featureinterfaces = {
1100 "chunkselector": [
1100 "chunkselector": [
1101 "text",
1101 "text",
1102 "curses",
1102 "curses",
1103 ]
1103 ]
1104 }
1104 }
1105
1105
1106 # Feature-specific interface
1106 # Feature-specific interface
1107 if feature not in featureinterfaces.keys():
1107 if feature not in featureinterfaces.keys():
1108 # Programming error, not user error
1108 # Programming error, not user error
1109 raise ValueError("Unknown feature requested %s" % feature)
1109 raise ValueError("Unknown feature requested %s" % feature)
1110
1110
1111 availableinterfaces = frozenset(featureinterfaces[feature])
1111 availableinterfaces = frozenset(featureinterfaces[feature])
1112 if alldefaults > availableinterfaces:
1112 if alldefaults > availableinterfaces:
1113 # Programming error, not user error. We need a use case to
1113 # Programming error, not user error. We need a use case to
1114 # define the right thing to do here.
1114 # define the right thing to do here.
1115 raise ValueError(
1115 raise ValueError(
1116 "Feature %s does not handle all default interfaces" %
1116 "Feature %s does not handle all default interfaces" %
1117 feature)
1117 feature)
1118
1118
1119 if self.plain():
1119 if self.plain():
1120 return "text"
1120 return "text"
1121
1121
1122 # Default interface for all the features
1122 # Default interface for all the features
1123 defaultinterface = "text"
1123 defaultinterface = "text"
1124 i = self.config("ui", "interface")
1124 i = self.config("ui", "interface")
1125 if i in alldefaults:
1125 if i in alldefaults:
1126 defaultinterface = i
1126 defaultinterface = i
1127
1127
1128 choseninterface = defaultinterface
1128 choseninterface = defaultinterface
1129 f = self.config("ui", "interface.%s" % feature, None)
1129 f = self.config("ui", "interface.%s" % feature, None)
1130 if f in availableinterfaces:
1130 if f in availableinterfaces:
1131 choseninterface = f
1131 choseninterface = f
1132
1132
1133 if i is not None and defaultinterface != i:
1133 if i is not None and defaultinterface != i:
1134 if f is not None:
1134 if f is not None:
1135 self.warn(_("invalid value for ui.interface: %s\n") %
1135 self.warn(_("invalid value for ui.interface: %s\n") %
1136 (i,))
1136 (i,))
1137 else:
1137 else:
1138 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
1138 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
1139 (i, choseninterface))
1139 (i, choseninterface))
1140 if f is not None and choseninterface != f:
1140 if f is not None and choseninterface != f:
1141 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
1141 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
1142 (feature, f, choseninterface))
1142 (feature, f, choseninterface))
1143
1143
1144 return choseninterface
1144 return choseninterface
1145
1145
1146 def interactive(self):
1146 def interactive(self):
1147 '''is interactive input allowed?
1147 '''is interactive input allowed?
1148
1148
1149 An interactive session is a session where input can be reasonably read
1149 An interactive session is a session where input can be reasonably read
1150 from `sys.stdin'. If this function returns false, any attempt to read
1150 from `sys.stdin'. If this function returns false, any attempt to read
1151 from stdin should fail with an error, unless a sensible default has been
1151 from stdin should fail with an error, unless a sensible default has been
1152 specified.
1152 specified.
1153
1153
1154 Interactiveness is triggered by the value of the `ui.interactive'
1154 Interactiveness is triggered by the value of the `ui.interactive'
1155 configuration variable or - if it is unset - when `sys.stdin' points
1155 configuration variable or - if it is unset - when `sys.stdin' points
1156 to a terminal device.
1156 to a terminal device.
1157
1157
1158 This function refers to input only; for output, see `ui.formatted()'.
1158 This function refers to input only; for output, see `ui.formatted()'.
1159 '''
1159 '''
1160 i = self.configbool("ui", "interactive")
1160 i = self.configbool("ui", "interactive")
1161 if i is None:
1161 if i is None:
1162 # some environments replace stdin without implementing isatty
1162 # some environments replace stdin without implementing isatty
1163 # usually those are non-interactive
1163 # usually those are non-interactive
1164 return self._isatty(self.fin)
1164 return self._isatty(self.fin)
1165
1165
1166 return i
1166 return i
1167
1167
1168 def termwidth(self):
1168 def termwidth(self):
1169 '''how wide is the terminal in columns?
1169 '''how wide is the terminal in columns?
1170 '''
1170 '''
1171 if 'COLUMNS' in encoding.environ:
1171 if 'COLUMNS' in encoding.environ:
1172 try:
1172 try:
1173 return int(encoding.environ['COLUMNS'])
1173 return int(encoding.environ['COLUMNS'])
1174 except ValueError:
1174 except ValueError:
1175 pass
1175 pass
1176 return scmutil.termsize(self)[0]
1176 return scmutil.termsize(self)[0]
1177
1177
1178 def formatted(self):
1178 def formatted(self):
1179 '''should formatted output be used?
1179 '''should formatted output be used?
1180
1180
1181 It is often desirable to format the output to suite the output medium.
1181 It is often desirable to format the output to suite the output medium.
1182 Examples of this are truncating long lines or colorizing messages.
1182 Examples of this are truncating long lines or colorizing messages.
1183 However, this is not often not desirable when piping output into other
1183 However, this is not often not desirable when piping output into other
1184 utilities, e.g. `grep'.
1184 utilities, e.g. `grep'.
1185
1185
1186 Formatted output is triggered by the value of the `ui.formatted'
1186 Formatted output is triggered by the value of the `ui.formatted'
1187 configuration variable or - if it is unset - when `sys.stdout' points
1187 configuration variable or - if it is unset - when `sys.stdout' points
1188 to a terminal device. Please note that `ui.formatted' should be
1188 to a terminal device. Please note that `ui.formatted' should be
1189 considered an implementation detail; it is not intended for use outside
1189 considered an implementation detail; it is not intended for use outside
1190 Mercurial or its extensions.
1190 Mercurial or its extensions.
1191
1191
1192 This function refers to output only; for input, see `ui.interactive()'.
1192 This function refers to output only; for input, see `ui.interactive()'.
1193 This function always returns false when in plain mode, see `ui.plain()'.
1193 This function always returns false when in plain mode, see `ui.plain()'.
1194 '''
1194 '''
1195 if self.plain():
1195 if self.plain():
1196 return False
1196 return False
1197
1197
1198 i = self.configbool("ui", "formatted")
1198 i = self.configbool("ui", "formatted")
1199 if i is None:
1199 if i is None:
1200 # some environments replace stdout without implementing isatty
1200 # some environments replace stdout without implementing isatty
1201 # usually those are non-interactive
1201 # usually those are non-interactive
1202 return self._isatty(self.fout)
1202 return self._isatty(self.fout)
1203
1203
1204 return i
1204 return i
1205
1205
1206 def _readline(self, prompt=''):
1206 def _readline(self, prompt=''):
1207 if self._isatty(self.fin):
1207 if self._isatty(self.fin):
1208 try:
1208 try:
1209 # magically add command line editing support, where
1209 # magically add command line editing support, where
1210 # available
1210 # available
1211 import readline
1211 import readline
1212 # force demandimport to really load the module
1212 # force demandimport to really load the module
1213 readline.read_history_file
1213 readline.read_history_file
1214 # windows sometimes raises something other than ImportError
1214 # windows sometimes raises something other than ImportError
1215 except Exception:
1215 except Exception:
1216 pass
1216 pass
1217
1217
1218 # call write() so output goes through subclassed implementation
1218 # call write() so output goes through subclassed implementation
1219 # e.g. color extension on Windows
1219 # e.g. color extension on Windows
1220 self.write(prompt, prompt=True)
1220 self.write(prompt, prompt=True)
1221 self.flush()
1221 self.flush()
1222
1222
1223 # instead of trying to emulate raw_input, swap (self.fin,
1223 # instead of trying to emulate raw_input, swap (self.fin,
1224 # self.fout) with (sys.stdin, sys.stdout)
1224 # self.fout) with (sys.stdin, sys.stdout)
1225 oldin = sys.stdin
1225 oldin = sys.stdin
1226 oldout = sys.stdout
1226 oldout = sys.stdout
1227 sys.stdin = self.fin
1227 sys.stdin = self.fin
1228 sys.stdout = self.fout
1228 sys.stdout = self.fout
1229 # prompt ' ' must exist; otherwise readline may delete entire line
1229 # prompt ' ' must exist; otherwise readline may delete entire line
1230 # - http://bugs.python.org/issue12833
1230 # - http://bugs.python.org/issue12833
1231 with self.timeblockedsection('stdio'):
1231 with self.timeblockedsection('stdio'):
1232 line = raw_input(' ')
1232 line = raw_input(' ')
1233 sys.stdin = oldin
1233 sys.stdin = oldin
1234 sys.stdout = oldout
1234 sys.stdout = oldout
1235
1235
1236 # When stdin is in binary mode on Windows, it can cause
1236 # When stdin is in binary mode on Windows, it can cause
1237 # raw_input() to emit an extra trailing carriage return
1237 # raw_input() to emit an extra trailing carriage return
1238 if pycompat.oslinesep == '\r\n' and line and line[-1] == '\r':
1238 if pycompat.oslinesep == '\r\n' and line and line[-1] == '\r':
1239 line = line[:-1]
1239 line = line[:-1]
1240 return line
1240 return line
1241
1241
1242 def prompt(self, msg, default="y"):
1242 def prompt(self, msg, default="y"):
1243 """Prompt user with msg, read response.
1243 """Prompt user with msg, read response.
1244 If ui is not interactive, the default is returned.
1244 If ui is not interactive, the default is returned.
1245 """
1245 """
1246 if not self.interactive():
1246 if not self.interactive():
1247 self.write(msg, ' ', default or '', "\n")
1247 self.write(msg, ' ', default or '', "\n")
1248 return default
1248 return default
1249 try:
1249 try:
1250 r = self._readline(self.label(msg, 'ui.prompt'))
1250 r = self._readline(self.label(msg, 'ui.prompt'))
1251 if not r:
1251 if not r:
1252 r = default
1252 r = default
1253 if self.configbool('ui', 'promptecho'):
1253 if self.configbool('ui', 'promptecho'):
1254 self.write(r, "\n")
1254 self.write(r, "\n")
1255 return r
1255 return r
1256 except EOFError:
1256 except EOFError:
1257 raise error.ResponseExpected()
1257 raise error.ResponseExpected()
1258
1258
1259 @staticmethod
1259 @staticmethod
1260 def extractchoices(prompt):
1260 def extractchoices(prompt):
1261 """Extract prompt message and list of choices from specified prompt.
1261 """Extract prompt message and list of choices from specified prompt.
1262
1262
1263 This returns tuple "(message, choices)", and "choices" is the
1263 This returns tuple "(message, choices)", and "choices" is the
1264 list of tuple "(response character, text without &)".
1264 list of tuple "(response character, text without &)".
1265
1265
1266 >>> ui.extractchoices("awake? $$ &Yes $$ &No")
1266 >>> ui.extractchoices("awake? $$ &Yes $$ &No")
1267 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1267 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1268 >>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
1268 >>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
1269 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1269 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1270 >>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
1270 >>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
1271 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1271 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1272 """
1272 """
1273
1273
1274 # Sadly, the prompt string may have been built with a filename
1274 # Sadly, the prompt string may have been built with a filename
1275 # containing "$$" so let's try to find the first valid-looking
1275 # containing "$$" so let's try to find the first valid-looking
1276 # prompt to start parsing. Sadly, we also can't rely on
1276 # prompt to start parsing. Sadly, we also can't rely on
1277 # choices containing spaces, ASCII, or basically anything
1277 # choices containing spaces, ASCII, or basically anything
1278 # except an ampersand followed by a character.
1278 # except an ampersand followed by a character.
1279 m = re.match(br'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
1279 m = re.match(br'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
1280 msg = m.group(1)
1280 msg = m.group(1)
1281 choices = [p.strip(' ') for p in m.group(2).split('$$')]
1281 choices = [p.strip(' ') for p in m.group(2).split('$$')]
1282 return (msg,
1282 return (msg,
1283 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
1283 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
1284 for s in choices])
1284 for s in choices])
1285
1285
1286 def promptchoice(self, prompt, default=0):
1286 def promptchoice(self, prompt, default=0):
1287 """Prompt user with a message, read response, and ensure it matches
1287 """Prompt user with a message, read response, and ensure it matches
1288 one of the provided choices. The prompt is formatted as follows:
1288 one of the provided choices. The prompt is formatted as follows:
1289
1289
1290 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1290 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1291
1291
1292 The index of the choice is returned. Responses are case
1292 The index of the choice is returned. Responses are case
1293 insensitive. If ui is not interactive, the default is
1293 insensitive. If ui is not interactive, the default is
1294 returned.
1294 returned.
1295 """
1295 """
1296
1296
1297 msg, choices = self.extractchoices(prompt)
1297 msg, choices = self.extractchoices(prompt)
1298 resps = [r for r, t in choices]
1298 resps = [r for r, t in choices]
1299 while True:
1299 while True:
1300 r = self.prompt(msg, resps[default])
1300 r = self.prompt(msg, resps[default])
1301 if r.lower() in resps:
1301 if r.lower() in resps:
1302 return resps.index(r.lower())
1302 return resps.index(r.lower())
1303 self.write(_("unrecognized response\n"))
1303 self.write(_("unrecognized response\n"))
1304
1304
1305 def getpass(self, prompt=None, default=None):
1305 def getpass(self, prompt=None, default=None):
1306 if not self.interactive():
1306 if not self.interactive():
1307 return default
1307 return default
1308 try:
1308 try:
1309 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1309 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1310 # disable getpass() only if explicitly specified. it's still valid
1310 # disable getpass() only if explicitly specified. it's still valid
1311 # to interact with tty even if fin is not a tty.
1311 # to interact with tty even if fin is not a tty.
1312 with self.timeblockedsection('stdio'):
1312 with self.timeblockedsection('stdio'):
1313 if self.configbool('ui', 'nontty'):
1313 if self.configbool('ui', 'nontty'):
1314 l = self.fin.readline()
1314 l = self.fin.readline()
1315 if not l:
1315 if not l:
1316 raise EOFError
1316 raise EOFError
1317 return l.rstrip('\n')
1317 return l.rstrip('\n')
1318 else:
1318 else:
1319 return getpass.getpass('')
1319 return getpass.getpass('')
1320 except EOFError:
1320 except EOFError:
1321 raise error.ResponseExpected()
1321 raise error.ResponseExpected()
1322 def status(self, *msg, **opts):
1322 def status(self, *msg, **opts):
1323 '''write status message to output (if ui.quiet is False)
1323 '''write status message to output (if ui.quiet is False)
1324
1324
1325 This adds an output label of "ui.status".
1325 This adds an output label of "ui.status".
1326 '''
1326 '''
1327 if not self.quiet:
1327 if not self.quiet:
1328 opts[r'label'] = opts.get(r'label', '') + ' ui.status'
1328 opts[r'label'] = opts.get(r'label', '') + ' ui.status'
1329 self.write(*msg, **opts)
1329 self.write(*msg, **opts)
1330 def warn(self, *msg, **opts):
1330 def warn(self, *msg, **opts):
1331 '''write warning message to output (stderr)
1331 '''write warning message to output (stderr)
1332
1332
1333 This adds an output label of "ui.warning".
1333 This adds an output label of "ui.warning".
1334 '''
1334 '''
1335 opts[r'label'] = opts.get(r'label', '') + ' ui.warning'
1335 opts[r'label'] = opts.get(r'label', '') + ' ui.warning'
1336 self.write_err(*msg, **opts)
1336 self.write_err(*msg, **opts)
1337 def note(self, *msg, **opts):
1337 def note(self, *msg, **opts):
1338 '''write note to output (if ui.verbose is True)
1338 '''write note to output (if ui.verbose is True)
1339
1339
1340 This adds an output label of "ui.note".
1340 This adds an output label of "ui.note".
1341 '''
1341 '''
1342 if self.verbose:
1342 if self.verbose:
1343 opts[r'label'] = opts.get(r'label', '') + ' ui.note'
1343 opts[r'label'] = opts.get(r'label', '') + ' ui.note'
1344 self.write(*msg, **opts)
1344 self.write(*msg, **opts)
1345 def debug(self, *msg, **opts):
1345 def debug(self, *msg, **opts):
1346 '''write debug message to output (if ui.debugflag is True)
1346 '''write debug message to output (if ui.debugflag is True)
1347
1347
1348 This adds an output label of "ui.debug".
1348 This adds an output label of "ui.debug".
1349 '''
1349 '''
1350 if self.debugflag:
1350 if self.debugflag:
1351 opts[r'label'] = opts.get(r'label', '') + ' ui.debug'
1351 opts[r'label'] = opts.get(r'label', '') + ' ui.debug'
1352 self.write(*msg, **opts)
1352 self.write(*msg, **opts)
1353
1353
1354 def edit(self, text, user, extra=None, editform=None, pending=None,
1354 def edit(self, text, user, extra=None, editform=None, pending=None,
1355 repopath=None):
1355 repopath=None):
1356 extra_defaults = {
1356 extra_defaults = {
1357 'prefix': 'editor',
1357 'prefix': 'editor',
1358 'suffix': '.txt',
1358 'suffix': '.txt',
1359 }
1359 }
1360 if extra is not None:
1360 if extra is not None:
1361 extra_defaults.update(extra)
1361 extra_defaults.update(extra)
1362 extra = extra_defaults
1362 extra = extra_defaults
1363
1363
1364 rdir = None
1364 rdir = None
1365 if self.configbool('experimental', 'editortmpinhg'):
1365 if self.configbool('experimental', 'editortmpinhg'):
1366 rdir = repopath
1366 rdir = repopath
1367 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1367 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1368 suffix=extra['suffix'],
1368 suffix=extra['suffix'],
1369 dir=rdir)
1369 dir=rdir)
1370 try:
1370 try:
1371 f = os.fdopen(fd, r'wb')
1371 f = os.fdopen(fd, r'wb')
1372 f.write(util.tonativeeol(text))
1372 f.write(util.tonativeeol(text))
1373 f.close()
1373 f.close()
1374
1374
1375 environ = {'HGUSER': user}
1375 environ = {'HGUSER': user}
1376 if 'transplant_source' in extra:
1376 if 'transplant_source' in extra:
1377 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1377 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1378 for label in ('intermediate-source', 'source', 'rebase_source'):
1378 for label in ('intermediate-source', 'source', 'rebase_source'):
1379 if label in extra:
1379 if label in extra:
1380 environ.update({'HGREVISION': extra[label]})
1380 environ.update({'HGREVISION': extra[label]})
1381 break
1381 break
1382 if editform:
1382 if editform:
1383 environ.update({'HGEDITFORM': editform})
1383 environ.update({'HGEDITFORM': editform})
1384 if pending:
1384 if pending:
1385 environ.update({'HG_PENDING': pending})
1385 environ.update({'HG_PENDING': pending})
1386
1386
1387 editor = self.geteditor()
1387 editor = self.geteditor()
1388
1388
1389 self.system("%s \"%s\"" % (editor, name),
1389 self.system("%s \"%s\"" % (editor, name),
1390 environ=environ,
1390 environ=environ,
1391 onerr=error.Abort, errprefix=_("edit failed"),
1391 onerr=error.Abort, errprefix=_("edit failed"),
1392 blockedtag='editor')
1392 blockedtag='editor')
1393
1393
1394 f = open(name, r'rb')
1394 f = open(name, r'rb')
1395 t = util.fromnativeeol(f.read())
1395 t = util.fromnativeeol(f.read())
1396 f.close()
1396 f.close()
1397 finally:
1397 finally:
1398 os.unlink(name)
1398 os.unlink(name)
1399
1399
1400 return t
1400 return t
1401
1401
1402 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None,
1402 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None,
1403 blockedtag=None):
1403 blockedtag=None):
1404 '''execute shell command with appropriate output stream. command
1404 '''execute shell command with appropriate output stream. command
1405 output will be redirected if fout is not stdout.
1405 output will be redirected if fout is not stdout.
1406
1406
1407 if command fails and onerr is None, return status, else raise onerr
1407 if command fails and onerr is None, return status, else raise onerr
1408 object as exception.
1408 object as exception.
1409 '''
1409 '''
1410 if blockedtag is None:
1410 if blockedtag is None:
1411 # Long cmds tend to be because of an absolute path on cmd. Keep
1411 # Long cmds tend to be because of an absolute path on cmd. Keep
1412 # the tail end instead
1412 # the tail end instead
1413 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1413 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1414 blockedtag = 'unknown_system_' + cmdsuffix
1414 blockedtag = 'unknown_system_' + cmdsuffix
1415 out = self.fout
1415 out = self.fout
1416 if any(s[1] for s in self._bufferstates):
1416 if any(s[1] for s in self._bufferstates):
1417 out = self
1417 out = self
1418 with self.timeblockedsection(blockedtag):
1418 with self.timeblockedsection(blockedtag):
1419 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1419 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1420 if rc and onerr:
1420 if rc and onerr:
1421 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
1421 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
1422 util.explainexit(rc)[0])
1422 util.explainexit(rc)[0])
1423 if errprefix:
1423 if errprefix:
1424 errmsg = '%s: %s' % (errprefix, errmsg)
1424 errmsg = '%s: %s' % (errprefix, errmsg)
1425 raise onerr(errmsg)
1425 raise onerr(errmsg)
1426 return rc
1426 return rc
1427
1427
1428 def _runsystem(self, cmd, environ, cwd, out):
1428 def _runsystem(self, cmd, environ, cwd, out):
1429 """actually execute the given shell command (can be overridden by
1429 """actually execute the given shell command (can be overridden by
1430 extensions like chg)"""
1430 extensions like chg)"""
1431 return util.system(cmd, environ=environ, cwd=cwd, out=out)
1431 return util.system(cmd, environ=environ, cwd=cwd, out=out)
1432
1432
1433 def traceback(self, exc=None, force=False):
1433 def traceback(self, exc=None, force=False):
1434 '''print exception traceback if traceback printing enabled or forced.
1434 '''print exception traceback if traceback printing enabled or forced.
1435 only to call in exception handler. returns true if traceback
1435 only to call in exception handler. returns true if traceback
1436 printed.'''
1436 printed.'''
1437 if self.tracebackflag or force:
1437 if self.tracebackflag or force:
1438 if exc is None:
1438 if exc is None:
1439 exc = sys.exc_info()
1439 exc = sys.exc_info()
1440 cause = getattr(exc[1], 'cause', None)
1440 cause = getattr(exc[1], 'cause', None)
1441
1441
1442 if cause is not None:
1442 if cause is not None:
1443 causetb = traceback.format_tb(cause[2])
1443 causetb = traceback.format_tb(cause[2])
1444 exctb = traceback.format_tb(exc[2])
1444 exctb = traceback.format_tb(exc[2])
1445 exconly = traceback.format_exception_only(cause[0], cause[1])
1445 exconly = traceback.format_exception_only(cause[0], cause[1])
1446
1446
1447 # exclude frame where 'exc' was chained and rethrown from exctb
1447 # exclude frame where 'exc' was chained and rethrown from exctb
1448 self.write_err('Traceback (most recent call last):\n',
1448 self.write_err('Traceback (most recent call last):\n',
1449 ''.join(exctb[:-1]),
1449 ''.join(exctb[:-1]),
1450 ''.join(causetb),
1450 ''.join(causetb),
1451 ''.join(exconly))
1451 ''.join(exconly))
1452 else:
1452 else:
1453 output = traceback.format_exception(exc[0], exc[1], exc[2])
1453 output = traceback.format_exception(exc[0], exc[1], exc[2])
1454 data = r''.join(output)
1454 data = r''.join(output)
1455 if pycompat.ispy3:
1455 if pycompat.ispy3:
1456 enc = pycompat.sysstr(encoding.encoding)
1456 enc = pycompat.sysstr(encoding.encoding)
1457 data = data.encode(enc, errors=r'replace')
1457 data = data.encode(enc, errors=r'replace')
1458 self.write_err(data)
1458 self.write_err(data)
1459 return self.tracebackflag or force
1459 return self.tracebackflag or force
1460
1460
1461 def geteditor(self):
1461 def geteditor(self):
1462 '''return editor to use'''
1462 '''return editor to use'''
1463 if pycompat.sysplatform == 'plan9':
1463 if pycompat.sysplatform == 'plan9':
1464 # vi is the MIPS instruction simulator on Plan 9. We
1464 # vi is the MIPS instruction simulator on Plan 9. We
1465 # instead default to E to plumb commit messages to
1465 # instead default to E to plumb commit messages to
1466 # avoid confusion.
1466 # avoid confusion.
1467 editor = 'E'
1467 editor = 'E'
1468 else:
1468 else:
1469 editor = 'vi'
1469 editor = 'vi'
1470 return (encoding.environ.get("HGEDITOR") or
1470 return (encoding.environ.get("HGEDITOR") or
1471 self.config("ui", "editor", editor))
1471 self.config("ui", "editor", editor))
1472
1472
1473 @util.propertycache
1473 @util.propertycache
1474 def _progbar(self):
1474 def _progbar(self):
1475 """setup the progbar singleton to the ui object"""
1475 """setup the progbar singleton to the ui object"""
1476 if (self.quiet or self.debugflag
1476 if (self.quiet or self.debugflag
1477 or self.configbool('progress', 'disable')
1477 or self.configbool('progress', 'disable')
1478 or not progress.shouldprint(self)):
1478 or not progress.shouldprint(self)):
1479 return None
1479 return None
1480 return getprogbar(self)
1480 return getprogbar(self)
1481
1481
1482 def _progclear(self):
1482 def _progclear(self):
1483 """clear progress bar output if any. use it before any output"""
1483 """clear progress bar output if any. use it before any output"""
1484 if '_progbar' not in vars(self): # nothing loaded yet
1484 if not haveprogbar(): # nothing loaded yet
1485 return
1485 return
1486 if self._progbar is not None and self._progbar.printed:
1486 if self._progbar is not None and self._progbar.printed:
1487 self._progbar.clear()
1487 self._progbar.clear()
1488
1488
1489 def progress(self, topic, pos, item="", unit="", total=None):
1489 def progress(self, topic, pos, item="", unit="", total=None):
1490 '''show a progress message
1490 '''show a progress message
1491
1491
1492 By default a textual progress bar will be displayed if an operation
1492 By default a textual progress bar will be displayed if an operation
1493 takes too long. 'topic' is the current operation, 'item' is a
1493 takes too long. 'topic' is the current operation, 'item' is a
1494 non-numeric marker of the current position (i.e. the currently
1494 non-numeric marker of the current position (i.e. the currently
1495 in-process file), 'pos' is the current numeric position (i.e.
1495 in-process file), 'pos' is the current numeric position (i.e.
1496 revision, bytes, etc.), unit is a corresponding unit label,
1496 revision, bytes, etc.), unit is a corresponding unit label,
1497 and total is the highest expected pos.
1497 and total is the highest expected pos.
1498
1498
1499 Multiple nested topics may be active at a time.
1499 Multiple nested topics may be active at a time.
1500
1500
1501 All topics should be marked closed by setting pos to None at
1501 All topics should be marked closed by setting pos to None at
1502 termination.
1502 termination.
1503 '''
1503 '''
1504 if self._progbar is not None:
1504 if self._progbar is not None:
1505 self._progbar.progress(topic, pos, item=item, unit=unit,
1505 self._progbar.progress(topic, pos, item=item, unit=unit,
1506 total=total)
1506 total=total)
1507 if pos is None or not self.configbool('progress', 'debug'):
1507 if pos is None or not self.configbool('progress', 'debug'):
1508 return
1508 return
1509
1509
1510 if unit:
1510 if unit:
1511 unit = ' ' + unit
1511 unit = ' ' + unit
1512 if item:
1512 if item:
1513 item = ' ' + item
1513 item = ' ' + item
1514
1514
1515 if total:
1515 if total:
1516 pct = 100.0 * pos / total
1516 pct = 100.0 * pos / total
1517 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
1517 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
1518 % (topic, item, pos, total, unit, pct))
1518 % (topic, item, pos, total, unit, pct))
1519 else:
1519 else:
1520 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
1520 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
1521
1521
1522 def log(self, service, *msg, **opts):
1522 def log(self, service, *msg, **opts):
1523 '''hook for logging facility extensions
1523 '''hook for logging facility extensions
1524
1524
1525 service should be a readily-identifiable subsystem, which will
1525 service should be a readily-identifiable subsystem, which will
1526 allow filtering.
1526 allow filtering.
1527
1527
1528 *msg should be a newline-terminated format string to log, and
1528 *msg should be a newline-terminated format string to log, and
1529 then any values to %-format into that format string.
1529 then any values to %-format into that format string.
1530
1530
1531 **opts currently has no defined meanings.
1531 **opts currently has no defined meanings.
1532 '''
1532 '''
1533
1533
1534 def label(self, msg, label):
1534 def label(self, msg, label):
1535 '''style msg based on supplied label
1535 '''style msg based on supplied label
1536
1536
1537 If some color mode is enabled, this will add the necessary control
1537 If some color mode is enabled, this will add the necessary control
1538 characters to apply such color. In addition, 'debug' color mode adds
1538 characters to apply such color. In addition, 'debug' color mode adds
1539 markup showing which label affects a piece of text.
1539 markup showing which label affects a piece of text.
1540
1540
1541 ui.write(s, 'label') is equivalent to
1541 ui.write(s, 'label') is equivalent to
1542 ui.write(ui.label(s, 'label')).
1542 ui.write(ui.label(s, 'label')).
1543 '''
1543 '''
1544 if self._colormode is not None:
1544 if self._colormode is not None:
1545 return color.colorlabel(self, msg, label)
1545 return color.colorlabel(self, msg, label)
1546 return msg
1546 return msg
1547
1547
1548 def develwarn(self, msg, stacklevel=1, config=None):
1548 def develwarn(self, msg, stacklevel=1, config=None):
1549 """issue a developer warning message
1549 """issue a developer warning message
1550
1550
1551 Use 'stacklevel' to report the offender some layers further up in the
1551 Use 'stacklevel' to report the offender some layers further up in the
1552 stack.
1552 stack.
1553 """
1553 """
1554 if not self.configbool('devel', 'all-warnings'):
1554 if not self.configbool('devel', 'all-warnings'):
1555 if config is not None and not self.configbool('devel', config):
1555 if config is not None and not self.configbool('devel', config):
1556 return
1556 return
1557 msg = 'devel-warn: ' + msg
1557 msg = 'devel-warn: ' + msg
1558 stacklevel += 1 # get in develwarn
1558 stacklevel += 1 # get in develwarn
1559 if self.tracebackflag:
1559 if self.tracebackflag:
1560 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1560 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1561 self.log('develwarn', '%s at:\n%s' %
1561 self.log('develwarn', '%s at:\n%s' %
1562 (msg, ''.join(util.getstackframes(stacklevel))))
1562 (msg, ''.join(util.getstackframes(stacklevel))))
1563 else:
1563 else:
1564 curframe = inspect.currentframe()
1564 curframe = inspect.currentframe()
1565 calframe = inspect.getouterframes(curframe, 2)
1565 calframe = inspect.getouterframes(curframe, 2)
1566 self.write_err('%s at: %s:%s (%s)\n'
1566 self.write_err('%s at: %s:%s (%s)\n'
1567 % ((msg,) + calframe[stacklevel][1:4]))
1567 % ((msg,) + calframe[stacklevel][1:4]))
1568 self.log('develwarn', '%s at: %s:%s (%s)\n',
1568 self.log('develwarn', '%s at: %s:%s (%s)\n',
1569 msg, *calframe[stacklevel][1:4])
1569 msg, *calframe[stacklevel][1:4])
1570 curframe = calframe = None # avoid cycles
1570 curframe = calframe = None # avoid cycles
1571
1571
1572 def deprecwarn(self, msg, version):
1572 def deprecwarn(self, msg, version):
1573 """issue a deprecation warning
1573 """issue a deprecation warning
1574
1574
1575 - msg: message explaining what is deprecated and how to upgrade,
1575 - msg: message explaining what is deprecated and how to upgrade,
1576 - version: last version where the API will be supported,
1576 - version: last version where the API will be supported,
1577 """
1577 """
1578 if not (self.configbool('devel', 'all-warnings')
1578 if not (self.configbool('devel', 'all-warnings')
1579 or self.configbool('devel', 'deprec-warn')):
1579 or self.configbool('devel', 'deprec-warn')):
1580 return
1580 return
1581 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1581 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1582 " update your code.)") % version
1582 " update your code.)") % version
1583 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1583 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1584
1584
1585 def exportableenviron(self):
1585 def exportableenviron(self):
1586 """The environment variables that are safe to export, e.g. through
1586 """The environment variables that are safe to export, e.g. through
1587 hgweb.
1587 hgweb.
1588 """
1588 """
1589 return self._exportableenviron
1589 return self._exportableenviron
1590
1590
1591 @contextlib.contextmanager
1591 @contextlib.contextmanager
1592 def configoverride(self, overrides, source=""):
1592 def configoverride(self, overrides, source=""):
1593 """Context manager for temporary config overrides
1593 """Context manager for temporary config overrides
1594 `overrides` must be a dict of the following structure:
1594 `overrides` must be a dict of the following structure:
1595 {(section, name) : value}"""
1595 {(section, name) : value}"""
1596 backups = {}
1596 backups = {}
1597 try:
1597 try:
1598 for (section, name), value in overrides.items():
1598 for (section, name), value in overrides.items():
1599 backups[(section, name)] = self.backupconfig(section, name)
1599 backups[(section, name)] = self.backupconfig(section, name)
1600 self.setconfig(section, name, value, source)
1600 self.setconfig(section, name, value, source)
1601 yield
1601 yield
1602 finally:
1602 finally:
1603 for __, backup in backups.items():
1603 for __, backup in backups.items():
1604 self.restoreconfig(backup)
1604 self.restoreconfig(backup)
1605 # just restoring ui.quiet config to the previous value is not enough
1605 # just restoring ui.quiet config to the previous value is not enough
1606 # as it does not update ui.quiet class member
1606 # as it does not update ui.quiet class member
1607 if ('ui', 'quiet') in overrides:
1607 if ('ui', 'quiet') in overrides:
1608 self.fixconfig(section='ui')
1608 self.fixconfig(section='ui')
1609
1609
1610 class paths(dict):
1610 class paths(dict):
1611 """Represents a collection of paths and their configs.
1611 """Represents a collection of paths and their configs.
1612
1612
1613 Data is initially derived from ui instances and the config files they have
1613 Data is initially derived from ui instances and the config files they have
1614 loaded.
1614 loaded.
1615 """
1615 """
1616 def __init__(self, ui):
1616 def __init__(self, ui):
1617 dict.__init__(self)
1617 dict.__init__(self)
1618
1618
1619 for name, loc in ui.configitems('paths', ignoresub=True):
1619 for name, loc in ui.configitems('paths', ignoresub=True):
1620 # No location is the same as not existing.
1620 # No location is the same as not existing.
1621 if not loc:
1621 if not loc:
1622 continue
1622 continue
1623 loc, sub = ui.configsuboptions('paths', name)
1623 loc, sub = ui.configsuboptions('paths', name)
1624 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1624 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1625
1625
1626 def getpath(self, name, default=None):
1626 def getpath(self, name, default=None):
1627 """Return a ``path`` from a string, falling back to default.
1627 """Return a ``path`` from a string, falling back to default.
1628
1628
1629 ``name`` can be a named path or locations. Locations are filesystem
1629 ``name`` can be a named path or locations. Locations are filesystem
1630 paths or URIs.
1630 paths or URIs.
1631
1631
1632 Returns None if ``name`` is not a registered path, a URI, or a local
1632 Returns None if ``name`` is not a registered path, a URI, or a local
1633 path to a repo.
1633 path to a repo.
1634 """
1634 """
1635 # Only fall back to default if no path was requested.
1635 # Only fall back to default if no path was requested.
1636 if name is None:
1636 if name is None:
1637 if not default:
1637 if not default:
1638 default = ()
1638 default = ()
1639 elif not isinstance(default, (tuple, list)):
1639 elif not isinstance(default, (tuple, list)):
1640 default = (default,)
1640 default = (default,)
1641 for k in default:
1641 for k in default:
1642 try:
1642 try:
1643 return self[k]
1643 return self[k]
1644 except KeyError:
1644 except KeyError:
1645 continue
1645 continue
1646 return None
1646 return None
1647
1647
1648 # Most likely empty string.
1648 # Most likely empty string.
1649 # This may need to raise in the future.
1649 # This may need to raise in the future.
1650 if not name:
1650 if not name:
1651 return None
1651 return None
1652
1652
1653 try:
1653 try:
1654 return self[name]
1654 return self[name]
1655 except KeyError:
1655 except KeyError:
1656 # Try to resolve as a local path or URI.
1656 # Try to resolve as a local path or URI.
1657 try:
1657 try:
1658 # We don't pass sub-options in, so no need to pass ui instance.
1658 # We don't pass sub-options in, so no need to pass ui instance.
1659 return path(None, None, rawloc=name)
1659 return path(None, None, rawloc=name)
1660 except ValueError:
1660 except ValueError:
1661 raise error.RepoError(_('repository %s does not exist') %
1661 raise error.RepoError(_('repository %s does not exist') %
1662 name)
1662 name)
1663
1663
1664 _pathsuboptions = {}
1664 _pathsuboptions = {}
1665
1665
1666 def pathsuboption(option, attr):
1666 def pathsuboption(option, attr):
1667 """Decorator used to declare a path sub-option.
1667 """Decorator used to declare a path sub-option.
1668
1668
1669 Arguments are the sub-option name and the attribute it should set on
1669 Arguments are the sub-option name and the attribute it should set on
1670 ``path`` instances.
1670 ``path`` instances.
1671
1671
1672 The decorated function will receive as arguments a ``ui`` instance,
1672 The decorated function will receive as arguments a ``ui`` instance,
1673 ``path`` instance, and the string value of this option from the config.
1673 ``path`` instance, and the string value of this option from the config.
1674 The function should return the value that will be set on the ``path``
1674 The function should return the value that will be set on the ``path``
1675 instance.
1675 instance.
1676
1676
1677 This decorator can be used to perform additional verification of
1677 This decorator can be used to perform additional verification of
1678 sub-options and to change the type of sub-options.
1678 sub-options and to change the type of sub-options.
1679 """
1679 """
1680 def register(func):
1680 def register(func):
1681 _pathsuboptions[option] = (attr, func)
1681 _pathsuboptions[option] = (attr, func)
1682 return func
1682 return func
1683 return register
1683 return register
1684
1684
1685 @pathsuboption('pushurl', 'pushloc')
1685 @pathsuboption('pushurl', 'pushloc')
1686 def pushurlpathoption(ui, path, value):
1686 def pushurlpathoption(ui, path, value):
1687 u = util.url(value)
1687 u = util.url(value)
1688 # Actually require a URL.
1688 # Actually require a URL.
1689 if not u.scheme:
1689 if not u.scheme:
1690 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1690 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1691 return None
1691 return None
1692
1692
1693 # Don't support the #foo syntax in the push URL to declare branch to
1693 # Don't support the #foo syntax in the push URL to declare branch to
1694 # push.
1694 # push.
1695 if u.fragment:
1695 if u.fragment:
1696 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1696 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1697 'ignoring)\n') % path.name)
1697 'ignoring)\n') % path.name)
1698 u.fragment = None
1698 u.fragment = None
1699
1699
1700 return str(u)
1700 return str(u)
1701
1701
1702 @pathsuboption('pushrev', 'pushrev')
1702 @pathsuboption('pushrev', 'pushrev')
1703 def pushrevpathoption(ui, path, value):
1703 def pushrevpathoption(ui, path, value):
1704 return value
1704 return value
1705
1705
1706 class path(object):
1706 class path(object):
1707 """Represents an individual path and its configuration."""
1707 """Represents an individual path and its configuration."""
1708
1708
1709 def __init__(self, ui, name, rawloc=None, suboptions=None):
1709 def __init__(self, ui, name, rawloc=None, suboptions=None):
1710 """Construct a path from its config options.
1710 """Construct a path from its config options.
1711
1711
1712 ``ui`` is the ``ui`` instance the path is coming from.
1712 ``ui`` is the ``ui`` instance the path is coming from.
1713 ``name`` is the symbolic name of the path.
1713 ``name`` is the symbolic name of the path.
1714 ``rawloc`` is the raw location, as defined in the config.
1714 ``rawloc`` is the raw location, as defined in the config.
1715 ``pushloc`` is the raw locations pushes should be made to.
1715 ``pushloc`` is the raw locations pushes should be made to.
1716
1716
1717 If ``name`` is not defined, we require that the location be a) a local
1717 If ``name`` is not defined, we require that the location be a) a local
1718 filesystem path with a .hg directory or b) a URL. If not,
1718 filesystem path with a .hg directory or b) a URL. If not,
1719 ``ValueError`` is raised.
1719 ``ValueError`` is raised.
1720 """
1720 """
1721 if not rawloc:
1721 if not rawloc:
1722 raise ValueError('rawloc must be defined')
1722 raise ValueError('rawloc must be defined')
1723
1723
1724 # Locations may define branches via syntax <base>#<branch>.
1724 # Locations may define branches via syntax <base>#<branch>.
1725 u = util.url(rawloc)
1725 u = util.url(rawloc)
1726 branch = None
1726 branch = None
1727 if u.fragment:
1727 if u.fragment:
1728 branch = u.fragment
1728 branch = u.fragment
1729 u.fragment = None
1729 u.fragment = None
1730
1730
1731 self.url = u
1731 self.url = u
1732 self.branch = branch
1732 self.branch = branch
1733
1733
1734 self.name = name
1734 self.name = name
1735 self.rawloc = rawloc
1735 self.rawloc = rawloc
1736 self.loc = '%s' % u
1736 self.loc = '%s' % u
1737
1737
1738 # When given a raw location but not a symbolic name, validate the
1738 # When given a raw location but not a symbolic name, validate the
1739 # location is valid.
1739 # location is valid.
1740 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1740 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1741 raise ValueError('location is not a URL or path to a local '
1741 raise ValueError('location is not a URL or path to a local '
1742 'repo: %s' % rawloc)
1742 'repo: %s' % rawloc)
1743
1743
1744 suboptions = suboptions or {}
1744 suboptions = suboptions or {}
1745
1745
1746 # Now process the sub-options. If a sub-option is registered, its
1746 # Now process the sub-options. If a sub-option is registered, its
1747 # attribute will always be present. The value will be None if there
1747 # attribute will always be present. The value will be None if there
1748 # was no valid sub-option.
1748 # was no valid sub-option.
1749 for suboption, (attr, func) in _pathsuboptions.iteritems():
1749 for suboption, (attr, func) in _pathsuboptions.iteritems():
1750 if suboption not in suboptions:
1750 if suboption not in suboptions:
1751 setattr(self, attr, None)
1751 setattr(self, attr, None)
1752 continue
1752 continue
1753
1753
1754 value = func(ui, self, suboptions[suboption])
1754 value = func(ui, self, suboptions[suboption])
1755 setattr(self, attr, value)
1755 setattr(self, attr, value)
1756
1756
1757 def _isvalidlocalpath(self, path):
1757 def _isvalidlocalpath(self, path):
1758 """Returns True if the given path is a potentially valid repository.
1758 """Returns True if the given path is a potentially valid repository.
1759 This is its own function so that extensions can change the definition of
1759 This is its own function so that extensions can change the definition of
1760 'valid' in this case (like when pulling from a git repo into a hg
1760 'valid' in this case (like when pulling from a git repo into a hg
1761 one)."""
1761 one)."""
1762 return os.path.isdir(os.path.join(path, '.hg'))
1762 return os.path.isdir(os.path.join(path, '.hg'))
1763
1763
1764 @property
1764 @property
1765 def suboptions(self):
1765 def suboptions(self):
1766 """Return sub-options and their values for this path.
1766 """Return sub-options and their values for this path.
1767
1767
1768 This is intended to be used for presentation purposes.
1768 This is intended to be used for presentation purposes.
1769 """
1769 """
1770 d = {}
1770 d = {}
1771 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1771 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1772 value = getattr(self, attr)
1772 value = getattr(self, attr)
1773 if value is not None:
1773 if value is not None:
1774 d[subopt] = value
1774 d[subopt] = value
1775 return d
1775 return d
1776
1776
1777 # we instantiate one globally shared progress bar to avoid
1777 # we instantiate one globally shared progress bar to avoid
1778 # competing progress bars when multiple UI objects get created
1778 # competing progress bars when multiple UI objects get created
1779 _progresssingleton = None
1779 _progresssingleton = None
1780
1780
1781 def getprogbar(ui):
1781 def getprogbar(ui):
1782 global _progresssingleton
1782 global _progresssingleton
1783 if _progresssingleton is None:
1783 if _progresssingleton is None:
1784 # passing 'ui' object to the singleton is fishy,
1784 # passing 'ui' object to the singleton is fishy,
1785 # this is how the extension used to work but feel free to rework it.
1785 # this is how the extension used to work but feel free to rework it.
1786 _progresssingleton = progress.progbar(ui)
1786 _progresssingleton = progress.progbar(ui)
1787 return _progresssingleton
1787 return _progresssingleton
1788
1789 def haveprogbar():
1790 return _progresssingleton is not None
@@ -1,1165 +1,1191 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extdiff]
2 > [extdiff]
3 > # for portability:
3 > # for portability:
4 > pdiff = sh "$RUNTESTDIR/pdiff"
4 > pdiff = sh "$RUNTESTDIR/pdiff"
5 > [progress]
5 > [progress]
6 > disable=False
6 > disable=False
7 > assume-tty = 1
7 > assume-tty = 1
8 > delay = 0
8 > delay = 0
9 > # set changedelay really large so we don't see nested topics
9 > # set changedelay really large so we don't see nested topics
10 > changedelay = 30000
10 > changedelay = 30000
11 > format = topic bar number
11 > format = topic bar number
12 > refresh = 0
12 > refresh = 0
13 > width = 60
13 > width = 60
14 > EOF
14 > EOF
15
15
16 Preparing the subrepository 'sub2'
16 Preparing the subrepository 'sub2'
17
17
18 $ hg init sub2
18 $ hg init sub2
19 $ echo sub2 > sub2/sub2
19 $ echo sub2 > sub2/sub2
20 $ hg add -R sub2
20 $ hg add -R sub2
21 adding sub2/sub2 (glob)
21 adding sub2/sub2 (glob)
22 $ hg commit -R sub2 -m "sub2 import"
22 $ hg commit -R sub2 -m "sub2 import"
23
23
24 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
24 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
25
25
26 $ hg init sub1
26 $ hg init sub1
27 $ echo sub1 > sub1/sub1
27 $ echo sub1 > sub1/sub1
28 $ echo "sub2 = ../sub2" > sub1/.hgsub
28 $ echo "sub2 = ../sub2" > sub1/.hgsub
29 $ hg clone sub2 sub1/sub2
29 $ hg clone sub2 sub1/sub2
30 \r (no-eol) (esc)
30 \r (no-eol) (esc)
31 linking [ <=> ] 1\r (no-eol) (esc)
31 linking [ <=> ] 1\r (no-eol) (esc)
32 linking [ <=> ] 2\r (no-eol) (esc)
32 linking [ <=> ] 2\r (no-eol) (esc)
33 linking [ <=> ] 3\r (no-eol) (esc)
33 linking [ <=> ] 3\r (no-eol) (esc)
34 linking [ <=> ] 4\r (no-eol) (esc)
34 linking [ <=> ] 4\r (no-eol) (esc)
35 linking [ <=> ] 5\r (no-eol) (esc)
35 linking [ <=> ] 5\r (no-eol) (esc)
36 linking [ <=> ] 6\r (no-eol) (esc)
36 linking [ <=> ] 6\r (no-eol) (esc)
37 \r (no-eol) (esc)
37 \r (no-eol) (esc)
38 \r (no-eol) (esc)
38 \r (no-eol) (esc)
39 updating [===========================================>] 1/1\r (no-eol) (esc)
39 updating [===========================================>] 1/1\r (no-eol) (esc)
40 \r (no-eol) (esc)
40 \r (no-eol) (esc)
41 updating to branch default
41 updating to branch default
42 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 $ hg add -R sub1
43 $ hg add -R sub1
44 adding sub1/.hgsub (glob)
44 adding sub1/.hgsub (glob)
45 adding sub1/sub1 (glob)
45 adding sub1/sub1 (glob)
46 $ hg commit -R sub1 -m "sub1 import"
46 $ hg commit -R sub1 -m "sub1 import"
47
47
48 Preparing the 'main' repo which depends on the subrepo 'sub1'
48 Preparing the 'main' repo which depends on the subrepo 'sub1'
49
49
50 $ hg init main
50 $ hg init main
51 $ echo main > main/main
51 $ echo main > main/main
52 $ echo "sub1 = ../sub1" > main/.hgsub
52 $ echo "sub1 = ../sub1" > main/.hgsub
53 $ hg clone sub1 main/sub1
53 $ hg clone sub1 main/sub1
54 \r (no-eol) (esc)
54 \r (no-eol) (esc)
55 linking [ <=> ] 1\r (no-eol) (esc)
55 linking [ <=> ] 1\r (no-eol) (esc)
56 linking [ <=> ] 2\r (no-eol) (esc)
56 linking [ <=> ] 2\r (no-eol) (esc)
57 linking [ <=> ] 3\r (no-eol) (esc)
57 linking [ <=> ] 3\r (no-eol) (esc)
58 linking [ <=> ] 4\r (no-eol) (esc)
58 linking [ <=> ] 4\r (no-eol) (esc)
59 linking [ <=> ] 5\r (no-eol) (esc)
59 linking [ <=> ] 5\r (no-eol) (esc)
60 linking [ <=> ] 6\r (no-eol) (esc)
60 linking [ <=> ] 6\r (no-eol) (esc)
61 linking [ <=> ] 7\r (no-eol) (esc)
61 linking [ <=> ] 7\r (no-eol) (esc)
62 linking [ <=> ] 8\r (no-eol) (esc)
62 linking [ <=> ] 8\r (no-eol) (esc)
63 \r (no-eol) (esc)
63 \r (no-eol) (esc)
64 \r (no-eol) (esc)
64 \r (no-eol) (esc)
65 updating [===========================================>] 3/3\r (no-eol) (esc)
65 updating [===========================================>] 3/3\r (no-eol) (esc)
66 \r (no-eol) (esc)
67 \r (no-eol) (esc)
68 linking [ <=> ] 1\r (no-eol) (esc)
69 linking [ <=> ] 2\r (no-eol) (esc)
70 linking [ <=> ] 3\r (no-eol) (esc)
71 linking [ <=> ] 4\r (no-eol) (esc)
72 linking [ <=> ] 5\r (no-eol) (esc)
73 linking [ <=> ] 6\r (no-eol) (esc)
66 updating [===========================================>] 1/1\r (no-eol) (esc)
74 updating [===========================================>] 1/1\r (no-eol) (esc)
67 \r (no-eol) (esc)
75 \r (no-eol) (esc)
68 updating to branch default
76 updating to branch default
69 cloning subrepo sub2 from $TESTTMP/sub2
77 cloning subrepo sub2 from $TESTTMP/sub2
70 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 $ hg add -R main
79 $ hg add -R main
72 adding main/.hgsub (glob)
80 adding main/.hgsub (glob)
73 adding main/main (glob)
81 adding main/main (glob)
74 $ hg commit -R main -m "main import"
82 $ hg commit -R main -m "main import"
75
83
76 #if serve
84 #if serve
77
85
78 Unfortunately, subrepos not at their nominal location cannot be cloned. But
86 Unfortunately, subrepos not at their nominal location cannot be cloned. But
79 they are still served from their location within the local repository. The only
87 they are still served from their location within the local repository. The only
80 reason why 'main' can be cloned via the filesystem is because 'sub1' and 'sub2'
88 reason why 'main' can be cloned via the filesystem is because 'sub1' and 'sub2'
81 are also available as siblings of 'main'.
89 are also available as siblings of 'main'.
82
90
83 $ hg serve -R main --debug -S -p $HGPORT -d --pid-file=hg1.pid -E error.log -A access.log
91 $ hg serve -R main --debug -S -p $HGPORT -d --pid-file=hg1.pid -E error.log -A access.log
84 adding = $TESTTMP/main (glob)
92 adding = $TESTTMP/main (glob)
85 adding sub1 = $TESTTMP/main/sub1 (glob)
93 adding sub1 = $TESTTMP/main/sub1 (glob)
86 adding sub1/sub2 = $TESTTMP/main/sub1/sub2 (glob)
94 adding sub1/sub2 = $TESTTMP/main/sub1/sub2 (glob)
87 listening at http://*:$HGPORT/ (bound to *:$HGPORT) (glob) (?)
95 listening at http://*:$HGPORT/ (bound to *:$HGPORT) (glob) (?)
88 adding = $TESTTMP/main (glob) (?)
96 adding = $TESTTMP/main (glob) (?)
89 adding sub1 = $TESTTMP/main/sub1 (glob) (?)
97 adding sub1 = $TESTTMP/main/sub1 (glob) (?)
90 adding sub1/sub2 = $TESTTMP/main/sub1/sub2 (glob) (?)
98 adding sub1/sub2 = $TESTTMP/main/sub1/sub2 (glob) (?)
91 $ cat hg1.pid >> $DAEMON_PIDS
99 $ cat hg1.pid >> $DAEMON_PIDS
92
100
93 $ hg clone http://localhost:$HGPORT httpclone --config progress.disable=True
101 $ hg clone http://localhost:$HGPORT httpclone --config progress.disable=True
94 requesting all changes
102 requesting all changes
95 adding changesets
103 adding changesets
96 adding manifests
104 adding manifests
97 adding file changes
105 adding file changes
98 added 1 changesets with 3 changes to 3 files
106 added 1 changesets with 3 changes to 3 files
99 updating to branch default
107 updating to branch default
100 abort: HTTP Error 404: Not Found
108 abort: HTTP Error 404: Not Found
101 [255]
109 [255]
102
110
103 $ cat access.log
111 $ cat access.log
104 * "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
112 * "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
105 * "GET /?cmd=batch HTTP/1.1" 200 - * (glob)
113 * "GET /?cmd=batch HTTP/1.1" 200 - * (glob)
106 * "GET /?cmd=getbundle HTTP/1.1" 200 - * (glob)
114 * "GET /?cmd=getbundle HTTP/1.1" 200 - * (glob)
107 * "GET /../sub1?cmd=capabilities HTTP/1.1" 404 - (glob)
115 * "GET /../sub1?cmd=capabilities HTTP/1.1" 404 - (glob)
108
116
109 $ killdaemons.py
117 $ killdaemons.py
110 $ rm hg1.pid error.log access.log
118 $ rm hg1.pid error.log access.log
111 #endif
119 #endif
112
120
113 Cleaning both repositories, just as a clone -U
121 Cleaning both repositories, just as a clone -U
114
122
115 $ hg up -C -R sub2 null
123 $ hg up -C -R sub2 null
116 \r (no-eol) (esc)
124 \r (no-eol) (esc)
117 updating [===========================================>] 1/1\r (no-eol) (esc)
125 updating [===========================================>] 1/1\r (no-eol) (esc)
118 \r (no-eol) (esc)
126 \r (no-eol) (esc)
119 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
127 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
120 $ hg up -C -R sub1 null
128 $ hg up -C -R sub1 null
121 \r (no-eol) (esc)
129 \r (no-eol) (esc)
122 updating [===========================================>] 1/1\r (no-eol) (esc)
130 updating [===========================================>] 1/1\r (no-eol) (esc)
123 \r (no-eol) (esc)
131 \r (no-eol) (esc)
124 \r (no-eol) (esc)
132 \r (no-eol) (esc)
125 updating [===========================================>] 3/3\r (no-eol) (esc)
133 updating [===========================================>] 3/3\r (no-eol) (esc)
126 \r (no-eol) (esc)
134 \r (no-eol) (esc)
127 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
135 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
128 $ hg up -C -R main null
136 $ hg up -C -R main null
129 \r (no-eol) (esc)
137 \r (no-eol) (esc)
130 updating [===========================================>] 1/1\r (no-eol) (esc)
138 updating [===========================================>] 1/1\r (no-eol) (esc)
131 \r (no-eol) (esc)
139 \r (no-eol) (esc)
132 \r (no-eol) (esc)
140 \r (no-eol) (esc)
133 updating [===========================================>] 3/3\r (no-eol) (esc)
141 updating [===========================================>] 3/3\r (no-eol) (esc)
134 \r (no-eol) (esc)
142 \r (no-eol) (esc)
135 \r (no-eol) (esc)
143 \r (no-eol) (esc)
136 updating [===========================================>] 3/3\r (no-eol) (esc)
144 updating [===========================================>] 3/3\r (no-eol) (esc)
137 \r (no-eol) (esc)
145 \r (no-eol) (esc)
138 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
146 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
139 $ rm -rf main/sub1
147 $ rm -rf main/sub1
140 $ rm -rf sub1/sub2
148 $ rm -rf sub1/sub2
141
149
142 Clone main
150 Clone main
143
151
144 $ hg --config extensions.largefiles= clone main cloned
152 $ hg --config extensions.largefiles= clone main cloned
145 \r (no-eol) (esc)
153 \r (no-eol) (esc)
146 linking [ <=> ] 1\r (no-eol) (esc)
154 linking [ <=> ] 1\r (no-eol) (esc)
147 linking [ <=> ] 2\r (no-eol) (esc)
155 linking [ <=> ] 2\r (no-eol) (esc)
148 linking [ <=> ] 3\r (no-eol) (esc)
156 linking [ <=> ] 3\r (no-eol) (esc)
149 linking [ <=> ] 4\r (no-eol) (esc)
157 linking [ <=> ] 4\r (no-eol) (esc)
150 linking [ <=> ] 5\r (no-eol) (esc)
158 linking [ <=> ] 5\r (no-eol) (esc)
151 linking [ <=> ] 6\r (no-eol) (esc)
159 linking [ <=> ] 6\r (no-eol) (esc)
152 linking [ <=> ] 7\r (no-eol) (esc)
160 linking [ <=> ] 7\r (no-eol) (esc)
153 linking [ <=> ] 8\r (no-eol) (esc)
161 linking [ <=> ] 8\r (no-eol) (esc)
154 \r (no-eol) (esc)
162 \r (no-eol) (esc)
155 \r (no-eol) (esc)
163 \r (no-eol) (esc)
156 updating [===========================================>] 3/3\r (no-eol) (esc)
164 updating [===========================================>] 3/3\r (no-eol) (esc)
165 \r (no-eol) (esc)
166 \r (no-eol) (esc)
167 linking [ <=> ] 1\r (no-eol) (esc)
168 linking [ <=> ] 2\r (no-eol) (esc)
169 linking [ <=> ] 3\r (no-eol) (esc)
170 linking [ <=> ] 4\r (no-eol) (esc)
171 linking [ <=> ] 5\r (no-eol) (esc)
172 linking [ <=> ] 6\r (no-eol) (esc)
173 linking [ <=> ] 7\r (no-eol) (esc)
174 linking [ <=> ] 8\r (no-eol) (esc)
157 updating [===========================================>] 3/3\r (no-eol) (esc)
175 updating [===========================================>] 3/3\r (no-eol) (esc)
176 \r (no-eol) (esc)
177 \r (no-eol) (esc)
178 linking [ <=> ] 1\r (no-eol) (esc)
179 linking [ <=> ] 2\r (no-eol) (esc)
180 linking [ <=> ] 3\r (no-eol) (esc)
181 linking [ <=> ] 4\r (no-eol) (esc)
182 linking [ <=> ] 5\r (no-eol) (esc)
183 linking [ <=> ] 6\r (no-eol) (esc)
158 updating [===========================================>] 1/1\r (no-eol) (esc)
184 updating [===========================================>] 1/1\r (no-eol) (esc)
159 \r (no-eol) (esc)
185 \r (no-eol) (esc)
160 updating to branch default
186 updating to branch default
161 cloning subrepo sub1 from $TESTTMP/sub1
187 cloning subrepo sub1 from $TESTTMP/sub1
162 cloning subrepo sub1/sub2 from $TESTTMP/sub2 (glob)
188 cloning subrepo sub1/sub2 from $TESTTMP/sub2 (glob)
163 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
164
190
165 Largefiles is NOT enabled in the clone if the source repo doesn't require it
191 Largefiles is NOT enabled in the clone if the source repo doesn't require it
166 $ cat cloned/.hg/hgrc
192 $ cat cloned/.hg/hgrc
167 # example repository config (see 'hg help config' for more info)
193 # example repository config (see 'hg help config' for more info)
168 [paths]
194 [paths]
169 default = $TESTTMP/main (glob)
195 default = $TESTTMP/main (glob)
170
196
171 # path aliases to other clones of this repo in URLs or filesystem paths
197 # path aliases to other clones of this repo in URLs or filesystem paths
172 # (see 'hg help config.paths' for more info)
198 # (see 'hg help config.paths' for more info)
173 #
199 #
174 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
200 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
175 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
201 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
176 # my-clone = /home/jdoe/jdoes-clone
202 # my-clone = /home/jdoe/jdoes-clone
177
203
178 [ui]
204 [ui]
179 # name and email (local to this repository, optional), e.g.
205 # name and email (local to this repository, optional), e.g.
180 # username = Jane Doe <jdoe@example.com>
206 # username = Jane Doe <jdoe@example.com>
181
207
182 Checking cloned repo ids
208 Checking cloned repo ids
183
209
184 $ printf "cloned " ; hg id -R cloned
210 $ printf "cloned " ; hg id -R cloned
185 cloned 7f491f53a367 tip
211 cloned 7f491f53a367 tip
186 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
212 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
187 cloned/sub1 fc3b4ce2696f tip
213 cloned/sub1 fc3b4ce2696f tip
188 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
214 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
189 cloned/sub1/sub2 c57a0840e3ba tip
215 cloned/sub1/sub2 c57a0840e3ba tip
190
216
191 debugsub output for main and sub1
217 debugsub output for main and sub1
192
218
193 $ hg debugsub -R cloned
219 $ hg debugsub -R cloned
194 path sub1
220 path sub1
195 source ../sub1
221 source ../sub1
196 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
222 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
197 $ hg debugsub -R cloned/sub1
223 $ hg debugsub -R cloned/sub1
198 path sub2
224 path sub2
199 source ../sub2
225 source ../sub2
200 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
226 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
201
227
202 Modifying deeply nested 'sub2'
228 Modifying deeply nested 'sub2'
203
229
204 $ echo modified > cloned/sub1/sub2/sub2
230 $ echo modified > cloned/sub1/sub2/sub2
205 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
231 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
206 committing subrepository sub1
232 committing subrepository sub1
207 committing subrepository sub1/sub2 (glob)
233 committing subrepository sub1/sub2 (glob)
208
234
209 Checking modified node ids
235 Checking modified node ids
210
236
211 $ printf "cloned " ; hg id -R cloned
237 $ printf "cloned " ; hg id -R cloned
212 cloned ffe6649062fe tip
238 cloned ffe6649062fe tip
213 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
239 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
214 cloned/sub1 2ecb03bf44a9 tip
240 cloned/sub1 2ecb03bf44a9 tip
215 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
241 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
216 cloned/sub1/sub2 53dd3430bcaf tip
242 cloned/sub1/sub2 53dd3430bcaf tip
217
243
218 debugsub output for main and sub1
244 debugsub output for main and sub1
219
245
220 $ hg debugsub -R cloned
246 $ hg debugsub -R cloned
221 path sub1
247 path sub1
222 source ../sub1
248 source ../sub1
223 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
249 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
224 $ hg debugsub -R cloned/sub1
250 $ hg debugsub -R cloned/sub1
225 path sub2
251 path sub2
226 source ../sub2
252 source ../sub2
227 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
253 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
228
254
229 Check that deep archiving works
255 Check that deep archiving works
230
256
231 $ cd cloned
257 $ cd cloned
232 $ echo 'test' > sub1/sub2/test.txt
258 $ echo 'test' > sub1/sub2/test.txt
233 $ hg --config extensions.largefiles=! add sub1/sub2/test.txt
259 $ hg --config extensions.largefiles=! add sub1/sub2/test.txt
234 $ mkdir sub1/sub2/folder
260 $ mkdir sub1/sub2/folder
235 $ echo 'subfolder' > sub1/sub2/folder/test.txt
261 $ echo 'subfolder' > sub1/sub2/folder/test.txt
236 $ hg ci -ASm "add test.txt"
262 $ hg ci -ASm "add test.txt"
237 adding sub1/sub2/folder/test.txt
263 adding sub1/sub2/folder/test.txt
238 committing subrepository sub1
264 committing subrepository sub1
239 committing subrepository sub1/sub2 (glob)
265 committing subrepository sub1/sub2 (glob)
240
266
241 $ rm -r main
267 $ rm -r main
242 $ hg archive -S -qr 'wdir()' ../wdir
268 $ hg archive -S -qr 'wdir()' ../wdir
243 $ cat ../wdir/.hg_archival.txt
269 $ cat ../wdir/.hg_archival.txt
244 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
270 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
245 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd+
271 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd+
246 branch: default
272 branch: default
247 latesttag: null
273 latesttag: null
248 latesttagdistance: 4
274 latesttagdistance: 4
249 changessincelatesttag: 4
275 changessincelatesttag: 4
250 $ hg update -Cq .
276 $ hg update -Cq .
251
277
252 A deleted subrepo file is flagged as dirty, like the top level repo
278 A deleted subrepo file is flagged as dirty, like the top level repo
253
279
254 $ rm -r ../wdir sub1/sub2/folder/test.txt
280 $ rm -r ../wdir sub1/sub2/folder/test.txt
255 $ hg archive -S -qr 'wdir()' ../wdir
281 $ hg archive -S -qr 'wdir()' ../wdir
256 $ cat ../wdir/.hg_archival.txt
282 $ cat ../wdir/.hg_archival.txt
257 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
283 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
258 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd+
284 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd+
259 branch: default
285 branch: default
260 latesttag: null
286 latesttag: null
261 latesttagdistance: 4
287 latesttagdistance: 4
262 changessincelatesttag: 4
288 changessincelatesttag: 4
263 $ hg update -Cq .
289 $ hg update -Cq .
264 $ rm -r ../wdir
290 $ rm -r ../wdir
265
291
266 $ hg archive -S -qr 'wdir()' ../wdir \
292 $ hg archive -S -qr 'wdir()' ../wdir \
267 > --config 'experimental.archivemetatemplate=archived {node|short}\n'
293 > --config 'experimental.archivemetatemplate=archived {node|short}\n'
268 $ cat ../wdir/.hg_archival.txt
294 $ cat ../wdir/.hg_archival.txt
269 archived ffffffffffff
295 archived ffffffffffff
270 $ rm -r ../wdir
296 $ rm -r ../wdir
271
297
272 .. but first take a detour through some deep removal testing
298 .. but first take a detour through some deep removal testing
273
299
274 $ hg remove -S -I 're:.*.txt' .
300 $ hg remove -S -I 're:.*.txt' .
275 \r (no-eol) (esc)
301 \r (no-eol) (esc)
276 searching [==========================================>] 1/1\r (no-eol) (esc)
302 searching [==========================================>] 1/1\r (no-eol) (esc)
277 searching [==========================================>] 1/1\r (no-eol) (esc)
303 searching [==========================================>] 1/1\r (no-eol) (esc)
278 \r (no-eol) (esc)
304 \r (no-eol) (esc)
279 \r (no-eol) (esc)
305 \r (no-eol) (esc)
280 deleting [=====================> ] 1/2\r (no-eol) (esc)
306 deleting [=====================> ] 1/2\r (no-eol) (esc)
281 \r (no-eol) (esc)
307 \r (no-eol) (esc)
282 \r (no-eol) (esc)
308 \r (no-eol) (esc)
283 deleting [===========================================>] 2/2\r (no-eol) (esc)
309 deleting [===========================================>] 2/2\r (no-eol) (esc)
284 \r (no-eol) (esc)
310 \r (no-eol) (esc)
285 removing sub1/sub2/folder/test.txt (glob)
311 removing sub1/sub2/folder/test.txt (glob)
286 removing sub1/sub2/test.txt (glob)
312 removing sub1/sub2/test.txt (glob)
287 $ hg status -S
313 $ hg status -S
288 R sub1/sub2/folder/test.txt
314 R sub1/sub2/folder/test.txt
289 R sub1/sub2/test.txt
315 R sub1/sub2/test.txt
290 $ hg update -Cq
316 $ hg update -Cq
291 $ hg remove -I 're:.*.txt' sub1
317 $ hg remove -I 're:.*.txt' sub1
292 \r (no-eol) (esc)
318 \r (no-eol) (esc)
293 searching [==========================================>] 1/1\r (no-eol) (esc)
319 searching [==========================================>] 1/1\r (no-eol) (esc)
294 \r (no-eol) (esc)
320 \r (no-eol) (esc)
295 \r (no-eol) (esc)
321 \r (no-eol) (esc)
296 deleting [===========================================>] 1/1\r (no-eol) (esc)
322 deleting [===========================================>] 1/1\r (no-eol) (esc)
297 \r (no-eol) (esc)
323 \r (no-eol) (esc)
298 $ hg status -S
324 $ hg status -S
299 $ hg remove sub1/sub2/folder/test.txt
325 $ hg remove sub1/sub2/folder/test.txt
300 \r (no-eol) (esc)
326 \r (no-eol) (esc)
301 searching [==========================================>] 1/1\r (no-eol) (esc)
327 searching [==========================================>] 1/1\r (no-eol) (esc)
302 searching [==========================================>] 1/1\r (no-eol) (esc)
328 searching [==========================================>] 1/1\r (no-eol) (esc)
303 \r (no-eol) (esc)
329 \r (no-eol) (esc)
304 \r (no-eol) (esc)
330 \r (no-eol) (esc)
305 deleting [===========================================>] 1/1\r (no-eol) (esc)
331 deleting [===========================================>] 1/1\r (no-eol) (esc)
306 \r (no-eol) (esc)
332 \r (no-eol) (esc)
307 \r (no-eol) (esc)
333 \r (no-eol) (esc)
308 deleting [===========================================>] 1/1\r (no-eol) (esc)
334 deleting [===========================================>] 1/1\r (no-eol) (esc)
309 \r (no-eol) (esc)
335 \r (no-eol) (esc)
310 \r (no-eol) (esc)
336 \r (no-eol) (esc)
311 deleting [===========================================>] 1/1\r (no-eol) (esc)
337 deleting [===========================================>] 1/1\r (no-eol) (esc)
312 \r (no-eol) (esc)
338 \r (no-eol) (esc)
313 $ hg remove sub1/.hgsubstate
339 $ hg remove sub1/.hgsubstate
314 \r (no-eol) (esc)
340 \r (no-eol) (esc)
315 searching [==========================================>] 1/1\r (no-eol) (esc)
341 searching [==========================================>] 1/1\r (no-eol) (esc)
316 \r (no-eol) (esc)
342 \r (no-eol) (esc)
317 \r (no-eol) (esc)
343 \r (no-eol) (esc)
318 deleting [===========================================>] 1/1\r (no-eol) (esc)
344 deleting [===========================================>] 1/1\r (no-eol) (esc)
319 \r (no-eol) (esc)
345 \r (no-eol) (esc)
320 \r (no-eol) (esc)
346 \r (no-eol) (esc)
321 deleting [===========================================>] 1/1\r (no-eol) (esc)
347 deleting [===========================================>] 1/1\r (no-eol) (esc)
322 \r (no-eol) (esc)
348 \r (no-eol) (esc)
323 $ mv sub1/.hgsub sub1/x.hgsub
349 $ mv sub1/.hgsub sub1/x.hgsub
324 $ hg status -S
350 $ hg status -S
325 warning: subrepo spec file 'sub1/.hgsub' not found
351 warning: subrepo spec file 'sub1/.hgsub' not found
326 R sub1/.hgsubstate
352 R sub1/.hgsubstate
327 R sub1/sub2/folder/test.txt
353 R sub1/sub2/folder/test.txt
328 ! sub1/.hgsub
354 ! sub1/.hgsub
329 ? sub1/x.hgsub
355 ? sub1/x.hgsub
330 $ mv sub1/x.hgsub sub1/.hgsub
356 $ mv sub1/x.hgsub sub1/.hgsub
331 $ hg update -Cq
357 $ hg update -Cq
332 $ touch sub1/foo
358 $ touch sub1/foo
333 $ hg forget sub1/sub2/folder/test.txt
359 $ hg forget sub1/sub2/folder/test.txt
334 $ rm sub1/sub2/test.txt
360 $ rm sub1/sub2/test.txt
335
361
336 Test relative path printing + subrepos
362 Test relative path printing + subrepos
337 $ mkdir -p foo/bar
363 $ mkdir -p foo/bar
338 $ cd foo
364 $ cd foo
339 $ touch bar/abc
365 $ touch bar/abc
340 $ hg addremove -S ..
366 $ hg addremove -S ..
341 \r (no-eol) (esc)
367 \r (no-eol) (esc)
342 searching for exact renames [ ] 0/1\r (no-eol) (esc)
368 searching for exact renames [ ] 0/1\r (no-eol) (esc)
343 \r (no-eol) (esc)
369 \r (no-eol) (esc)
344 adding ../sub1/sub2/folder/test.txt (glob)
370 adding ../sub1/sub2/folder/test.txt (glob)
345 removing ../sub1/sub2/test.txt (glob)
371 removing ../sub1/sub2/test.txt (glob)
346 adding ../sub1/foo (glob)
372 adding ../sub1/foo (glob)
347 adding bar/abc (glob)
373 adding bar/abc (glob)
348 $ cd ..
374 $ cd ..
349 $ hg status -S
375 $ hg status -S
350 A foo/bar/abc
376 A foo/bar/abc
351 A sub1/foo
377 A sub1/foo
352 R sub1/sub2/test.txt
378 R sub1/sub2/test.txt
353
379
354 Archive wdir() with subrepos
380 Archive wdir() with subrepos
355 $ hg rm main
381 $ hg rm main
356 \r (no-eol) (esc)
382 \r (no-eol) (esc)
357 deleting [===========================================>] 1/1\r (no-eol) (esc)
383 deleting [===========================================>] 1/1\r (no-eol) (esc)
358 \r (no-eol) (esc)
384 \r (no-eol) (esc)
359 $ hg archive -S -r 'wdir()' ../wdir
385 $ hg archive -S -r 'wdir()' ../wdir
360 \r (no-eol) (esc)
386 \r (no-eol) (esc)
361 archiving [ ] 0/3\r (no-eol) (esc)
387 archiving [ ] 0/3\r (no-eol) (esc)
362 archiving [=============> ] 1/3\r (no-eol) (esc)
388 archiving [=============> ] 1/3\r (no-eol) (esc)
363 archiving [===========================> ] 2/3\r (no-eol) (esc)
389 archiving [===========================> ] 2/3\r (no-eol) (esc)
364 archiving [==========================================>] 3/3\r (no-eol) (esc)
390 archiving [==========================================>] 3/3\r (no-eol) (esc)
365 \r (no-eol) (esc)
391 \r (no-eol) (esc)
366 \r (no-eol) (esc)
392 \r (no-eol) (esc)
367 archiving (sub1) [ ] 0/4\r (no-eol) (esc)
393 archiving (sub1) [ ] 0/4\r (no-eol) (esc)
368 archiving (sub1) [========> ] 1/4\r (no-eol) (esc)
394 archiving (sub1) [========> ] 1/4\r (no-eol) (esc)
369 archiving (sub1) [=================> ] 2/4\r (no-eol) (esc)
395 archiving (sub1) [=================> ] 2/4\r (no-eol) (esc)
370 archiving (sub1) [==========================> ] 3/4\r (no-eol) (esc)
396 archiving (sub1) [==========================> ] 3/4\r (no-eol) (esc)
371 archiving (sub1) [===================================>] 4/4\r (no-eol) (esc)
397 archiving (sub1) [===================================>] 4/4\r (no-eol) (esc)
372 \r (no-eol) (esc)
398 \r (no-eol) (esc)
373 \r (no-eol) (esc)
399 \r (no-eol) (esc)
374 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
400 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
375 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
401 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
376 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
402 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
377 \r (no-eol) (esc)
403 \r (no-eol) (esc)
378 $ diff -r . ../wdir | egrep -v '\.hg$|^Common subdirectories:'
404 $ diff -r . ../wdir | egrep -v '\.hg$|^Common subdirectories:'
379 Only in ../wdir: .hg_archival.txt
405 Only in ../wdir: .hg_archival.txt
380
406
381 $ find ../wdir -type f | sort
407 $ find ../wdir -type f | sort
382 ../wdir/.hg_archival.txt
408 ../wdir/.hg_archival.txt
383 ../wdir/.hgsub
409 ../wdir/.hgsub
384 ../wdir/.hgsubstate
410 ../wdir/.hgsubstate
385 ../wdir/foo/bar/abc
411 ../wdir/foo/bar/abc
386 ../wdir/sub1/.hgsub
412 ../wdir/sub1/.hgsub
387 ../wdir/sub1/.hgsubstate
413 ../wdir/sub1/.hgsubstate
388 ../wdir/sub1/foo
414 ../wdir/sub1/foo
389 ../wdir/sub1/sub1
415 ../wdir/sub1/sub1
390 ../wdir/sub1/sub2/folder/test.txt
416 ../wdir/sub1/sub2/folder/test.txt
391 ../wdir/sub1/sub2/sub2
417 ../wdir/sub1/sub2/sub2
392
418
393 $ cat ../wdir/.hg_archival.txt
419 $ cat ../wdir/.hg_archival.txt
394 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
420 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
395 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd+
421 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd+
396 branch: default
422 branch: default
397 latesttag: null
423 latesttag: null
398 latesttagdistance: 4
424 latesttagdistance: 4
399 changessincelatesttag: 4
425 changessincelatesttag: 4
400
426
401 Attempting to archive 'wdir()' with a missing file is handled gracefully
427 Attempting to archive 'wdir()' with a missing file is handled gracefully
402 $ rm sub1/sub1
428 $ rm sub1/sub1
403 $ rm -r ../wdir
429 $ rm -r ../wdir
404 $ hg archive -v -S -r 'wdir()' ../wdir
430 $ hg archive -v -S -r 'wdir()' ../wdir
405 \r (no-eol) (esc)
431 \r (no-eol) (esc)
406 archiving [ ] 0/3\r (no-eol) (esc)
432 archiving [ ] 0/3\r (no-eol) (esc)
407 archiving [=============> ] 1/3\r (no-eol) (esc)
433 archiving [=============> ] 1/3\r (no-eol) (esc)
408 archiving [===========================> ] 2/3\r (no-eol) (esc)
434 archiving [===========================> ] 2/3\r (no-eol) (esc)
409 archiving [==========================================>] 3/3\r (no-eol) (esc)
435 archiving [==========================================>] 3/3\r (no-eol) (esc)
410 \r (no-eol) (esc)
436 \r (no-eol) (esc)
411 \r (no-eol) (esc)
437 \r (no-eol) (esc)
412 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
438 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
413 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
439 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
414 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
440 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
415 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
441 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
416 \r (no-eol) (esc)
442 \r (no-eol) (esc)
417 \r (no-eol) (esc)
443 \r (no-eol) (esc)
418 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
444 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
419 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
445 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
420 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
446 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
421 \r (no-eol) (esc)
447 \r (no-eol) (esc)
422 $ find ../wdir -type f | sort
448 $ find ../wdir -type f | sort
423 ../wdir/.hg_archival.txt
449 ../wdir/.hg_archival.txt
424 ../wdir/.hgsub
450 ../wdir/.hgsub
425 ../wdir/.hgsubstate
451 ../wdir/.hgsubstate
426 ../wdir/foo/bar/abc
452 ../wdir/foo/bar/abc
427 ../wdir/sub1/.hgsub
453 ../wdir/sub1/.hgsub
428 ../wdir/sub1/.hgsubstate
454 ../wdir/sub1/.hgsubstate
429 ../wdir/sub1/foo
455 ../wdir/sub1/foo
430 ../wdir/sub1/sub2/folder/test.txt
456 ../wdir/sub1/sub2/folder/test.txt
431 ../wdir/sub1/sub2/sub2
457 ../wdir/sub1/sub2/sub2
432
458
433 Continue relative path printing + subrepos
459 Continue relative path printing + subrepos
434 $ hg update -Cq
460 $ hg update -Cq
435 $ rm -r ../wdir
461 $ rm -r ../wdir
436 $ hg archive -S -r 'wdir()' ../wdir
462 $ hg archive -S -r 'wdir()' ../wdir
437 \r (no-eol) (esc)
463 \r (no-eol) (esc)
438 archiving [ ] 0/3\r (no-eol) (esc)
464 archiving [ ] 0/3\r (no-eol) (esc)
439 archiving [=============> ] 1/3\r (no-eol) (esc)
465 archiving [=============> ] 1/3\r (no-eol) (esc)
440 archiving [===========================> ] 2/3\r (no-eol) (esc)
466 archiving [===========================> ] 2/3\r (no-eol) (esc)
441 archiving [==========================================>] 3/3\r (no-eol) (esc)
467 archiving [==========================================>] 3/3\r (no-eol) (esc)
442 \r (no-eol) (esc)
468 \r (no-eol) (esc)
443 \r (no-eol) (esc)
469 \r (no-eol) (esc)
444 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
470 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
445 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
471 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
446 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
472 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
447 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
473 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
448 \r (no-eol) (esc)
474 \r (no-eol) (esc)
449 \r (no-eol) (esc)
475 \r (no-eol) (esc)
450 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
476 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
451 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
477 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
452 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
478 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
453 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
479 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
454 \r (no-eol) (esc)
480 \r (no-eol) (esc)
455 $ cat ../wdir/.hg_archival.txt
481 $ cat ../wdir/.hg_archival.txt
456 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
482 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
457 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd
483 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd
458 branch: default
484 branch: default
459 latesttag: null
485 latesttag: null
460 latesttagdistance: 4
486 latesttagdistance: 4
461 changessincelatesttag: 4
487 changessincelatesttag: 4
462
488
463 $ touch sub1/sub2/folder/bar
489 $ touch sub1/sub2/folder/bar
464 $ hg addremove sub1/sub2
490 $ hg addremove sub1/sub2
465 adding sub1/sub2/folder/bar (glob)
491 adding sub1/sub2/folder/bar (glob)
466 $ hg status -S
492 $ hg status -S
467 A sub1/sub2/folder/bar
493 A sub1/sub2/folder/bar
468 ? foo/bar/abc
494 ? foo/bar/abc
469 ? sub1/foo
495 ? sub1/foo
470 $ hg update -Cq
496 $ hg update -Cq
471 $ hg addremove sub1
497 $ hg addremove sub1
472 adding sub1/sub2/folder/bar (glob)
498 adding sub1/sub2/folder/bar (glob)
473 adding sub1/foo (glob)
499 adding sub1/foo (glob)
474 $ hg update -Cq
500 $ hg update -Cq
475 $ rm sub1/sub2/folder/test.txt
501 $ rm sub1/sub2/folder/test.txt
476 $ rm sub1/sub2/test.txt
502 $ rm sub1/sub2/test.txt
477 $ hg ci -ASm "remove test.txt"
503 $ hg ci -ASm "remove test.txt"
478 adding sub1/sub2/folder/bar
504 adding sub1/sub2/folder/bar
479 removing sub1/sub2/folder/test.txt
505 removing sub1/sub2/folder/test.txt
480 removing sub1/sub2/test.txt
506 removing sub1/sub2/test.txt
481 adding sub1/foo
507 adding sub1/foo
482 adding foo/bar/abc
508 adding foo/bar/abc
483 committing subrepository sub1
509 committing subrepository sub1
484 committing subrepository sub1/sub2 (glob)
510 committing subrepository sub1/sub2 (glob)
485
511
486 $ hg forget sub1/sub2/sub2
512 $ hg forget sub1/sub2/sub2
487 $ echo x > sub1/sub2/x.txt
513 $ echo x > sub1/sub2/x.txt
488 $ hg add sub1/sub2/x.txt
514 $ hg add sub1/sub2/x.txt
489
515
490 Files sees uncommitted adds and removes in subrepos
516 Files sees uncommitted adds and removes in subrepos
491 $ hg files -S
517 $ hg files -S
492 .hgsub
518 .hgsub
493 .hgsubstate
519 .hgsubstate
494 foo/bar/abc (glob)
520 foo/bar/abc (glob)
495 main
521 main
496 sub1/.hgsub (glob)
522 sub1/.hgsub (glob)
497 sub1/.hgsubstate (glob)
523 sub1/.hgsubstate (glob)
498 sub1/foo (glob)
524 sub1/foo (glob)
499 sub1/sub1 (glob)
525 sub1/sub1 (glob)
500 sub1/sub2/folder/bar (glob)
526 sub1/sub2/folder/bar (glob)
501 sub1/sub2/x.txt (glob)
527 sub1/sub2/x.txt (glob)
502
528
503 $ hg files -S "set:eol('dos') or eol('unix') or size('<= 0')"
529 $ hg files -S "set:eol('dos') or eol('unix') or size('<= 0')"
504 .hgsub
530 .hgsub
505 .hgsubstate
531 .hgsubstate
506 foo/bar/abc (glob)
532 foo/bar/abc (glob)
507 main
533 main
508 sub1/.hgsub (glob)
534 sub1/.hgsub (glob)
509 sub1/.hgsubstate (glob)
535 sub1/.hgsubstate (glob)
510 sub1/foo (glob)
536 sub1/foo (glob)
511 sub1/sub1 (glob)
537 sub1/sub1 (glob)
512 sub1/sub2/folder/bar (glob)
538 sub1/sub2/folder/bar (glob)
513 sub1/sub2/x.txt (glob)
539 sub1/sub2/x.txt (glob)
514
540
515 $ hg files -r '.^' -S "set:eol('dos') or eol('unix')"
541 $ hg files -r '.^' -S "set:eol('dos') or eol('unix')"
516 .hgsub
542 .hgsub
517 .hgsubstate
543 .hgsubstate
518 main
544 main
519 sub1/.hgsub (glob)
545 sub1/.hgsub (glob)
520 sub1/.hgsubstate (glob)
546 sub1/.hgsubstate (glob)
521 sub1/sub1 (glob)
547 sub1/sub1 (glob)
522 sub1/sub2/folder/test.txt (glob)
548 sub1/sub2/folder/test.txt (glob)
523 sub1/sub2/sub2 (glob)
549 sub1/sub2/sub2 (glob)
524 sub1/sub2/test.txt (glob)
550 sub1/sub2/test.txt (glob)
525
551
526 $ hg files sub1
552 $ hg files sub1
527 sub1/.hgsub (glob)
553 sub1/.hgsub (glob)
528 sub1/.hgsubstate (glob)
554 sub1/.hgsubstate (glob)
529 sub1/foo (glob)
555 sub1/foo (glob)
530 sub1/sub1 (glob)
556 sub1/sub1 (glob)
531 sub1/sub2/folder/bar (glob)
557 sub1/sub2/folder/bar (glob)
532 sub1/sub2/x.txt (glob)
558 sub1/sub2/x.txt (glob)
533
559
534 $ hg files sub1/sub2
560 $ hg files sub1/sub2
535 sub1/sub2/folder/bar (glob)
561 sub1/sub2/folder/bar (glob)
536 sub1/sub2/x.txt (glob)
562 sub1/sub2/x.txt (glob)
537
563
538 $ hg files
564 $ hg files
539 .hgsub
565 .hgsub
540 .hgsubstate
566 .hgsubstate
541 foo/bar/abc (glob)
567 foo/bar/abc (glob)
542 main
568 main
543
569
544 $ hg files -S -r '.^' sub1/sub2/folder
570 $ hg files -S -r '.^' sub1/sub2/folder
545 sub1/sub2/folder/test.txt (glob)
571 sub1/sub2/folder/test.txt (glob)
546
572
547 $ hg files -S -r '.^' sub1/sub2/missing
573 $ hg files -S -r '.^' sub1/sub2/missing
548 sub1/sub2/missing: no such file in rev 78026e779ea6 (glob)
574 sub1/sub2/missing: no such file in rev 78026e779ea6 (glob)
549 [1]
575 [1]
550
576
551 $ hg files -r '.^' sub1/
577 $ hg files -r '.^' sub1/
552 sub1/.hgsub (glob)
578 sub1/.hgsub (glob)
553 sub1/.hgsubstate (glob)
579 sub1/.hgsubstate (glob)
554 sub1/sub1 (glob)
580 sub1/sub1 (glob)
555 sub1/sub2/folder/test.txt (glob)
581 sub1/sub2/folder/test.txt (glob)
556 sub1/sub2/sub2 (glob)
582 sub1/sub2/sub2 (glob)
557 sub1/sub2/test.txt (glob)
583 sub1/sub2/test.txt (glob)
558
584
559 $ hg files -r '.^' sub1/sub2
585 $ hg files -r '.^' sub1/sub2
560 sub1/sub2/folder/test.txt (glob)
586 sub1/sub2/folder/test.txt (glob)
561 sub1/sub2/sub2 (glob)
587 sub1/sub2/sub2 (glob)
562 sub1/sub2/test.txt (glob)
588 sub1/sub2/test.txt (glob)
563
589
564 $ hg rollback -q
590 $ hg rollback -q
565 $ hg up -Cq
591 $ hg up -Cq
566
592
567 $ hg --config extensions.largefiles=! archive -S ../archive_all
593 $ hg --config extensions.largefiles=! archive -S ../archive_all
568 \r (no-eol) (esc)
594 \r (no-eol) (esc)
569 archiving [ ] 0/3\r (no-eol) (esc)
595 archiving [ ] 0/3\r (no-eol) (esc)
570 archiving [=============> ] 1/3\r (no-eol) (esc)
596 archiving [=============> ] 1/3\r (no-eol) (esc)
571 archiving [===========================> ] 2/3\r (no-eol) (esc)
597 archiving [===========================> ] 2/3\r (no-eol) (esc)
572 archiving [==========================================>] 3/3\r (no-eol) (esc)
598 archiving [==========================================>] 3/3\r (no-eol) (esc)
573 \r (no-eol) (esc)
599 \r (no-eol) (esc)
574 \r (no-eol) (esc)
600 \r (no-eol) (esc)
575 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
601 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
576 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
602 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
577 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
603 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
578 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
604 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
579 \r (no-eol) (esc)
605 \r (no-eol) (esc)
580 \r (no-eol) (esc)
606 \r (no-eol) (esc)
581 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
607 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
582 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
608 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
583 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
609 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
584 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
610 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
585 \r (no-eol) (esc)
611 \r (no-eol) (esc)
586 $ find ../archive_all | sort
612 $ find ../archive_all | sort
587 ../archive_all
613 ../archive_all
588 ../archive_all/.hg_archival.txt
614 ../archive_all/.hg_archival.txt
589 ../archive_all/.hgsub
615 ../archive_all/.hgsub
590 ../archive_all/.hgsubstate
616 ../archive_all/.hgsubstate
591 ../archive_all/main
617 ../archive_all/main
592 ../archive_all/sub1
618 ../archive_all/sub1
593 ../archive_all/sub1/.hgsub
619 ../archive_all/sub1/.hgsub
594 ../archive_all/sub1/.hgsubstate
620 ../archive_all/sub1/.hgsubstate
595 ../archive_all/sub1/sub1
621 ../archive_all/sub1/sub1
596 ../archive_all/sub1/sub2
622 ../archive_all/sub1/sub2
597 ../archive_all/sub1/sub2/folder
623 ../archive_all/sub1/sub2/folder
598 ../archive_all/sub1/sub2/folder/test.txt
624 ../archive_all/sub1/sub2/folder/test.txt
599 ../archive_all/sub1/sub2/sub2
625 ../archive_all/sub1/sub2/sub2
600 ../archive_all/sub1/sub2/test.txt
626 ../archive_all/sub1/sub2/test.txt
601
627
602 Check that archive -X works in deep subrepos
628 Check that archive -X works in deep subrepos
603
629
604 $ hg --config extensions.largefiles=! archive -S -X '**test*' ../archive_exclude
630 $ hg --config extensions.largefiles=! archive -S -X '**test*' ../archive_exclude
605 \r (no-eol) (esc)
631 \r (no-eol) (esc)
606 archiving [ ] 0/3\r (no-eol) (esc)
632 archiving [ ] 0/3\r (no-eol) (esc)
607 archiving [=============> ] 1/3\r (no-eol) (esc)
633 archiving [=============> ] 1/3\r (no-eol) (esc)
608 archiving [===========================> ] 2/3\r (no-eol) (esc)
634 archiving [===========================> ] 2/3\r (no-eol) (esc)
609 archiving [==========================================>] 3/3\r (no-eol) (esc)
635 archiving [==========================================>] 3/3\r (no-eol) (esc)
610 \r (no-eol) (esc)
636 \r (no-eol) (esc)
611 \r (no-eol) (esc)
637 \r (no-eol) (esc)
612 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
638 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
613 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
639 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
614 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
640 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
615 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
641 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
616 \r (no-eol) (esc)
642 \r (no-eol) (esc)
617 \r (no-eol) (esc)
643 \r (no-eol) (esc)
618 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
644 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
619 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
645 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
620 \r (no-eol) (esc)
646 \r (no-eol) (esc)
621 $ find ../archive_exclude | sort
647 $ find ../archive_exclude | sort
622 ../archive_exclude
648 ../archive_exclude
623 ../archive_exclude/.hg_archival.txt
649 ../archive_exclude/.hg_archival.txt
624 ../archive_exclude/.hgsub
650 ../archive_exclude/.hgsub
625 ../archive_exclude/.hgsubstate
651 ../archive_exclude/.hgsubstate
626 ../archive_exclude/main
652 ../archive_exclude/main
627 ../archive_exclude/sub1
653 ../archive_exclude/sub1
628 ../archive_exclude/sub1/.hgsub
654 ../archive_exclude/sub1/.hgsub
629 ../archive_exclude/sub1/.hgsubstate
655 ../archive_exclude/sub1/.hgsubstate
630 ../archive_exclude/sub1/sub1
656 ../archive_exclude/sub1/sub1
631 ../archive_exclude/sub1/sub2
657 ../archive_exclude/sub1/sub2
632 ../archive_exclude/sub1/sub2/sub2
658 ../archive_exclude/sub1/sub2/sub2
633
659
634 $ hg --config extensions.largefiles=! archive -S -I '**test*' ../archive_include
660 $ hg --config extensions.largefiles=! archive -S -I '**test*' ../archive_include
635 \r (no-eol) (esc)
661 \r (no-eol) (esc)
636 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
662 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
637 \r (no-eol) (esc)
663 \r (no-eol) (esc)
638 \r (no-eol) (esc)
664 \r (no-eol) (esc)
639 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
665 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
640 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
666 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
641 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
667 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
642 \r (no-eol) (esc)
668 \r (no-eol) (esc)
643 $ find ../archive_include | sort
669 $ find ../archive_include | sort
644 ../archive_include
670 ../archive_include
645 ../archive_include/sub1
671 ../archive_include/sub1
646 ../archive_include/sub1/sub2
672 ../archive_include/sub1/sub2
647 ../archive_include/sub1/sub2/folder
673 ../archive_include/sub1/sub2/folder
648 ../archive_include/sub1/sub2/folder/test.txt
674 ../archive_include/sub1/sub2/folder/test.txt
649 ../archive_include/sub1/sub2/test.txt
675 ../archive_include/sub1/sub2/test.txt
650
676
651 Check that deep archive works with largefiles (which overrides hgsubrepo impl)
677 Check that deep archive works with largefiles (which overrides hgsubrepo impl)
652 This also tests the repo.ui regression in 43fb170a23bd, and that lf subrepo
678 This also tests the repo.ui regression in 43fb170a23bd, and that lf subrepo
653 subrepos are archived properly.
679 subrepos are archived properly.
654 Note that add --large through a subrepo currently adds the file as a normal file
680 Note that add --large through a subrepo currently adds the file as a normal file
655
681
656 $ echo "large" > sub1/sub2/large.bin
682 $ echo "large" > sub1/sub2/large.bin
657 $ hg --config extensions.largefiles= add --large -R sub1/sub2 sub1/sub2/large.bin
683 $ hg --config extensions.largefiles= add --large -R sub1/sub2 sub1/sub2/large.bin
658 $ echo "large" > large.bin
684 $ echo "large" > large.bin
659 $ hg --config extensions.largefiles= add --large large.bin
685 $ hg --config extensions.largefiles= add --large large.bin
660 $ hg --config extensions.largefiles= ci -S -m "add large files"
686 $ hg --config extensions.largefiles= ci -S -m "add large files"
661 committing subrepository sub1
687 committing subrepository sub1
662 committing subrepository sub1/sub2 (glob)
688 committing subrepository sub1/sub2 (glob)
663
689
664 $ hg --config extensions.largefiles= archive -S ../archive_lf
690 $ hg --config extensions.largefiles= archive -S ../archive_lf
665 $ find ../archive_lf | sort
691 $ find ../archive_lf | sort
666 ../archive_lf
692 ../archive_lf
667 ../archive_lf/.hg_archival.txt
693 ../archive_lf/.hg_archival.txt
668 ../archive_lf/.hgsub
694 ../archive_lf/.hgsub
669 ../archive_lf/.hgsubstate
695 ../archive_lf/.hgsubstate
670 ../archive_lf/large.bin
696 ../archive_lf/large.bin
671 ../archive_lf/main
697 ../archive_lf/main
672 ../archive_lf/sub1
698 ../archive_lf/sub1
673 ../archive_lf/sub1/.hgsub
699 ../archive_lf/sub1/.hgsub
674 ../archive_lf/sub1/.hgsubstate
700 ../archive_lf/sub1/.hgsubstate
675 ../archive_lf/sub1/sub1
701 ../archive_lf/sub1/sub1
676 ../archive_lf/sub1/sub2
702 ../archive_lf/sub1/sub2
677 ../archive_lf/sub1/sub2/folder
703 ../archive_lf/sub1/sub2/folder
678 ../archive_lf/sub1/sub2/folder/test.txt
704 ../archive_lf/sub1/sub2/folder/test.txt
679 ../archive_lf/sub1/sub2/large.bin
705 ../archive_lf/sub1/sub2/large.bin
680 ../archive_lf/sub1/sub2/sub2
706 ../archive_lf/sub1/sub2/sub2
681 ../archive_lf/sub1/sub2/test.txt
707 ../archive_lf/sub1/sub2/test.txt
682 $ rm -rf ../archive_lf
708 $ rm -rf ../archive_lf
683
709
684 Exclude large files from main and sub-sub repo
710 Exclude large files from main and sub-sub repo
685
711
686 $ hg --config extensions.largefiles= archive -S -X '**.bin' ../archive_lf
712 $ hg --config extensions.largefiles= archive -S -X '**.bin' ../archive_lf
687 $ find ../archive_lf | sort
713 $ find ../archive_lf | sort
688 ../archive_lf
714 ../archive_lf
689 ../archive_lf/.hg_archival.txt
715 ../archive_lf/.hg_archival.txt
690 ../archive_lf/.hgsub
716 ../archive_lf/.hgsub
691 ../archive_lf/.hgsubstate
717 ../archive_lf/.hgsubstate
692 ../archive_lf/main
718 ../archive_lf/main
693 ../archive_lf/sub1
719 ../archive_lf/sub1
694 ../archive_lf/sub1/.hgsub
720 ../archive_lf/sub1/.hgsub
695 ../archive_lf/sub1/.hgsubstate
721 ../archive_lf/sub1/.hgsubstate
696 ../archive_lf/sub1/sub1
722 ../archive_lf/sub1/sub1
697 ../archive_lf/sub1/sub2
723 ../archive_lf/sub1/sub2
698 ../archive_lf/sub1/sub2/folder
724 ../archive_lf/sub1/sub2/folder
699 ../archive_lf/sub1/sub2/folder/test.txt
725 ../archive_lf/sub1/sub2/folder/test.txt
700 ../archive_lf/sub1/sub2/sub2
726 ../archive_lf/sub1/sub2/sub2
701 ../archive_lf/sub1/sub2/test.txt
727 ../archive_lf/sub1/sub2/test.txt
702 $ rm -rf ../archive_lf
728 $ rm -rf ../archive_lf
703
729
704 Exclude normal files from main and sub-sub repo
730 Exclude normal files from main and sub-sub repo
705
731
706 $ hg --config extensions.largefiles= archive -S -X '**.txt' -p '.' ../archive_lf.tgz
732 $ hg --config extensions.largefiles= archive -S -X '**.txt' -p '.' ../archive_lf.tgz
707 $ tar -tzf ../archive_lf.tgz | sort
733 $ tar -tzf ../archive_lf.tgz | sort
708 .hgsub
734 .hgsub
709 .hgsubstate
735 .hgsubstate
710 large.bin
736 large.bin
711 main
737 main
712 sub1/.hgsub
738 sub1/.hgsub
713 sub1/.hgsubstate
739 sub1/.hgsubstate
714 sub1/sub1
740 sub1/sub1
715 sub1/sub2/large.bin
741 sub1/sub2/large.bin
716 sub1/sub2/sub2
742 sub1/sub2/sub2
717
743
718 Include normal files from within a largefiles subrepo
744 Include normal files from within a largefiles subrepo
719
745
720 $ hg --config extensions.largefiles= archive -S -I '**.txt' ../archive_lf
746 $ hg --config extensions.largefiles= archive -S -I '**.txt' ../archive_lf
721 $ find ../archive_lf | sort
747 $ find ../archive_lf | sort
722 ../archive_lf
748 ../archive_lf
723 ../archive_lf/.hg_archival.txt
749 ../archive_lf/.hg_archival.txt
724 ../archive_lf/sub1
750 ../archive_lf/sub1
725 ../archive_lf/sub1/sub2
751 ../archive_lf/sub1/sub2
726 ../archive_lf/sub1/sub2/folder
752 ../archive_lf/sub1/sub2/folder
727 ../archive_lf/sub1/sub2/folder/test.txt
753 ../archive_lf/sub1/sub2/folder/test.txt
728 ../archive_lf/sub1/sub2/test.txt
754 ../archive_lf/sub1/sub2/test.txt
729 $ rm -rf ../archive_lf
755 $ rm -rf ../archive_lf
730
756
731 Include large files from within a largefiles subrepo
757 Include large files from within a largefiles subrepo
732
758
733 $ hg --config extensions.largefiles= archive -S -I '**.bin' ../archive_lf
759 $ hg --config extensions.largefiles= archive -S -I '**.bin' ../archive_lf
734 $ find ../archive_lf | sort
760 $ find ../archive_lf | sort
735 ../archive_lf
761 ../archive_lf
736 ../archive_lf/large.bin
762 ../archive_lf/large.bin
737 ../archive_lf/sub1
763 ../archive_lf/sub1
738 ../archive_lf/sub1/sub2
764 ../archive_lf/sub1/sub2
739 ../archive_lf/sub1/sub2/large.bin
765 ../archive_lf/sub1/sub2/large.bin
740 $ rm -rf ../archive_lf
766 $ rm -rf ../archive_lf
741
767
742 Find an exact largefile match in a largefiles subrepo
768 Find an exact largefile match in a largefiles subrepo
743
769
744 $ hg --config extensions.largefiles= archive -S -I 'sub1/sub2/large.bin' ../archive_lf
770 $ hg --config extensions.largefiles= archive -S -I 'sub1/sub2/large.bin' ../archive_lf
745 $ find ../archive_lf | sort
771 $ find ../archive_lf | sort
746 ../archive_lf
772 ../archive_lf
747 ../archive_lf/sub1
773 ../archive_lf/sub1
748 ../archive_lf/sub1/sub2
774 ../archive_lf/sub1/sub2
749 ../archive_lf/sub1/sub2/large.bin
775 ../archive_lf/sub1/sub2/large.bin
750 $ rm -rf ../archive_lf
776 $ rm -rf ../archive_lf
751
777
752 The local repo enables largefiles if a largefiles repo is cloned
778 The local repo enables largefiles if a largefiles repo is cloned
753 $ hg showconfig extensions
779 $ hg showconfig extensions
754 abort: repository requires features unknown to this Mercurial: largefiles!
780 abort: repository requires features unknown to this Mercurial: largefiles!
755 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
781 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
756 [255]
782 [255]
757 $ hg --config extensions.largefiles= clone -qU . ../lfclone
783 $ hg --config extensions.largefiles= clone -qU . ../lfclone
758 $ cat ../lfclone/.hg/hgrc
784 $ cat ../lfclone/.hg/hgrc
759 # example repository config (see 'hg help config' for more info)
785 # example repository config (see 'hg help config' for more info)
760 [paths]
786 [paths]
761 default = $TESTTMP/cloned (glob)
787 default = $TESTTMP/cloned (glob)
762
788
763 # path aliases to other clones of this repo in URLs or filesystem paths
789 # path aliases to other clones of this repo in URLs or filesystem paths
764 # (see 'hg help config.paths' for more info)
790 # (see 'hg help config.paths' for more info)
765 #
791 #
766 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
792 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
767 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
793 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
768 # my-clone = /home/jdoe/jdoes-clone
794 # my-clone = /home/jdoe/jdoes-clone
769
795
770 [ui]
796 [ui]
771 # name and email (local to this repository, optional), e.g.
797 # name and email (local to this repository, optional), e.g.
772 # username = Jane Doe <jdoe@example.com>
798 # username = Jane Doe <jdoe@example.com>
773
799
774 [extensions]
800 [extensions]
775 largefiles=
801 largefiles=
776
802
777 Find an exact match to a standin (should archive nothing)
803 Find an exact match to a standin (should archive nothing)
778 $ hg --config extensions.largefiles= archive -S -I 'sub/sub2/.hglf/large.bin' ../archive_lf
804 $ hg --config extensions.largefiles= archive -S -I 'sub/sub2/.hglf/large.bin' ../archive_lf
779 $ find ../archive_lf 2> /dev/null | sort
805 $ find ../archive_lf 2> /dev/null | sort
780
806
781 $ cat >> $HGRCPATH <<EOF
807 $ cat >> $HGRCPATH <<EOF
782 > [extensions]
808 > [extensions]
783 > largefiles=
809 > largefiles=
784 > [largefiles]
810 > [largefiles]
785 > patterns=glob:**.dat
811 > patterns=glob:**.dat
786 > EOF
812 > EOF
787
813
788 Test forget through a deep subrepo with the largefiles extension, both a
814 Test forget through a deep subrepo with the largefiles extension, both a
789 largefile and a normal file. Then a largefile that hasn't been committed yet.
815 largefile and a normal file. Then a largefile that hasn't been committed yet.
790 $ touch sub1/sub2/untracked.txt
816 $ touch sub1/sub2/untracked.txt
791 $ touch sub1/sub2/large.dat
817 $ touch sub1/sub2/large.dat
792 $ hg forget sub1/sub2/large.bin sub1/sub2/test.txt sub1/sub2/untracked.txt
818 $ hg forget sub1/sub2/large.bin sub1/sub2/test.txt sub1/sub2/untracked.txt
793 not removing sub1/sub2/untracked.txt: file is already untracked (glob)
819 not removing sub1/sub2/untracked.txt: file is already untracked (glob)
794 [1]
820 [1]
795 $ hg add --large --dry-run -v sub1/sub2/untracked.txt
821 $ hg add --large --dry-run -v sub1/sub2/untracked.txt
796 adding sub1/sub2/untracked.txt as a largefile (glob)
822 adding sub1/sub2/untracked.txt as a largefile (glob)
797 $ hg add --large -v sub1/sub2/untracked.txt
823 $ hg add --large -v sub1/sub2/untracked.txt
798 adding sub1/sub2/untracked.txt as a largefile (glob)
824 adding sub1/sub2/untracked.txt as a largefile (glob)
799 $ hg add --normal -v sub1/sub2/large.dat
825 $ hg add --normal -v sub1/sub2/large.dat
800 adding sub1/sub2/large.dat (glob)
826 adding sub1/sub2/large.dat (glob)
801 $ hg forget -v sub1/sub2/untracked.txt
827 $ hg forget -v sub1/sub2/untracked.txt
802 removing sub1/sub2/untracked.txt (glob)
828 removing sub1/sub2/untracked.txt (glob)
803 $ hg status -S
829 $ hg status -S
804 A sub1/sub2/large.dat
830 A sub1/sub2/large.dat
805 R sub1/sub2/large.bin
831 R sub1/sub2/large.bin
806 R sub1/sub2/test.txt
832 R sub1/sub2/test.txt
807 ? foo/bar/abc
833 ? foo/bar/abc
808 ? sub1/sub2/untracked.txt
834 ? sub1/sub2/untracked.txt
809 ? sub1/sub2/x.txt
835 ? sub1/sub2/x.txt
810 $ hg add sub1/sub2
836 $ hg add sub1/sub2
811
837
812 $ hg archive -S -r 'wdir()' ../wdir2
838 $ hg archive -S -r 'wdir()' ../wdir2
813 $ diff -r . ../wdir2 | egrep -v '\.hg$|^Common subdirectories:'
839 $ diff -r . ../wdir2 | egrep -v '\.hg$|^Common subdirectories:'
814 Only in ../wdir2: .hg_archival.txt
840 Only in ../wdir2: .hg_archival.txt
815 Only in .: .hglf
841 Only in .: .hglf
816 Only in .: foo
842 Only in .: foo
817 Only in ./sub1/sub2: large.bin
843 Only in ./sub1/sub2: large.bin
818 Only in ./sub1/sub2: test.txt
844 Only in ./sub1/sub2: test.txt
819 Only in ./sub1/sub2: untracked.txt
845 Only in ./sub1/sub2: untracked.txt
820 Only in ./sub1/sub2: x.txt
846 Only in ./sub1/sub2: x.txt
821 $ find ../wdir2 -type f | sort
847 $ find ../wdir2 -type f | sort
822 ../wdir2/.hg_archival.txt
848 ../wdir2/.hg_archival.txt
823 ../wdir2/.hgsub
849 ../wdir2/.hgsub
824 ../wdir2/.hgsubstate
850 ../wdir2/.hgsubstate
825 ../wdir2/large.bin
851 ../wdir2/large.bin
826 ../wdir2/main
852 ../wdir2/main
827 ../wdir2/sub1/.hgsub
853 ../wdir2/sub1/.hgsub
828 ../wdir2/sub1/.hgsubstate
854 ../wdir2/sub1/.hgsubstate
829 ../wdir2/sub1/sub1
855 ../wdir2/sub1/sub1
830 ../wdir2/sub1/sub2/folder/test.txt
856 ../wdir2/sub1/sub2/folder/test.txt
831 ../wdir2/sub1/sub2/large.dat
857 ../wdir2/sub1/sub2/large.dat
832 ../wdir2/sub1/sub2/sub2
858 ../wdir2/sub1/sub2/sub2
833 $ hg status -S -mac -n | sort
859 $ hg status -S -mac -n | sort
834 .hgsub
860 .hgsub
835 .hgsubstate
861 .hgsubstate
836 large.bin
862 large.bin
837 main
863 main
838 sub1/.hgsub
864 sub1/.hgsub
839 sub1/.hgsubstate
865 sub1/.hgsubstate
840 sub1/sub1
866 sub1/sub1
841 sub1/sub2/folder/test.txt
867 sub1/sub2/folder/test.txt
842 sub1/sub2/large.dat
868 sub1/sub2/large.dat
843 sub1/sub2/sub2
869 sub1/sub2/sub2
844
870
845 $ hg ci -Sqm 'forget testing'
871 $ hg ci -Sqm 'forget testing'
846
872
847 Test 'wdir()' modified file archiving with largefiles
873 Test 'wdir()' modified file archiving with largefiles
848 $ echo 'mod' > main
874 $ echo 'mod' > main
849 $ echo 'mod' > large.bin
875 $ echo 'mod' > large.bin
850 $ echo 'mod' > sub1/sub2/large.dat
876 $ echo 'mod' > sub1/sub2/large.dat
851 $ hg archive -S -r 'wdir()' ../wdir3
877 $ hg archive -S -r 'wdir()' ../wdir3
852 $ diff -r . ../wdir3 | egrep -v '\.hg$|^Common subdirectories'
878 $ diff -r . ../wdir3 | egrep -v '\.hg$|^Common subdirectories'
853 Only in ../wdir3: .hg_archival.txt
879 Only in ../wdir3: .hg_archival.txt
854 Only in .: .hglf
880 Only in .: .hglf
855 Only in .: foo
881 Only in .: foo
856 Only in ./sub1/sub2: large.bin
882 Only in ./sub1/sub2: large.bin
857 Only in ./sub1/sub2: test.txt
883 Only in ./sub1/sub2: test.txt
858 Only in ./sub1/sub2: untracked.txt
884 Only in ./sub1/sub2: untracked.txt
859 Only in ./sub1/sub2: x.txt
885 Only in ./sub1/sub2: x.txt
860 $ find ../wdir3 -type f | sort
886 $ find ../wdir3 -type f | sort
861 ../wdir3/.hg_archival.txt
887 ../wdir3/.hg_archival.txt
862 ../wdir3/.hgsub
888 ../wdir3/.hgsub
863 ../wdir3/.hgsubstate
889 ../wdir3/.hgsubstate
864 ../wdir3/large.bin
890 ../wdir3/large.bin
865 ../wdir3/main
891 ../wdir3/main
866 ../wdir3/sub1/.hgsub
892 ../wdir3/sub1/.hgsub
867 ../wdir3/sub1/.hgsubstate
893 ../wdir3/sub1/.hgsubstate
868 ../wdir3/sub1/sub1
894 ../wdir3/sub1/sub1
869 ../wdir3/sub1/sub2/folder/test.txt
895 ../wdir3/sub1/sub2/folder/test.txt
870 ../wdir3/sub1/sub2/large.dat
896 ../wdir3/sub1/sub2/large.dat
871 ../wdir3/sub1/sub2/sub2
897 ../wdir3/sub1/sub2/sub2
872 $ hg up -Cq
898 $ hg up -Cq
873
899
874 Test issue4330: commit a directory where only normal files have changed
900 Test issue4330: commit a directory where only normal files have changed
875 $ touch foo/bar/large.dat
901 $ touch foo/bar/large.dat
876 $ hg add --large foo/bar/large.dat
902 $ hg add --large foo/bar/large.dat
877 $ hg ci -m 'add foo/bar/large.dat'
903 $ hg ci -m 'add foo/bar/large.dat'
878 $ touch a.txt
904 $ touch a.txt
879 $ touch a.dat
905 $ touch a.dat
880 $ hg add -v foo/bar/abc a.txt a.dat
906 $ hg add -v foo/bar/abc a.txt a.dat
881 adding a.dat as a largefile
907 adding a.dat as a largefile
882 adding a.txt
908 adding a.txt
883 adding foo/bar/abc (glob)
909 adding foo/bar/abc (glob)
884 $ hg ci -m 'dir commit with only normal file deltas' foo/bar
910 $ hg ci -m 'dir commit with only normal file deltas' foo/bar
885 $ hg status
911 $ hg status
886 A a.dat
912 A a.dat
887 A a.txt
913 A a.txt
888
914
889 Test a directory commit with a changed largefile and a changed normal file
915 Test a directory commit with a changed largefile and a changed normal file
890 $ echo changed > foo/bar/large.dat
916 $ echo changed > foo/bar/large.dat
891 $ echo changed > foo/bar/abc
917 $ echo changed > foo/bar/abc
892 $ hg ci -m 'dir commit with normal and lf file deltas' foo
918 $ hg ci -m 'dir commit with normal and lf file deltas' foo
893 $ hg status
919 $ hg status
894 A a.dat
920 A a.dat
895 A a.txt
921 A a.txt
896
922
897 $ hg ci -m "add a.*"
923 $ hg ci -m "add a.*"
898 $ hg mv a.dat b.dat
924 $ hg mv a.dat b.dat
899 $ hg mv foo/bar/abc foo/bar/def
925 $ hg mv foo/bar/abc foo/bar/def
900 $ hg status -C
926 $ hg status -C
901 A b.dat
927 A b.dat
902 a.dat
928 a.dat
903 A foo/bar/def
929 A foo/bar/def
904 foo/bar/abc
930 foo/bar/abc
905 R a.dat
931 R a.dat
906 R foo/bar/abc
932 R foo/bar/abc
907
933
908 $ hg ci -m "move large and normal"
934 $ hg ci -m "move large and normal"
909 $ hg status -C --rev '.^' --rev .
935 $ hg status -C --rev '.^' --rev .
910 A b.dat
936 A b.dat
911 a.dat
937 a.dat
912 A foo/bar/def
938 A foo/bar/def
913 foo/bar/abc
939 foo/bar/abc
914 R a.dat
940 R a.dat
915 R foo/bar/abc
941 R foo/bar/abc
916
942
917
943
918 $ echo foo > main
944 $ echo foo > main
919 $ hg ci -m "mod parent only"
945 $ hg ci -m "mod parent only"
920 $ hg init sub3
946 $ hg init sub3
921 $ echo "sub3 = sub3" >> .hgsub
947 $ echo "sub3 = sub3" >> .hgsub
922 $ echo xyz > sub3/a.txt
948 $ echo xyz > sub3/a.txt
923 $ hg add sub3/a.txt
949 $ hg add sub3/a.txt
924 $ hg ci -Sm "add sub3"
950 $ hg ci -Sm "add sub3"
925 committing subrepository sub3
951 committing subrepository sub3
926 $ cat .hgsub | grep -v sub3 > .hgsub1
952 $ cat .hgsub | grep -v sub3 > .hgsub1
927 $ mv .hgsub1 .hgsub
953 $ mv .hgsub1 .hgsub
928 $ hg ci -m "remove sub3"
954 $ hg ci -m "remove sub3"
929
955
930 $ hg log -r "subrepo()" --style compact
956 $ hg log -r "subrepo()" --style compact
931 0 7f491f53a367 1970-01-01 00:00 +0000 test
957 0 7f491f53a367 1970-01-01 00:00 +0000 test
932 main import
958 main import
933
959
934 1 ffe6649062fe 1970-01-01 00:00 +0000 test
960 1 ffe6649062fe 1970-01-01 00:00 +0000 test
935 deep nested modif should trigger a commit
961 deep nested modif should trigger a commit
936
962
937 2 9bb10eebee29 1970-01-01 00:00 +0000 test
963 2 9bb10eebee29 1970-01-01 00:00 +0000 test
938 add test.txt
964 add test.txt
939
965
940 3 7c64f035294f 1970-01-01 00:00 +0000 test
966 3 7c64f035294f 1970-01-01 00:00 +0000 test
941 add large files
967 add large files
942
968
943 4 f734a59e2e35 1970-01-01 00:00 +0000 test
969 4 f734a59e2e35 1970-01-01 00:00 +0000 test
944 forget testing
970 forget testing
945
971
946 11 9685a22af5db 1970-01-01 00:00 +0000 test
972 11 9685a22af5db 1970-01-01 00:00 +0000 test
947 add sub3
973 add sub3
948
974
949 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test
975 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test
950 remove sub3
976 remove sub3
951
977
952 $ hg log -r "subrepo('sub3')" --style compact
978 $ hg log -r "subrepo('sub3')" --style compact
953 11 9685a22af5db 1970-01-01 00:00 +0000 test
979 11 9685a22af5db 1970-01-01 00:00 +0000 test
954 add sub3
980 add sub3
955
981
956 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test
982 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test
957 remove sub3
983 remove sub3
958
984
959 $ hg log -r "subrepo('bogus')" --style compact
985 $ hg log -r "subrepo('bogus')" --style compact
960
986
961
987
962 Test .hgsubstate in the R state
988 Test .hgsubstate in the R state
963
989
964 $ hg rm .hgsub .hgsubstate
990 $ hg rm .hgsub .hgsubstate
965 \r (no-eol) (esc)
991 \r (no-eol) (esc)
966 deleting [=====================> ] 1/2\r (no-eol) (esc)
992 deleting [=====================> ] 1/2\r (no-eol) (esc)
967 deleting [===========================================>] 2/2\r (no-eol) (esc)
993 deleting [===========================================>] 2/2\r (no-eol) (esc)
968 \r (no-eol) (esc)
994 \r (no-eol) (esc)
969 $ hg ci -m 'trash subrepo tracking'
995 $ hg ci -m 'trash subrepo tracking'
970
996
971 $ hg log -r "subrepo('re:sub\d+')" --style compact
997 $ hg log -r "subrepo('re:sub\d+')" --style compact
972 0 7f491f53a367 1970-01-01 00:00 +0000 test
998 0 7f491f53a367 1970-01-01 00:00 +0000 test
973 main import
999 main import
974
1000
975 1 ffe6649062fe 1970-01-01 00:00 +0000 test
1001 1 ffe6649062fe 1970-01-01 00:00 +0000 test
976 deep nested modif should trigger a commit
1002 deep nested modif should trigger a commit
977
1003
978 2 9bb10eebee29 1970-01-01 00:00 +0000 test
1004 2 9bb10eebee29 1970-01-01 00:00 +0000 test
979 add test.txt
1005 add test.txt
980
1006
981 3 7c64f035294f 1970-01-01 00:00 +0000 test
1007 3 7c64f035294f 1970-01-01 00:00 +0000 test
982 add large files
1008 add large files
983
1009
984 4 f734a59e2e35 1970-01-01 00:00 +0000 test
1010 4 f734a59e2e35 1970-01-01 00:00 +0000 test
985 forget testing
1011 forget testing
986
1012
987 11 9685a22af5db 1970-01-01 00:00 +0000 test
1013 11 9685a22af5db 1970-01-01 00:00 +0000 test
988 add sub3
1014 add sub3
989
1015
990 12 2e0485b475b9 1970-01-01 00:00 +0000 test
1016 12 2e0485b475b9 1970-01-01 00:00 +0000 test
991 remove sub3
1017 remove sub3
992
1018
993 13[tip] a68b2c361653 1970-01-01 00:00 +0000 test
1019 13[tip] a68b2c361653 1970-01-01 00:00 +0000 test
994 trash subrepo tracking
1020 trash subrepo tracking
995
1021
996
1022
997 Restore the trashed subrepo tracking
1023 Restore the trashed subrepo tracking
998
1024
999 $ hg rollback -q
1025 $ hg rollback -q
1000 $ hg update -Cq .
1026 $ hg update -Cq .
1001
1027
1002 Interaction with extdiff, largefiles and subrepos
1028 Interaction with extdiff, largefiles and subrepos
1003
1029
1004 $ hg --config extensions.extdiff= pdiff -S
1030 $ hg --config extensions.extdiff= pdiff -S
1005
1031
1006 $ hg --config extensions.extdiff= pdiff -r '.^' -S
1032 $ hg --config extensions.extdiff= pdiff -r '.^' -S
1007 \r (no-eol) (esc)
1033 \r (no-eol) (esc)
1008 archiving [ ] 0/2\r (no-eol) (esc)
1034 archiving [ ] 0/2\r (no-eol) (esc)
1009 archiving [====================> ] 1/2\r (no-eol) (esc)
1035 archiving [====================> ] 1/2\r (no-eol) (esc)
1010 archiving [==========================================>] 2/2\r (no-eol) (esc)
1036 archiving [==========================================>] 2/2\r (no-eol) (esc)
1011 \r (no-eol) (esc)
1037 \r (no-eol) (esc)
1012 \r (no-eol) (esc)
1038 \r (no-eol) (esc)
1013 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
1039 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
1014 \r (no-eol) (esc)
1040 \r (no-eol) (esc)
1015 \r (no-eol) (esc)
1041 \r (no-eol) (esc)
1016 archiving (sub1/sub2) [ <=> ] 0\r (no-eol) (glob) (esc)
1042 archiving (sub1/sub2) [ <=> ] 0\r (no-eol) (glob) (esc)
1017 \r (no-eol) (esc)
1043 \r (no-eol) (esc)
1018 \r (no-eol) (esc)
1044 \r (no-eol) (esc)
1019 archiving (sub3) [ <=> ] 0\r (no-eol) (esc)
1045 archiving (sub3) [ <=> ] 0\r (no-eol) (esc)
1020 \r (no-eol) (esc)
1046 \r (no-eol) (esc)
1021 \r (no-eol) (esc)
1047 \r (no-eol) (esc)
1022 archiving [ ] 0/2\r (no-eol) (esc)
1048 archiving [ ] 0/2\r (no-eol) (esc)
1023 archiving [====================> ] 1/2\r (no-eol) (esc)
1049 archiving [====================> ] 1/2\r (no-eol) (esc)
1024 archiving [==========================================>] 2/2\r (no-eol) (esc)
1050 archiving [==========================================>] 2/2\r (no-eol) (esc)
1025 \r (no-eol) (esc)
1051 \r (no-eol) (esc)
1026 \r (no-eol) (esc)
1052 \r (no-eol) (esc)
1027 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
1053 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
1028 \r (no-eol) (esc)
1054 \r (no-eol) (esc)
1029 \r (no-eol) (esc)
1055 \r (no-eol) (esc)
1030 archiving (sub1/sub2) [ <=> ] 0\r (no-eol) (glob) (esc)
1056 archiving (sub1/sub2) [ <=> ] 0\r (no-eol) (glob) (esc)
1031 \r (no-eol) (esc)
1057 \r (no-eol) (esc)
1032 diff -Nru cloned.*/.hgsub cloned/.hgsub (glob)
1058 diff -Nru cloned.*/.hgsub cloned/.hgsub (glob)
1033 --- cloned.*/.hgsub * (glob)
1059 --- cloned.*/.hgsub * (glob)
1034 +++ cloned/.hgsub * (glob)
1060 +++ cloned/.hgsub * (glob)
1035 @@ -1,2 +1* @@ (glob)
1061 @@ -1,2 +1* @@ (glob)
1036 sub1 = ../sub1
1062 sub1 = ../sub1
1037 -sub3 = sub3
1063 -sub3 = sub3
1038 diff -Nru cloned.*/.hgsubstate cloned/.hgsubstate (glob)
1064 diff -Nru cloned.*/.hgsubstate cloned/.hgsubstate (glob)
1039 --- cloned.*/.hgsubstate * (glob)
1065 --- cloned.*/.hgsubstate * (glob)
1040 +++ cloned/.hgsubstate * (glob)
1066 +++ cloned/.hgsubstate * (glob)
1041 @@ -1,2 +1* @@ (glob)
1067 @@ -1,2 +1* @@ (glob)
1042 7a36fa02b66e61f27f3d4a822809f159479b8ab2 sub1
1068 7a36fa02b66e61f27f3d4a822809f159479b8ab2 sub1
1043 -b1a26de6f2a045a9f079323693614ee322f1ff7e sub3
1069 -b1a26de6f2a045a9f079323693614ee322f1ff7e sub3
1044 [1]
1070 [1]
1045
1071
1046 $ hg --config extensions.extdiff= pdiff -r 0 -r '.^' -S
1072 $ hg --config extensions.extdiff= pdiff -r 0 -r '.^' -S
1047 \r (no-eol) (esc)
1073 \r (no-eol) (esc)
1048 archiving [ ] 0/3\r (no-eol) (esc)
1074 archiving [ ] 0/3\r (no-eol) (esc)
1049 archiving [=============> ] 1/3\r (no-eol) (esc)
1075 archiving [=============> ] 1/3\r (no-eol) (esc)
1050 archiving [===========================> ] 2/3\r (no-eol) (esc)
1076 archiving [===========================> ] 2/3\r (no-eol) (esc)
1051 archiving [==========================================>] 3/3\r (no-eol) (esc)
1077 archiving [==========================================>] 3/3\r (no-eol) (esc)
1052 \r (no-eol) (esc)
1078 \r (no-eol) (esc)
1053 \r (no-eol) (esc)
1079 \r (no-eol) (esc)
1054 archiving (sub1) [ ] 0/1\r (no-eol) (esc)
1080 archiving (sub1) [ ] 0/1\r (no-eol) (esc)
1055 archiving (sub1) [===================================>] 1/1\r (no-eol) (esc)
1081 archiving (sub1) [===================================>] 1/1\r (no-eol) (esc)
1056 \r (no-eol) (esc)
1082 \r (no-eol) (esc)
1057 \r (no-eol) (esc)
1083 \r (no-eol) (esc)
1058 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
1084 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
1059 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
1085 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
1060 \r (no-eol) (esc)
1086 \r (no-eol) (esc)
1061 \r (no-eol) (esc)
1087 \r (no-eol) (esc)
1062 archiving [ ] 0/8\r (no-eol) (esc)
1088 archiving [ ] 0/8\r (no-eol) (esc)
1063 archiving [====> ] 1/8\r (no-eol) (esc)
1089 archiving [====> ] 1/8\r (no-eol) (esc)
1064 archiving [=========> ] 2/8\r (no-eol) (esc)
1090 archiving [=========> ] 2/8\r (no-eol) (esc)
1065 archiving [===============> ] 3/8\r (no-eol) (esc)
1091 archiving [===============> ] 3/8\r (no-eol) (esc)
1066 archiving [====================> ] 4/8\r (no-eol) (esc)
1092 archiving [====================> ] 4/8\r (no-eol) (esc)
1067 archiving [=========================> ] 5/8\r (no-eol) (esc)
1093 archiving [=========================> ] 5/8\r (no-eol) (esc)
1068 archiving [===============================> ] 6/8\r (no-eol) (esc)
1094 archiving [===============================> ] 6/8\r (no-eol) (esc)
1069 archiving [====================================> ] 7/8\r (no-eol) (esc)
1095 archiving [====================================> ] 7/8\r (no-eol) (esc)
1070 archiving [==========================================>] 8/8\r (no-eol) (esc)
1096 archiving [==========================================>] 8/8\r (no-eol) (esc)
1071 \r (no-eol) (esc)
1097 \r (no-eol) (esc)
1072 \r (no-eol) (esc)
1098 \r (no-eol) (esc)
1073 archiving (sub1) [ ] 0/1\r (no-eol) (esc)
1099 archiving (sub1) [ ] 0/1\r (no-eol) (esc)
1074 archiving (sub1) [===================================>] 1/1\r (no-eol) (esc)
1100 archiving (sub1) [===================================>] 1/1\r (no-eol) (esc)
1075 \r (no-eol) (esc)
1101 \r (no-eol) (esc)
1076 \r (no-eol) (esc)
1102 \r (no-eol) (esc)
1077 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
1103 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
1078 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
1104 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
1079 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
1105 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
1080 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
1106 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
1081 \r (no-eol) (esc)
1107 \r (no-eol) (esc)
1082 \r (no-eol) (esc)
1108 \r (no-eol) (esc)
1083 archiving (sub3) [ ] 0/1\r (no-eol) (esc)
1109 archiving (sub3) [ ] 0/1\r (no-eol) (esc)
1084 archiving (sub3) [===================================>] 1/1\r (no-eol) (esc)
1110 archiving (sub3) [===================================>] 1/1\r (no-eol) (esc)
1085 \r (no-eol) (esc)
1111 \r (no-eol) (esc)
1086 diff -Nru cloned.*/.hglf/b.dat cloned.*/.hglf/b.dat (glob)
1112 diff -Nru cloned.*/.hglf/b.dat cloned.*/.hglf/b.dat (glob)
1087 --- cloned.*/.hglf/b.dat * (glob)
1113 --- cloned.*/.hglf/b.dat * (glob)
1088 +++ cloned.*/.hglf/b.dat * (glob)
1114 +++ cloned.*/.hglf/b.dat * (glob)
1089 @@ -*,0 +1* @@ (glob)
1115 @@ -*,0 +1* @@ (glob)
1090 +da39a3ee5e6b4b0d3255bfef95601890afd80709
1116 +da39a3ee5e6b4b0d3255bfef95601890afd80709
1091 diff -Nru cloned.*/.hglf/foo/bar/large.dat cloned.*/.hglf/foo/bar/large.dat (glob)
1117 diff -Nru cloned.*/.hglf/foo/bar/large.dat cloned.*/.hglf/foo/bar/large.dat (glob)
1092 --- cloned.*/.hglf/foo/bar/large.dat * (glob)
1118 --- cloned.*/.hglf/foo/bar/large.dat * (glob)
1093 +++ cloned.*/.hglf/foo/bar/large.dat * (glob)
1119 +++ cloned.*/.hglf/foo/bar/large.dat * (glob)
1094 @@ -*,0 +1* @@ (glob)
1120 @@ -*,0 +1* @@ (glob)
1095 +2f6933b5ee0f5fdd823d9717d8729f3c2523811b
1121 +2f6933b5ee0f5fdd823d9717d8729f3c2523811b
1096 diff -Nru cloned.*/.hglf/large.bin cloned.*/.hglf/large.bin (glob)
1122 diff -Nru cloned.*/.hglf/large.bin cloned.*/.hglf/large.bin (glob)
1097 --- cloned.*/.hglf/large.bin * (glob)
1123 --- cloned.*/.hglf/large.bin * (glob)
1098 +++ cloned.*/.hglf/large.bin * (glob)
1124 +++ cloned.*/.hglf/large.bin * (glob)
1099 @@ -*,0 +1* @@ (glob)
1125 @@ -*,0 +1* @@ (glob)
1100 +7f7097b041ccf68cc5561e9600da4655d21c6d18
1126 +7f7097b041ccf68cc5561e9600da4655d21c6d18
1101 diff -Nru cloned.*/.hgsub cloned.*/.hgsub (glob)
1127 diff -Nru cloned.*/.hgsub cloned.*/.hgsub (glob)
1102 --- cloned.*/.hgsub * (glob)
1128 --- cloned.*/.hgsub * (glob)
1103 +++ cloned.*/.hgsub * (glob)
1129 +++ cloned.*/.hgsub * (glob)
1104 @@ -1* +1,2 @@ (glob)
1130 @@ -1* +1,2 @@ (glob)
1105 sub1 = ../sub1
1131 sub1 = ../sub1
1106 +sub3 = sub3
1132 +sub3 = sub3
1107 diff -Nru cloned.*/.hgsubstate cloned.*/.hgsubstate (glob)
1133 diff -Nru cloned.*/.hgsubstate cloned.*/.hgsubstate (glob)
1108 --- cloned.*/.hgsubstate * (glob)
1134 --- cloned.*/.hgsubstate * (glob)
1109 +++ cloned.*/.hgsubstate * (glob)
1135 +++ cloned.*/.hgsubstate * (glob)
1110 @@ -1* +1,2 @@ (glob)
1136 @@ -1* +1,2 @@ (glob)
1111 -fc3b4ce2696f7741438c79207583768f2ce6b0dd sub1
1137 -fc3b4ce2696f7741438c79207583768f2ce6b0dd sub1
1112 +7a36fa02b66e61f27f3d4a822809f159479b8ab2 sub1
1138 +7a36fa02b66e61f27f3d4a822809f159479b8ab2 sub1
1113 +b1a26de6f2a045a9f079323693614ee322f1ff7e sub3
1139 +b1a26de6f2a045a9f079323693614ee322f1ff7e sub3
1114 diff -Nru cloned.*/foo/bar/def cloned.*/foo/bar/def (glob)
1140 diff -Nru cloned.*/foo/bar/def cloned.*/foo/bar/def (glob)
1115 --- cloned.*/foo/bar/def * (glob)
1141 --- cloned.*/foo/bar/def * (glob)
1116 +++ cloned.*/foo/bar/def * (glob)
1142 +++ cloned.*/foo/bar/def * (glob)
1117 @@ -*,0 +1* @@ (glob)
1143 @@ -*,0 +1* @@ (glob)
1118 +changed
1144 +changed
1119 diff -Nru cloned.*/main cloned.*/main (glob)
1145 diff -Nru cloned.*/main cloned.*/main (glob)
1120 --- cloned.*/main * (glob)
1146 --- cloned.*/main * (glob)
1121 +++ cloned.*/main * (glob)
1147 +++ cloned.*/main * (glob)
1122 @@ -1* +1* @@ (glob)
1148 @@ -1* +1* @@ (glob)
1123 -main
1149 -main
1124 +foo
1150 +foo
1125 diff -Nru cloned.*/sub1/.hgsubstate cloned.*/sub1/.hgsubstate (glob)
1151 diff -Nru cloned.*/sub1/.hgsubstate cloned.*/sub1/.hgsubstate (glob)
1126 --- cloned.*/sub1/.hgsubstate * (glob)
1152 --- cloned.*/sub1/.hgsubstate * (glob)
1127 +++ cloned.*/sub1/.hgsubstate * (glob)
1153 +++ cloned.*/sub1/.hgsubstate * (glob)
1128 @@ -1* +1* @@ (glob)
1154 @@ -1* +1* @@ (glob)
1129 -c57a0840e3badd667ef3c3ef65471609acb2ba3c sub2
1155 -c57a0840e3badd667ef3c3ef65471609acb2ba3c sub2
1130 +c77908c81ccea3794a896c79e98b0e004aee2e9e sub2
1156 +c77908c81ccea3794a896c79e98b0e004aee2e9e sub2
1131 diff -Nru cloned.*/sub1/sub2/folder/test.txt cloned.*/sub1/sub2/folder/test.txt (glob)
1157 diff -Nru cloned.*/sub1/sub2/folder/test.txt cloned.*/sub1/sub2/folder/test.txt (glob)
1132 --- cloned.*/sub1/sub2/folder/test.txt * (glob)
1158 --- cloned.*/sub1/sub2/folder/test.txt * (glob)
1133 +++ cloned.*/sub1/sub2/folder/test.txt * (glob)
1159 +++ cloned.*/sub1/sub2/folder/test.txt * (glob)
1134 @@ -*,0 +1* @@ (glob)
1160 @@ -*,0 +1* @@ (glob)
1135 +subfolder
1161 +subfolder
1136 diff -Nru cloned.*/sub1/sub2/sub2 cloned.*/sub1/sub2/sub2 (glob)
1162 diff -Nru cloned.*/sub1/sub2/sub2 cloned.*/sub1/sub2/sub2 (glob)
1137 --- cloned.*/sub1/sub2/sub2 * (glob)
1163 --- cloned.*/sub1/sub2/sub2 * (glob)
1138 +++ cloned.*/sub1/sub2/sub2 * (glob)
1164 +++ cloned.*/sub1/sub2/sub2 * (glob)
1139 @@ -1* +1* @@ (glob)
1165 @@ -1* +1* @@ (glob)
1140 -sub2
1166 -sub2
1141 +modified
1167 +modified
1142 diff -Nru cloned.*/sub3/a.txt cloned.*/sub3/a.txt (glob)
1168 diff -Nru cloned.*/sub3/a.txt cloned.*/sub3/a.txt (glob)
1143 --- cloned.*/sub3/a.txt * (glob)
1169 --- cloned.*/sub3/a.txt * (glob)
1144 +++ cloned.*/sub3/a.txt * (glob)
1170 +++ cloned.*/sub3/a.txt * (glob)
1145 @@ -*,0 +1* @@ (glob)
1171 @@ -*,0 +1* @@ (glob)
1146 +xyz
1172 +xyz
1147 [1]
1173 [1]
1148
1174
1149 $ echo mod > sub1/sub2/sub2
1175 $ echo mod > sub1/sub2/sub2
1150 $ hg --config extensions.extdiff= pdiff -S
1176 $ hg --config extensions.extdiff= pdiff -S
1151 \r (no-eol) (esc)
1177 \r (no-eol) (esc)
1152 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
1178 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
1153 \r (no-eol) (esc)
1179 \r (no-eol) (esc)
1154 \r (no-eol) (esc)
1180 \r (no-eol) (esc)
1155 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
1181 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
1156 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
1182 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
1157 \r (no-eol) (esc)
1183 \r (no-eol) (esc)
1158 --- */cloned.*/sub1/sub2/sub2 * (glob)
1184 --- */cloned.*/sub1/sub2/sub2 * (glob)
1159 +++ */cloned/sub1/sub2/sub2 * (glob)
1185 +++ */cloned/sub1/sub2/sub2 * (glob)
1160 @@ -1* +1* @@ (glob)
1186 @@ -1* +1* @@ (glob)
1161 -modified
1187 -modified
1162 +mod
1188 +mod
1163 [1]
1189 [1]
1164
1190
1165 $ cd ..
1191 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now