##// END OF EJS Templates
merge with stable
Martin von Zweigbergk -
r31119:13bbcd56 merge default
parent child Browse files
Show More
@@ -1,152 +1,153 b''
1 # record.py
1 # record.py
2 #
2 #
3 # Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
3 # Copyright 2007 Bryan O'Sullivan <bos@serpentine.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 '''commands to interactively select changes for commit/qrefresh (DEPRECATED)
8 '''commands to interactively select changes for commit/qrefresh (DEPRECATED)
9
9
10 The feature provided by this extension has been moved into core Mercurial as
10 The feature provided by this extension has been moved into core Mercurial as
11 :hg:`commit --interactive`.'''
11 :hg:`commit --interactive`.'''
12
12
13 from __future__ import absolute_import
13 from __future__ import absolute_import
14
14
15 from mercurial.i18n import _
15 from mercurial.i18n import _
16 from mercurial import (
16 from mercurial import (
17 cmdutil,
17 cmdutil,
18 commands,
18 commands,
19 error,
19 error,
20 extensions,
20 extensions,
21 )
21 )
22
22
23 cmdtable = {}
23 cmdtable = {}
24 command = cmdutil.command(cmdtable)
24 command = cmdutil.command(cmdtable)
25 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
25 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
26 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
26 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
27 # be specifying the version(s) of Mercurial they are tested with, or
27 # be specifying the version(s) of Mercurial they are tested with, or
28 # leave the attribute unspecified.
28 # leave the attribute unspecified.
29 testedwith = 'ships-with-hg-core'
29 testedwith = 'ships-with-hg-core'
30
30
31
31
32 @command("record",
32 @command("record",
33 # same options as commit + white space diff options
33 # same options as commit + white space diff options
34 [c for c in commands.table['^commit|ci'][1][:]
34 [c for c in commands.table['^commit|ci'][1][:]
35 if c[1] != "interactive"] + commands.diffwsopts,
35 if c[1] != "interactive"] + commands.diffwsopts,
36 _('hg record [OPTION]... [FILE]...'))
36 _('hg record [OPTION]... [FILE]...'))
37 def record(ui, repo, *pats, **opts):
37 def record(ui, repo, *pats, **opts):
38 '''interactively select changes to commit
38 '''interactively select changes to commit
39
39
40 If a list of files is omitted, all changes reported by :hg:`status`
40 If a list of files is omitted, all changes reported by :hg:`status`
41 will be candidates for recording.
41 will be candidates for recording.
42
42
43 See :hg:`help dates` for a list of formats valid for -d/--date.
43 See :hg:`help dates` for a list of formats valid for -d/--date.
44
44
45 You will be prompted for whether to record changes to each
45 If using the text interface (see :hg:`help config`),
46 you will be prompted for whether to record changes to each
46 modified file, and for files with multiple changes, for each
47 modified file, and for files with multiple changes, for each
47 change to use. For each query, the following responses are
48 change to use. For each query, the following responses are
48 possible::
49 possible::
49
50
50 y - record this change
51 y - record this change
51 n - skip this change
52 n - skip this change
52 e - edit this change manually
53 e - edit this change manually
53
54
54 s - skip remaining changes to this file
55 s - skip remaining changes to this file
55 f - record remaining changes to this file
56 f - record remaining changes to this file
56
57
57 d - done, skip remaining changes and files
58 d - done, skip remaining changes and files
58 a - record all changes to all remaining files
59 a - record all changes to all remaining files
59 q - quit, recording no changes
60 q - quit, recording no changes
60
61
61 ? - display help
62 ? - display help
62
63
63 This command is not available when committing a merge.'''
64 This command is not available when committing a merge.'''
64
65
65 if not ui.interactive():
66 if not ui.interactive():
66 raise error.Abort(_('running non-interactively, use %s instead') %
67 raise error.Abort(_('running non-interactively, use %s instead') %
67 'commit')
68 'commit')
68
69
69 opts["interactive"] = True
70 opts["interactive"] = True
70 backup = ui.backupconfig('experimental', 'crecord')
71 backup = ui.backupconfig('experimental', 'crecord')
71 try:
72 try:
72 ui.setconfig('experimental', 'crecord', False, 'record')
73 ui.setconfig('experimental', 'crecord', False, 'record')
73 return commands.commit(ui, repo, *pats, **opts)
74 return commands.commit(ui, repo, *pats, **opts)
74 finally:
75 finally:
75 ui.restoreconfig(backup)
76 ui.restoreconfig(backup)
76
77
77 def qrefresh(origfn, ui, repo, *pats, **opts):
78 def qrefresh(origfn, ui, repo, *pats, **opts):
78 if not opts['interactive']:
79 if not opts['interactive']:
79 return origfn(ui, repo, *pats, **opts)
80 return origfn(ui, repo, *pats, **opts)
80
81
81 mq = extensions.find('mq')
82 mq = extensions.find('mq')
82
83
83 def committomq(ui, repo, *pats, **opts):
84 def committomq(ui, repo, *pats, **opts):
84 # At this point the working copy contains only changes that
85 # At this point the working copy contains only changes that
85 # were accepted. All other changes were reverted.
86 # were accepted. All other changes were reverted.
86 # We can't pass *pats here since qrefresh will undo all other
87 # We can't pass *pats here since qrefresh will undo all other
87 # changed files in the patch that aren't in pats.
88 # changed files in the patch that aren't in pats.
88 mq.refresh(ui, repo, **opts)
89 mq.refresh(ui, repo, **opts)
89
90
90 # backup all changed files
91 # backup all changed files
91 cmdutil.dorecord(ui, repo, committomq, None, True,
92 cmdutil.dorecord(ui, repo, committomq, None, True,
92 cmdutil.recordfilter, *pats, **opts)
93 cmdutil.recordfilter, *pats, **opts)
93
94
94 # This command registration is replaced during uisetup().
95 # This command registration is replaced during uisetup().
95 @command('qrecord',
96 @command('qrecord',
96 [],
97 [],
97 _('hg qrecord [OPTION]... PATCH [FILE]...'),
98 _('hg qrecord [OPTION]... PATCH [FILE]...'),
98 inferrepo=True)
99 inferrepo=True)
99 def qrecord(ui, repo, patch, *pats, **opts):
100 def qrecord(ui, repo, patch, *pats, **opts):
100 '''interactively record a new patch
101 '''interactively record a new patch
101
102
102 See :hg:`help qnew` & :hg:`help record` for more information and
103 See :hg:`help qnew` & :hg:`help record` for more information and
103 usage.
104 usage.
104 '''
105 '''
105 return _qrecord('qnew', ui, repo, patch, *pats, **opts)
106 return _qrecord('qnew', ui, repo, patch, *pats, **opts)
106
107
107 def _qrecord(cmdsuggest, ui, repo, patch, *pats, **opts):
108 def _qrecord(cmdsuggest, ui, repo, patch, *pats, **opts):
108 try:
109 try:
109 mq = extensions.find('mq')
110 mq = extensions.find('mq')
110 except KeyError:
111 except KeyError:
111 raise error.Abort(_("'mq' extension not loaded"))
112 raise error.Abort(_("'mq' extension not loaded"))
112
113
113 repo.mq.checkpatchname(patch)
114 repo.mq.checkpatchname(patch)
114
115
115 def committomq(ui, repo, *pats, **opts):
116 def committomq(ui, repo, *pats, **opts):
116 opts['checkname'] = False
117 opts['checkname'] = False
117 mq.new(ui, repo, patch, *pats, **opts)
118 mq.new(ui, repo, patch, *pats, **opts)
118
119
119 backup = ui.backupconfig('experimental', 'crecord')
120 backup = ui.backupconfig('experimental', 'crecord')
120 try:
121 try:
121 ui.setconfig('experimental', 'crecord', False, 'record')
122 ui.setconfig('experimental', 'crecord', False, 'record')
122 cmdutil.dorecord(ui, repo, committomq, cmdsuggest, False,
123 cmdutil.dorecord(ui, repo, committomq, cmdsuggest, False,
123 cmdutil.recordfilter, *pats, **opts)
124 cmdutil.recordfilter, *pats, **opts)
124 finally:
125 finally:
125 ui.restoreconfig(backup)
126 ui.restoreconfig(backup)
126
127
127 def qnew(origfn, ui, repo, patch, *args, **opts):
128 def qnew(origfn, ui, repo, patch, *args, **opts):
128 if opts['interactive']:
129 if opts['interactive']:
129 return _qrecord(None, ui, repo, patch, *args, **opts)
130 return _qrecord(None, ui, repo, patch, *args, **opts)
130 return origfn(ui, repo, patch, *args, **opts)
131 return origfn(ui, repo, patch, *args, **opts)
131
132
132
133
133 def uisetup(ui):
134 def uisetup(ui):
134 try:
135 try:
135 mq = extensions.find('mq')
136 mq = extensions.find('mq')
136 except KeyError:
137 except KeyError:
137 return
138 return
138
139
139 cmdtable["qrecord"] = \
140 cmdtable["qrecord"] = \
140 (qrecord,
141 (qrecord,
141 # same options as qnew, but copy them so we don't get
142 # same options as qnew, but copy them so we don't get
142 # -i/--interactive for qrecord and add white space diff options
143 # -i/--interactive for qrecord and add white space diff options
143 mq.cmdtable['^qnew'][1][:] + commands.diffwsopts,
144 mq.cmdtable['^qnew'][1][:] + commands.diffwsopts,
144 _('hg qrecord [OPTION]... PATCH [FILE]...'))
145 _('hg qrecord [OPTION]... PATCH [FILE]...'))
145
146
146 _wrapcmd('qnew', mq.cmdtable, qnew, _("interactively record a new patch"))
147 _wrapcmd('qnew', mq.cmdtable, qnew, _("interactively record a new patch"))
147 _wrapcmd('qrefresh', mq.cmdtable, qrefresh,
148 _wrapcmd('qrefresh', mq.cmdtable, qrefresh,
148 _("interactively select changes to refresh"))
149 _("interactively select changes to refresh"))
149
150
150 def _wrapcmd(cmd, table, wrapfn, msg):
151 def _wrapcmd(cmd, table, wrapfn, msg):
151 entry = extensions.wrapcommand(table, cmd, wrapfn)
152 entry = extensions.wrapcommand(table, cmd, wrapfn)
152 entry[1].append(('i', 'interactive', None, msg))
153 entry[1].append(('i', 'interactive', None, msg))
@@ -1,1664 +1,1664 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 atexit
10 import atexit
11 import collections
11 import collections
12 import contextlib
12 import contextlib
13 import errno
13 import errno
14 import getpass
14 import getpass
15 import inspect
15 import inspect
16 import os
16 import os
17 import re
17 import re
18 import signal
18 import signal
19 import socket
19 import socket
20 import subprocess
20 import subprocess
21 import sys
21 import sys
22 import tempfile
22 import tempfile
23 import traceback
23 import traceback
24
24
25 from .i18n import _
25 from .i18n import _
26 from .node import hex
26 from .node import hex
27
27
28 from . import (
28 from . import (
29 color,
29 color,
30 config,
30 config,
31 encoding,
31 encoding,
32 error,
32 error,
33 formatter,
33 formatter,
34 progress,
34 progress,
35 pycompat,
35 pycompat,
36 scmutil,
36 scmutil,
37 util,
37 util,
38 )
38 )
39
39
40 urlreq = util.urlreq
40 urlreq = util.urlreq
41
41
42 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
42 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
43 if pycompat.ispy3:
43 if pycompat.ispy3:
44 _bytes = [bytes([c]) for c in range(256)]
44 _bytes = [bytes([c]) for c in range(256)]
45 _notalnum = [s for s in _bytes if not s.isalnum()]
45 _notalnum = [s for s in _bytes if not s.isalnum()]
46 else:
46 else:
47 _notalnum = [c for c in map(chr, range(256)) if not c.isalnum()]
47 _notalnum = [c for c in map(chr, range(256)) if not c.isalnum()]
48 _keepalnum = ''.join(_notalnum)
48 _keepalnum = ''.join(_notalnum)
49
49
50 samplehgrcs = {
50 samplehgrcs = {
51 'user':
51 'user':
52 """# example user config (see 'hg help config' for more info)
52 """# example user config (see 'hg help config' for more info)
53 [ui]
53 [ui]
54 # name and email, e.g.
54 # name and email, e.g.
55 # username = Jane Doe <jdoe@example.com>
55 # username = Jane Doe <jdoe@example.com>
56 username =
56 username =
57
57
58 [extensions]
58 [extensions]
59 # uncomment these lines to enable some popular extensions
59 # uncomment these lines to enable some popular extensions
60 # (see 'hg help extensions' for more info)
60 # (see 'hg help extensions' for more info)
61 #
61 #
62 # pager =
62 # pager =
63 # color =""",
63 # color =""",
64
64
65 'cloned':
65 'cloned':
66 """# example repository config (see 'hg help config' for more info)
66 """# example repository config (see 'hg help config' for more info)
67 [paths]
67 [paths]
68 default = %s
68 default = %s
69
69
70 # path aliases to other clones of this repo in URLs or filesystem paths
70 # path aliases to other clones of this repo in URLs or filesystem paths
71 # (see 'hg help config.paths' for more info)
71 # (see 'hg help config.paths' for more info)
72 #
72 #
73 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
73 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
74 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
74 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
75 # my-clone = /home/jdoe/jdoes-clone
75 # my-clone = /home/jdoe/jdoes-clone
76
76
77 [ui]
77 [ui]
78 # name and email (local to this repository, optional), e.g.
78 # name and email (local to this repository, optional), e.g.
79 # username = Jane Doe <jdoe@example.com>
79 # username = Jane Doe <jdoe@example.com>
80 """,
80 """,
81
81
82 'local':
82 'local':
83 """# example repository config (see 'hg help config' for more info)
83 """# example repository config (see 'hg help config' for more info)
84 [paths]
84 [paths]
85 # path aliases to other clones of this repo in URLs or filesystem paths
85 # path aliases to other clones of this repo in URLs or filesystem paths
86 # (see 'hg help config.paths' for more info)
86 # (see 'hg help config.paths' for more info)
87 #
87 #
88 # default = http://example.com/hg/example-repo
88 # default = http://example.com/hg/example-repo
89 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
89 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
90 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
90 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
91 # my-clone = /home/jdoe/jdoes-clone
91 # my-clone = /home/jdoe/jdoes-clone
92
92
93 [ui]
93 [ui]
94 # name and email (local to this repository, optional), e.g.
94 # name and email (local to this repository, optional), e.g.
95 # username = Jane Doe <jdoe@example.com>
95 # username = Jane Doe <jdoe@example.com>
96 """,
96 """,
97
97
98 'global':
98 'global':
99 """# example system-wide hg config (see 'hg help config' for more info)
99 """# example system-wide hg config (see 'hg help config' for more info)
100
100
101 [extensions]
101 [extensions]
102 # uncomment these lines to enable some popular extensions
102 # uncomment these lines to enable some popular extensions
103 # (see 'hg help extensions' for more info)
103 # (see 'hg help extensions' for more info)
104 #
104 #
105 # blackbox =
105 # blackbox =
106 # color =
106 # color =
107 # pager =""",
107 # pager =""",
108 }
108 }
109
109
110
110
111 class httppasswordmgrdbproxy(object):
111 class httppasswordmgrdbproxy(object):
112 """Delays loading urllib2 until it's needed."""
112 """Delays loading urllib2 until it's needed."""
113 def __init__(self):
113 def __init__(self):
114 self._mgr = None
114 self._mgr = None
115
115
116 def _get_mgr(self):
116 def _get_mgr(self):
117 if self._mgr is None:
117 if self._mgr is None:
118 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
118 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
119 return self._mgr
119 return self._mgr
120
120
121 def add_password(self, *args, **kwargs):
121 def add_password(self, *args, **kwargs):
122 return self._get_mgr().add_password(*args, **kwargs)
122 return self._get_mgr().add_password(*args, **kwargs)
123
123
124 def find_user_password(self, *args, **kwargs):
124 def find_user_password(self, *args, **kwargs):
125 return self._get_mgr().find_user_password(*args, **kwargs)
125 return self._get_mgr().find_user_password(*args, **kwargs)
126
126
127 def _catchterm(*args):
127 def _catchterm(*args):
128 raise error.SignalInterrupt
128 raise error.SignalInterrupt
129
129
130 class ui(object):
130 class ui(object):
131 def __init__(self, src=None):
131 def __init__(self, src=None):
132 """Create a fresh new ui object if no src given
132 """Create a fresh new ui object if no src given
133
133
134 Use uimod.ui.load() to create a ui which knows global and user configs.
134 Use uimod.ui.load() to create a ui which knows global and user configs.
135 In most cases, you should use ui.copy() to create a copy of an existing
135 In most cases, you should use ui.copy() to create a copy of an existing
136 ui object.
136 ui object.
137 """
137 """
138 # _buffers: used for temporary capture of output
138 # _buffers: used for temporary capture of output
139 self._buffers = []
139 self._buffers = []
140 # 3-tuple describing how each buffer in the stack behaves.
140 # 3-tuple describing how each buffer in the stack behaves.
141 # Values are (capture stderr, capture subprocesses, apply labels).
141 # Values are (capture stderr, capture subprocesses, apply labels).
142 self._bufferstates = []
142 self._bufferstates = []
143 # When a buffer is active, defines whether we are expanding labels.
143 # When a buffer is active, defines whether we are expanding labels.
144 # This exists to prevent an extra list lookup.
144 # This exists to prevent an extra list lookup.
145 self._bufferapplylabels = None
145 self._bufferapplylabels = None
146 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
146 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
147 self._reportuntrusted = True
147 self._reportuntrusted = True
148 self._ocfg = config.config() # overlay
148 self._ocfg = config.config() # overlay
149 self._tcfg = config.config() # trusted
149 self._tcfg = config.config() # trusted
150 self._ucfg = config.config() # untrusted
150 self._ucfg = config.config() # untrusted
151 self._trustusers = set()
151 self._trustusers = set()
152 self._trustgroups = set()
152 self._trustgroups = set()
153 self.callhooks = True
153 self.callhooks = True
154 # Insecure server connections requested.
154 # Insecure server connections requested.
155 self.insecureconnections = False
155 self.insecureconnections = False
156 # Blocked time
156 # Blocked time
157 self.logblockedtimes = False
157 self.logblockedtimes = False
158 # color mode: see mercurial/color.py for possible value
158 # color mode: see mercurial/color.py for possible value
159 self._colormode = None
159 self._colormode = None
160 self._terminfoparams = {}
160 self._terminfoparams = {}
161 self._styles = {}
161 self._styles = {}
162
162
163 if src:
163 if src:
164 self.fout = src.fout
164 self.fout = src.fout
165 self.ferr = src.ferr
165 self.ferr = src.ferr
166 self.fin = src.fin
166 self.fin = src.fin
167 self.pageractive = src.pageractive
167 self.pageractive = src.pageractive
168 self._disablepager = src._disablepager
168 self._disablepager = src._disablepager
169
169
170 self._tcfg = src._tcfg.copy()
170 self._tcfg = src._tcfg.copy()
171 self._ucfg = src._ucfg.copy()
171 self._ucfg = src._ucfg.copy()
172 self._ocfg = src._ocfg.copy()
172 self._ocfg = src._ocfg.copy()
173 self._trustusers = src._trustusers.copy()
173 self._trustusers = src._trustusers.copy()
174 self._trustgroups = src._trustgroups.copy()
174 self._trustgroups = src._trustgroups.copy()
175 self.environ = src.environ
175 self.environ = src.environ
176 self.callhooks = src.callhooks
176 self.callhooks = src.callhooks
177 self.insecureconnections = src.insecureconnections
177 self.insecureconnections = src.insecureconnections
178 self._colormode = src._colormode
178 self._colormode = src._colormode
179 self._terminfoparams = src._terminfoparams.copy()
179 self._terminfoparams = src._terminfoparams.copy()
180 self._styles = src._styles.copy()
180 self._styles = src._styles.copy()
181
181
182 self.fixconfig()
182 self.fixconfig()
183
183
184 self.httppasswordmgrdb = src.httppasswordmgrdb
184 self.httppasswordmgrdb = src.httppasswordmgrdb
185 self._blockedtimes = src._blockedtimes
185 self._blockedtimes = src._blockedtimes
186 else:
186 else:
187 self.fout = util.stdout
187 self.fout = util.stdout
188 self.ferr = util.stderr
188 self.ferr = util.stderr
189 self.fin = util.stdin
189 self.fin = util.stdin
190 self.pageractive = False
190 self.pageractive = False
191 self._disablepager = False
191 self._disablepager = False
192
192
193 # shared read-only environment
193 # shared read-only environment
194 self.environ = encoding.environ
194 self.environ = encoding.environ
195
195
196 self.httppasswordmgrdb = httppasswordmgrdbproxy()
196 self.httppasswordmgrdb = httppasswordmgrdbproxy()
197 self._blockedtimes = collections.defaultdict(int)
197 self._blockedtimes = collections.defaultdict(int)
198
198
199 allowed = self.configlist('experimental', 'exportableenviron')
199 allowed = self.configlist('experimental', 'exportableenviron')
200 if '*' in allowed:
200 if '*' in allowed:
201 self._exportableenviron = self.environ
201 self._exportableenviron = self.environ
202 else:
202 else:
203 self._exportableenviron = {}
203 self._exportableenviron = {}
204 for k in allowed:
204 for k in allowed:
205 if k in self.environ:
205 if k in self.environ:
206 self._exportableenviron[k] = self.environ[k]
206 self._exportableenviron[k] = self.environ[k]
207
207
208 @classmethod
208 @classmethod
209 def load(cls):
209 def load(cls):
210 """Create a ui and load global and user configs"""
210 """Create a ui and load global and user configs"""
211 u = cls()
211 u = cls()
212 # we always trust global config files
212 # we always trust global config files
213 for f in scmutil.rcpath():
213 for f in scmutil.rcpath():
214 u.readconfig(f, trust=True)
214 u.readconfig(f, trust=True)
215 return u
215 return u
216
216
217 def copy(self):
217 def copy(self):
218 return self.__class__(self)
218 return self.__class__(self)
219
219
220 def resetstate(self):
220 def resetstate(self):
221 """Clear internal state that shouldn't persist across commands"""
221 """Clear internal state that shouldn't persist across commands"""
222 if self._progbar:
222 if self._progbar:
223 self._progbar.resetstate() # reset last-print time of progress bar
223 self._progbar.resetstate() # reset last-print time of progress bar
224 self.httppasswordmgrdb = httppasswordmgrdbproxy()
224 self.httppasswordmgrdb = httppasswordmgrdbproxy()
225
225
226 @contextlib.contextmanager
226 @contextlib.contextmanager
227 def timeblockedsection(self, key):
227 def timeblockedsection(self, key):
228 # this is open-coded below - search for timeblockedsection to find them
228 # this is open-coded below - search for timeblockedsection to find them
229 starttime = util.timer()
229 starttime = util.timer()
230 try:
230 try:
231 yield
231 yield
232 finally:
232 finally:
233 self._blockedtimes[key + '_blocked'] += \
233 self._blockedtimes[key + '_blocked'] += \
234 (util.timer() - starttime) * 1000
234 (util.timer() - starttime) * 1000
235
235
236 def formatter(self, topic, opts):
236 def formatter(self, topic, opts):
237 return formatter.formatter(self, topic, opts)
237 return formatter.formatter(self, topic, opts)
238
238
239 def _trusted(self, fp, f):
239 def _trusted(self, fp, f):
240 st = util.fstat(fp)
240 st = util.fstat(fp)
241 if util.isowner(st):
241 if util.isowner(st):
242 return True
242 return True
243
243
244 tusers, tgroups = self._trustusers, self._trustgroups
244 tusers, tgroups = self._trustusers, self._trustgroups
245 if '*' in tusers or '*' in tgroups:
245 if '*' in tusers or '*' in tgroups:
246 return True
246 return True
247
247
248 user = util.username(st.st_uid)
248 user = util.username(st.st_uid)
249 group = util.groupname(st.st_gid)
249 group = util.groupname(st.st_gid)
250 if user in tusers or group in tgroups or user == util.username():
250 if user in tusers or group in tgroups or user == util.username():
251 return True
251 return True
252
252
253 if self._reportuntrusted:
253 if self._reportuntrusted:
254 self.warn(_('not trusting file %s from untrusted '
254 self.warn(_('not trusting file %s from untrusted '
255 'user %s, group %s\n') % (f, user, group))
255 'user %s, group %s\n') % (f, user, group))
256 return False
256 return False
257
257
258 def readconfig(self, filename, root=None, trust=False,
258 def readconfig(self, filename, root=None, trust=False,
259 sections=None, remap=None):
259 sections=None, remap=None):
260 try:
260 try:
261 fp = open(filename, u'rb')
261 fp = open(filename, u'rb')
262 except IOError:
262 except IOError:
263 if not sections: # ignore unless we were looking for something
263 if not sections: # ignore unless we were looking for something
264 return
264 return
265 raise
265 raise
266
266
267 cfg = config.config()
267 cfg = config.config()
268 trusted = sections or trust or self._trusted(fp, filename)
268 trusted = sections or trust or self._trusted(fp, filename)
269
269
270 try:
270 try:
271 cfg.read(filename, fp, sections=sections, remap=remap)
271 cfg.read(filename, fp, sections=sections, remap=remap)
272 fp.close()
272 fp.close()
273 except error.ConfigError as inst:
273 except error.ConfigError as inst:
274 if trusted:
274 if trusted:
275 raise
275 raise
276 self.warn(_("ignored: %s\n") % str(inst))
276 self.warn(_("ignored: %s\n") % str(inst))
277
277
278 if self.plain():
278 if self.plain():
279 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
279 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
280 'logtemplate', 'statuscopies', 'style',
280 'logtemplate', 'statuscopies', 'style',
281 'traceback', 'verbose'):
281 'traceback', 'verbose'):
282 if k in cfg['ui']:
282 if k in cfg['ui']:
283 del cfg['ui'][k]
283 del cfg['ui'][k]
284 for k, v in cfg.items('defaults'):
284 for k, v in cfg.items('defaults'):
285 del cfg['defaults'][k]
285 del cfg['defaults'][k]
286 # Don't remove aliases from the configuration if in the exceptionlist
286 # Don't remove aliases from the configuration if in the exceptionlist
287 if self.plain('alias'):
287 if self.plain('alias'):
288 for k, v in cfg.items('alias'):
288 for k, v in cfg.items('alias'):
289 del cfg['alias'][k]
289 del cfg['alias'][k]
290 if self.plain('revsetalias'):
290 if self.plain('revsetalias'):
291 for k, v in cfg.items('revsetalias'):
291 for k, v in cfg.items('revsetalias'):
292 del cfg['revsetalias'][k]
292 del cfg['revsetalias'][k]
293 if self.plain('templatealias'):
293 if self.plain('templatealias'):
294 for k, v in cfg.items('templatealias'):
294 for k, v in cfg.items('templatealias'):
295 del cfg['templatealias'][k]
295 del cfg['templatealias'][k]
296
296
297 if trusted:
297 if trusted:
298 self._tcfg.update(cfg)
298 self._tcfg.update(cfg)
299 self._tcfg.update(self._ocfg)
299 self._tcfg.update(self._ocfg)
300 self._ucfg.update(cfg)
300 self._ucfg.update(cfg)
301 self._ucfg.update(self._ocfg)
301 self._ucfg.update(self._ocfg)
302
302
303 if root is None:
303 if root is None:
304 root = os.path.expanduser('~')
304 root = os.path.expanduser('~')
305 self.fixconfig(root=root)
305 self.fixconfig(root=root)
306
306
307 def fixconfig(self, root=None, section=None):
307 def fixconfig(self, root=None, section=None):
308 if section in (None, 'paths'):
308 if section in (None, 'paths'):
309 # expand vars and ~
309 # expand vars and ~
310 # translate paths relative to root (or home) into absolute paths
310 # translate paths relative to root (or home) into absolute paths
311 root = root or pycompat.getcwd()
311 root = root or pycompat.getcwd()
312 for c in self._tcfg, self._ucfg, self._ocfg:
312 for c in self._tcfg, self._ucfg, self._ocfg:
313 for n, p in c.items('paths'):
313 for n, p in c.items('paths'):
314 # Ignore sub-options.
314 # Ignore sub-options.
315 if ':' in n:
315 if ':' in n:
316 continue
316 continue
317 if not p:
317 if not p:
318 continue
318 continue
319 if '%%' in p:
319 if '%%' in p:
320 s = self.configsource('paths', n) or 'none'
320 s = self.configsource('paths', n) or 'none'
321 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
321 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
322 % (n, p, s))
322 % (n, p, s))
323 p = p.replace('%%', '%')
323 p = p.replace('%%', '%')
324 p = util.expandpath(p)
324 p = util.expandpath(p)
325 if not util.hasscheme(p) and not os.path.isabs(p):
325 if not util.hasscheme(p) and not os.path.isabs(p):
326 p = os.path.normpath(os.path.join(root, p))
326 p = os.path.normpath(os.path.join(root, p))
327 c.set("paths", n, p)
327 c.set("paths", n, p)
328
328
329 if section in (None, 'ui'):
329 if section in (None, 'ui'):
330 # update ui options
330 # update ui options
331 self.debugflag = self.configbool('ui', 'debug')
331 self.debugflag = self.configbool('ui', 'debug')
332 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
332 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
333 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
333 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
334 if self.verbose and self.quiet:
334 if self.verbose and self.quiet:
335 self.quiet = self.verbose = False
335 self.quiet = self.verbose = False
336 self._reportuntrusted = self.debugflag or self.configbool("ui",
336 self._reportuntrusted = self.debugflag or self.configbool("ui",
337 "report_untrusted", True)
337 "report_untrusted", True)
338 self.tracebackflag = self.configbool('ui', 'traceback', False)
338 self.tracebackflag = self.configbool('ui', 'traceback', False)
339 self.logblockedtimes = self.configbool('ui', 'logblockedtimes')
339 self.logblockedtimes = self.configbool('ui', 'logblockedtimes')
340
340
341 if section in (None, 'trusted'):
341 if section in (None, 'trusted'):
342 # update trust information
342 # update trust information
343 self._trustusers.update(self.configlist('trusted', 'users'))
343 self._trustusers.update(self.configlist('trusted', 'users'))
344 self._trustgroups.update(self.configlist('trusted', 'groups'))
344 self._trustgroups.update(self.configlist('trusted', 'groups'))
345
345
346 def backupconfig(self, section, item):
346 def backupconfig(self, section, item):
347 return (self._ocfg.backup(section, item),
347 return (self._ocfg.backup(section, item),
348 self._tcfg.backup(section, item),
348 self._tcfg.backup(section, item),
349 self._ucfg.backup(section, item),)
349 self._ucfg.backup(section, item),)
350 def restoreconfig(self, data):
350 def restoreconfig(self, data):
351 self._ocfg.restore(data[0])
351 self._ocfg.restore(data[0])
352 self._tcfg.restore(data[1])
352 self._tcfg.restore(data[1])
353 self._ucfg.restore(data[2])
353 self._ucfg.restore(data[2])
354
354
355 def setconfig(self, section, name, value, source=''):
355 def setconfig(self, section, name, value, source=''):
356 for cfg in (self._ocfg, self._tcfg, self._ucfg):
356 for cfg in (self._ocfg, self._tcfg, self._ucfg):
357 cfg.set(section, name, value, source)
357 cfg.set(section, name, value, source)
358 self.fixconfig(section=section)
358 self.fixconfig(section=section)
359
359
360 def _data(self, untrusted):
360 def _data(self, untrusted):
361 return untrusted and self._ucfg or self._tcfg
361 return untrusted and self._ucfg or self._tcfg
362
362
363 def configsource(self, section, name, untrusted=False):
363 def configsource(self, section, name, untrusted=False):
364 return self._data(untrusted).source(section, name)
364 return self._data(untrusted).source(section, name)
365
365
366 def config(self, section, name, default=None, untrusted=False):
366 def config(self, section, name, default=None, untrusted=False):
367 if isinstance(name, list):
367 if isinstance(name, list):
368 alternates = name
368 alternates = name
369 else:
369 else:
370 alternates = [name]
370 alternates = [name]
371
371
372 for n in alternates:
372 for n in alternates:
373 value = self._data(untrusted).get(section, n, None)
373 value = self._data(untrusted).get(section, n, None)
374 if value is not None:
374 if value is not None:
375 name = n
375 name = n
376 break
376 break
377 else:
377 else:
378 value = default
378 value = default
379
379
380 if self.debugflag and not untrusted and self._reportuntrusted:
380 if self.debugflag and not untrusted and self._reportuntrusted:
381 for n in alternates:
381 for n in alternates:
382 uvalue = self._ucfg.get(section, n)
382 uvalue = self._ucfg.get(section, n)
383 if uvalue is not None and uvalue != value:
383 if uvalue is not None and uvalue != value:
384 self.debug("ignoring untrusted configuration option "
384 self.debug("ignoring untrusted configuration option "
385 "%s.%s = %s\n" % (section, n, uvalue))
385 "%s.%s = %s\n" % (section, n, uvalue))
386 return value
386 return value
387
387
388 def configsuboptions(self, section, name, default=None, untrusted=False):
388 def configsuboptions(self, section, name, default=None, untrusted=False):
389 """Get a config option and all sub-options.
389 """Get a config option and all sub-options.
390
390
391 Some config options have sub-options that are declared with the
391 Some config options have sub-options that are declared with the
392 format "key:opt = value". This method is used to return the main
392 format "key:opt = value". This method is used to return the main
393 option and all its declared sub-options.
393 option and all its declared sub-options.
394
394
395 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
395 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
396 is a dict of defined sub-options where keys and values are strings.
396 is a dict of defined sub-options where keys and values are strings.
397 """
397 """
398 data = self._data(untrusted)
398 data = self._data(untrusted)
399 main = data.get(section, name, default)
399 main = data.get(section, name, default)
400 if self.debugflag and not untrusted and self._reportuntrusted:
400 if self.debugflag and not untrusted and self._reportuntrusted:
401 uvalue = self._ucfg.get(section, name)
401 uvalue = self._ucfg.get(section, name)
402 if uvalue is not None and uvalue != main:
402 if uvalue is not None and uvalue != main:
403 self.debug('ignoring untrusted configuration option '
403 self.debug('ignoring untrusted configuration option '
404 '%s.%s = %s\n' % (section, name, uvalue))
404 '%s.%s = %s\n' % (section, name, uvalue))
405
405
406 sub = {}
406 sub = {}
407 prefix = '%s:' % name
407 prefix = '%s:' % name
408 for k, v in data.items(section):
408 for k, v in data.items(section):
409 if k.startswith(prefix):
409 if k.startswith(prefix):
410 sub[k[len(prefix):]] = v
410 sub[k[len(prefix):]] = v
411
411
412 if self.debugflag and not untrusted and self._reportuntrusted:
412 if self.debugflag and not untrusted and self._reportuntrusted:
413 for k, v in sub.items():
413 for k, v in sub.items():
414 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
414 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
415 if uvalue is not None and uvalue != v:
415 if uvalue is not None and uvalue != v:
416 self.debug('ignoring untrusted configuration option '
416 self.debug('ignoring untrusted configuration option '
417 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
417 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
418
418
419 return main, sub
419 return main, sub
420
420
421 def configpath(self, section, name, default=None, untrusted=False):
421 def configpath(self, section, name, default=None, untrusted=False):
422 'get a path config item, expanded relative to repo root or config file'
422 'get a path config item, expanded relative to repo root or config file'
423 v = self.config(section, name, default, untrusted)
423 v = self.config(section, name, default, untrusted)
424 if v is None:
424 if v is None:
425 return None
425 return None
426 if not os.path.isabs(v) or "://" not in v:
426 if not os.path.isabs(v) or "://" not in v:
427 src = self.configsource(section, name, untrusted)
427 src = self.configsource(section, name, untrusted)
428 if ':' in src:
428 if ':' in src:
429 base = os.path.dirname(src.rsplit(':')[0])
429 base = os.path.dirname(src.rsplit(':')[0])
430 v = os.path.join(base, os.path.expanduser(v))
430 v = os.path.join(base, os.path.expanduser(v))
431 return v
431 return v
432
432
433 def configbool(self, section, name, default=False, untrusted=False):
433 def configbool(self, section, name, default=False, untrusted=False):
434 """parse a configuration element as a boolean
434 """parse a configuration element as a boolean
435
435
436 >>> u = ui(); s = 'foo'
436 >>> u = ui(); s = 'foo'
437 >>> u.setconfig(s, 'true', 'yes')
437 >>> u.setconfig(s, 'true', 'yes')
438 >>> u.configbool(s, 'true')
438 >>> u.configbool(s, 'true')
439 True
439 True
440 >>> u.setconfig(s, 'false', 'no')
440 >>> u.setconfig(s, 'false', 'no')
441 >>> u.configbool(s, 'false')
441 >>> u.configbool(s, 'false')
442 False
442 False
443 >>> u.configbool(s, 'unknown')
443 >>> u.configbool(s, 'unknown')
444 False
444 False
445 >>> u.configbool(s, 'unknown', True)
445 >>> u.configbool(s, 'unknown', True)
446 True
446 True
447 >>> u.setconfig(s, 'invalid', 'somevalue')
447 >>> u.setconfig(s, 'invalid', 'somevalue')
448 >>> u.configbool(s, 'invalid')
448 >>> u.configbool(s, 'invalid')
449 Traceback (most recent call last):
449 Traceback (most recent call last):
450 ...
450 ...
451 ConfigError: foo.invalid is not a boolean ('somevalue')
451 ConfigError: foo.invalid is not a boolean ('somevalue')
452 """
452 """
453
453
454 v = self.config(section, name, None, untrusted)
454 v = self.config(section, name, None, untrusted)
455 if v is None:
455 if v is None:
456 return default
456 return default
457 if isinstance(v, bool):
457 if isinstance(v, bool):
458 return v
458 return v
459 b = util.parsebool(v)
459 b = util.parsebool(v)
460 if b is None:
460 if b is None:
461 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
461 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
462 % (section, name, v))
462 % (section, name, v))
463 return b
463 return b
464
464
465 def configwith(self, convert, section, name, default=None,
465 def configwith(self, convert, section, name, default=None,
466 desc=None, untrusted=False):
466 desc=None, untrusted=False):
467 """parse a configuration element with a conversion function
467 """parse a configuration element with a conversion function
468
468
469 >>> u = ui(); s = 'foo'
469 >>> u = ui(); s = 'foo'
470 >>> u.setconfig(s, 'float1', '42')
470 >>> u.setconfig(s, 'float1', '42')
471 >>> u.configwith(float, s, 'float1')
471 >>> u.configwith(float, s, 'float1')
472 42.0
472 42.0
473 >>> u.setconfig(s, 'float2', '-4.25')
473 >>> u.setconfig(s, 'float2', '-4.25')
474 >>> u.configwith(float, s, 'float2')
474 >>> u.configwith(float, s, 'float2')
475 -4.25
475 -4.25
476 >>> u.configwith(float, s, 'unknown', 7)
476 >>> u.configwith(float, s, 'unknown', 7)
477 7
477 7
478 >>> u.setconfig(s, 'invalid', 'somevalue')
478 >>> u.setconfig(s, 'invalid', 'somevalue')
479 >>> u.configwith(float, s, 'invalid')
479 >>> u.configwith(float, s, 'invalid')
480 Traceback (most recent call last):
480 Traceback (most recent call last):
481 ...
481 ...
482 ConfigError: foo.invalid is not a valid float ('somevalue')
482 ConfigError: foo.invalid is not a valid float ('somevalue')
483 >>> u.configwith(float, s, 'invalid', desc='womble')
483 >>> u.configwith(float, s, 'invalid', desc='womble')
484 Traceback (most recent call last):
484 Traceback (most recent call last):
485 ...
485 ...
486 ConfigError: foo.invalid is not a valid womble ('somevalue')
486 ConfigError: foo.invalid is not a valid womble ('somevalue')
487 """
487 """
488
488
489 v = self.config(section, name, None, untrusted)
489 v = self.config(section, name, None, untrusted)
490 if v is None:
490 if v is None:
491 return default
491 return default
492 try:
492 try:
493 return convert(v)
493 return convert(v)
494 except ValueError:
494 except ValueError:
495 if desc is None:
495 if desc is None:
496 desc = convert.__name__
496 desc = convert.__name__
497 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
497 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
498 % (section, name, desc, v))
498 % (section, name, desc, v))
499
499
500 def configint(self, section, name, default=None, untrusted=False):
500 def configint(self, section, name, default=None, untrusted=False):
501 """parse a configuration element as an integer
501 """parse a configuration element as an integer
502
502
503 >>> u = ui(); s = 'foo'
503 >>> u = ui(); s = 'foo'
504 >>> u.setconfig(s, 'int1', '42')
504 >>> u.setconfig(s, 'int1', '42')
505 >>> u.configint(s, 'int1')
505 >>> u.configint(s, 'int1')
506 42
506 42
507 >>> u.setconfig(s, 'int2', '-42')
507 >>> u.setconfig(s, 'int2', '-42')
508 >>> u.configint(s, 'int2')
508 >>> u.configint(s, 'int2')
509 -42
509 -42
510 >>> u.configint(s, 'unknown', 7)
510 >>> u.configint(s, 'unknown', 7)
511 7
511 7
512 >>> u.setconfig(s, 'invalid', 'somevalue')
512 >>> u.setconfig(s, 'invalid', 'somevalue')
513 >>> u.configint(s, 'invalid')
513 >>> u.configint(s, 'invalid')
514 Traceback (most recent call last):
514 Traceback (most recent call last):
515 ...
515 ...
516 ConfigError: foo.invalid is not a valid integer ('somevalue')
516 ConfigError: foo.invalid is not a valid integer ('somevalue')
517 """
517 """
518
518
519 return self.configwith(int, section, name, default, 'integer',
519 return self.configwith(int, section, name, default, 'integer',
520 untrusted)
520 untrusted)
521
521
522 def configbytes(self, section, name, default=0, untrusted=False):
522 def configbytes(self, section, name, default=0, untrusted=False):
523 """parse a configuration element as a quantity in bytes
523 """parse a configuration element as a quantity in bytes
524
524
525 Units can be specified as b (bytes), k or kb (kilobytes), m or
525 Units can be specified as b (bytes), k or kb (kilobytes), m or
526 mb (megabytes), g or gb (gigabytes).
526 mb (megabytes), g or gb (gigabytes).
527
527
528 >>> u = ui(); s = 'foo'
528 >>> u = ui(); s = 'foo'
529 >>> u.setconfig(s, 'val1', '42')
529 >>> u.setconfig(s, 'val1', '42')
530 >>> u.configbytes(s, 'val1')
530 >>> u.configbytes(s, 'val1')
531 42
531 42
532 >>> u.setconfig(s, 'val2', '42.5 kb')
532 >>> u.setconfig(s, 'val2', '42.5 kb')
533 >>> u.configbytes(s, 'val2')
533 >>> u.configbytes(s, 'val2')
534 43520
534 43520
535 >>> u.configbytes(s, 'unknown', '7 MB')
535 >>> u.configbytes(s, 'unknown', '7 MB')
536 7340032
536 7340032
537 >>> u.setconfig(s, 'invalid', 'somevalue')
537 >>> u.setconfig(s, 'invalid', 'somevalue')
538 >>> u.configbytes(s, 'invalid')
538 >>> u.configbytes(s, 'invalid')
539 Traceback (most recent call last):
539 Traceback (most recent call last):
540 ...
540 ...
541 ConfigError: foo.invalid is not a byte quantity ('somevalue')
541 ConfigError: foo.invalid is not a byte quantity ('somevalue')
542 """
542 """
543
543
544 value = self.config(section, name)
544 value = self.config(section, name)
545 if value is None:
545 if value is None:
546 if not isinstance(default, str):
546 if not isinstance(default, str):
547 return default
547 return default
548 value = default
548 value = default
549 try:
549 try:
550 return util.sizetoint(value)
550 return util.sizetoint(value)
551 except error.ParseError:
551 except error.ParseError:
552 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
552 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
553 % (section, name, value))
553 % (section, name, value))
554
554
555 def configlist(self, section, name, default=None, untrusted=False):
555 def configlist(self, section, name, default=None, untrusted=False):
556 """parse a configuration element as a list of comma/space separated
556 """parse a configuration element as a list of comma/space separated
557 strings
557 strings
558
558
559 >>> u = ui(); s = 'foo'
559 >>> u = ui(); s = 'foo'
560 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
560 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
561 >>> u.configlist(s, 'list1')
561 >>> u.configlist(s, 'list1')
562 ['this', 'is', 'a small', 'test']
562 ['this', 'is', 'a small', 'test']
563 """
563 """
564
564
565 def _parse_plain(parts, s, offset):
565 def _parse_plain(parts, s, offset):
566 whitespace = False
566 whitespace = False
567 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
567 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
568 whitespace = True
568 whitespace = True
569 offset += 1
569 offset += 1
570 if offset >= len(s):
570 if offset >= len(s):
571 return None, parts, offset
571 return None, parts, offset
572 if whitespace:
572 if whitespace:
573 parts.append('')
573 parts.append('')
574 if s[offset] == '"' and not parts[-1]:
574 if s[offset] == '"' and not parts[-1]:
575 return _parse_quote, parts, offset + 1
575 return _parse_quote, parts, offset + 1
576 elif s[offset] == '"' and parts[-1][-1] == '\\':
576 elif s[offset] == '"' and parts[-1][-1] == '\\':
577 parts[-1] = parts[-1][:-1] + s[offset]
577 parts[-1] = parts[-1][:-1] + s[offset]
578 return _parse_plain, parts, offset + 1
578 return _parse_plain, parts, offset + 1
579 parts[-1] += s[offset]
579 parts[-1] += s[offset]
580 return _parse_plain, parts, offset + 1
580 return _parse_plain, parts, offset + 1
581
581
582 def _parse_quote(parts, s, offset):
582 def _parse_quote(parts, s, offset):
583 if offset < len(s) and s[offset] == '"': # ""
583 if offset < len(s) and s[offset] == '"': # ""
584 parts.append('')
584 parts.append('')
585 offset += 1
585 offset += 1
586 while offset < len(s) and (s[offset].isspace() or
586 while offset < len(s) and (s[offset].isspace() or
587 s[offset] == ','):
587 s[offset] == ','):
588 offset += 1
588 offset += 1
589 return _parse_plain, parts, offset
589 return _parse_plain, parts, offset
590
590
591 while offset < len(s) and s[offset] != '"':
591 while offset < len(s) and s[offset] != '"':
592 if (s[offset] == '\\' and offset + 1 < len(s)
592 if (s[offset] == '\\' and offset + 1 < len(s)
593 and s[offset + 1] == '"'):
593 and s[offset + 1] == '"'):
594 offset += 1
594 offset += 1
595 parts[-1] += '"'
595 parts[-1] += '"'
596 else:
596 else:
597 parts[-1] += s[offset]
597 parts[-1] += s[offset]
598 offset += 1
598 offset += 1
599
599
600 if offset >= len(s):
600 if offset >= len(s):
601 real_parts = _configlist(parts[-1])
601 real_parts = _configlist(parts[-1])
602 if not real_parts:
602 if not real_parts:
603 parts[-1] = '"'
603 parts[-1] = '"'
604 else:
604 else:
605 real_parts[0] = '"' + real_parts[0]
605 real_parts[0] = '"' + real_parts[0]
606 parts = parts[:-1]
606 parts = parts[:-1]
607 parts.extend(real_parts)
607 parts.extend(real_parts)
608 return None, parts, offset
608 return None, parts, offset
609
609
610 offset += 1
610 offset += 1
611 while offset < len(s) and s[offset] in [' ', ',']:
611 while offset < len(s) and s[offset] in [' ', ',']:
612 offset += 1
612 offset += 1
613
613
614 if offset < len(s):
614 if offset < len(s):
615 if offset + 1 == len(s) and s[offset] == '"':
615 if offset + 1 == len(s) and s[offset] == '"':
616 parts[-1] += '"'
616 parts[-1] += '"'
617 offset += 1
617 offset += 1
618 else:
618 else:
619 parts.append('')
619 parts.append('')
620 else:
620 else:
621 return None, parts, offset
621 return None, parts, offset
622
622
623 return _parse_plain, parts, offset
623 return _parse_plain, parts, offset
624
624
625 def _configlist(s):
625 def _configlist(s):
626 s = s.rstrip(' ,')
626 s = s.rstrip(' ,')
627 if not s:
627 if not s:
628 return []
628 return []
629 parser, parts, offset = _parse_plain, [''], 0
629 parser, parts, offset = _parse_plain, [''], 0
630 while parser:
630 while parser:
631 parser, parts, offset = parser(parts, s, offset)
631 parser, parts, offset = parser(parts, s, offset)
632 return parts
632 return parts
633
633
634 result = self.config(section, name, untrusted=untrusted)
634 result = self.config(section, name, untrusted=untrusted)
635 if result is None:
635 if result is None:
636 result = default or []
636 result = default or []
637 if isinstance(result, bytes):
637 if isinstance(result, bytes):
638 result = _configlist(result.lstrip(' ,\n'))
638 result = _configlist(result.lstrip(' ,\n'))
639 if result is None:
639 if result is None:
640 result = default or []
640 result = default or []
641 return result
641 return result
642
642
643 def hasconfig(self, section, name, untrusted=False):
643 def hasconfig(self, section, name, untrusted=False):
644 return self._data(untrusted).hasitem(section, name)
644 return self._data(untrusted).hasitem(section, name)
645
645
646 def has_section(self, section, untrusted=False):
646 def has_section(self, section, untrusted=False):
647 '''tell whether section exists in config.'''
647 '''tell whether section exists in config.'''
648 return section in self._data(untrusted)
648 return section in self._data(untrusted)
649
649
650 def configitems(self, section, untrusted=False, ignoresub=False):
650 def configitems(self, section, untrusted=False, ignoresub=False):
651 items = self._data(untrusted).items(section)
651 items = self._data(untrusted).items(section)
652 if ignoresub:
652 if ignoresub:
653 newitems = {}
653 newitems = {}
654 for k, v in items:
654 for k, v in items:
655 if ':' not in k:
655 if ':' not in k:
656 newitems[k] = v
656 newitems[k] = v
657 items = newitems.items()
657 items = newitems.items()
658 if self.debugflag and not untrusted and self._reportuntrusted:
658 if self.debugflag and not untrusted and self._reportuntrusted:
659 for k, v in self._ucfg.items(section):
659 for k, v in self._ucfg.items(section):
660 if self._tcfg.get(section, k) != v:
660 if self._tcfg.get(section, k) != v:
661 self.debug("ignoring untrusted configuration option "
661 self.debug("ignoring untrusted configuration option "
662 "%s.%s = %s\n" % (section, k, v))
662 "%s.%s = %s\n" % (section, k, v))
663 return items
663 return items
664
664
665 def walkconfig(self, untrusted=False):
665 def walkconfig(self, untrusted=False):
666 cfg = self._data(untrusted)
666 cfg = self._data(untrusted)
667 for section in cfg.sections():
667 for section in cfg.sections():
668 for name, value in self.configitems(section, untrusted):
668 for name, value in self.configitems(section, untrusted):
669 yield section, name, value
669 yield section, name, value
670
670
671 def plain(self, feature=None):
671 def plain(self, feature=None):
672 '''is plain mode active?
672 '''is plain mode active?
673
673
674 Plain mode means that all configuration variables which affect
674 Plain mode means that all configuration variables which affect
675 the behavior and output of Mercurial should be
675 the behavior and output of Mercurial should be
676 ignored. Additionally, the output should be stable,
676 ignored. Additionally, the output should be stable,
677 reproducible and suitable for use in scripts or applications.
677 reproducible and suitable for use in scripts or applications.
678
678
679 The only way to trigger plain mode is by setting either the
679 The only way to trigger plain mode is by setting either the
680 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
680 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
681
681
682 The return value can either be
682 The return value can either be
683 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
683 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
684 - True otherwise
684 - True otherwise
685 '''
685 '''
686 if ('HGPLAIN' not in encoding.environ and
686 if ('HGPLAIN' not in encoding.environ and
687 'HGPLAINEXCEPT' not in encoding.environ):
687 'HGPLAINEXCEPT' not in encoding.environ):
688 return False
688 return False
689 exceptions = encoding.environ.get('HGPLAINEXCEPT',
689 exceptions = encoding.environ.get('HGPLAINEXCEPT',
690 '').strip().split(',')
690 '').strip().split(',')
691 if feature and exceptions:
691 if feature and exceptions:
692 return feature not in exceptions
692 return feature not in exceptions
693 return True
693 return True
694
694
695 def username(self):
695 def username(self):
696 """Return default username to be used in commits.
696 """Return default username to be used in commits.
697
697
698 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
698 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
699 and stop searching if one of these is set.
699 and stop searching if one of these is set.
700 If not found and ui.askusername is True, ask the user, else use
700 If not found and ui.askusername is True, ask the user, else use
701 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
701 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
702 """
702 """
703 user = encoding.environ.get("HGUSER")
703 user = encoding.environ.get("HGUSER")
704 if user is None:
704 if user is None:
705 user = self.config("ui", ["username", "user"])
705 user = self.config("ui", ["username", "user"])
706 if user is not None:
706 if user is not None:
707 user = os.path.expandvars(user)
707 user = os.path.expandvars(user)
708 if user is None:
708 if user is None:
709 user = encoding.environ.get("EMAIL")
709 user = encoding.environ.get("EMAIL")
710 if user is None and self.configbool("ui", "askusername"):
710 if user is None and self.configbool("ui", "askusername"):
711 user = self.prompt(_("enter a commit username:"), default=None)
711 user = self.prompt(_("enter a commit username:"), default=None)
712 if user is None and not self.interactive():
712 if user is None and not self.interactive():
713 try:
713 try:
714 user = '%s@%s' % (util.getuser(), socket.getfqdn())
714 user = '%s@%s' % (util.getuser(), socket.getfqdn())
715 self.warn(_("no username found, using '%s' instead\n") % user)
715 self.warn(_("no username found, using '%s' instead\n") % user)
716 except KeyError:
716 except KeyError:
717 pass
717 pass
718 if not user:
718 if not user:
719 raise error.Abort(_('no username supplied'),
719 raise error.Abort(_('no username supplied'),
720 hint=_("use 'hg config --edit' "
720 hint=_("use 'hg config --edit' "
721 'to set your username'))
721 'to set your username'))
722 if "\n" in user:
722 if "\n" in user:
723 raise error.Abort(_("username %s contains a newline\n")
723 raise error.Abort(_("username %s contains a newline\n")
724 % repr(user))
724 % repr(user))
725 return user
725 return user
726
726
727 def shortuser(self, user):
727 def shortuser(self, user):
728 """Return a short representation of a user name or email address."""
728 """Return a short representation of a user name or email address."""
729 if not self.verbose:
729 if not self.verbose:
730 user = util.shortuser(user)
730 user = util.shortuser(user)
731 return user
731 return user
732
732
733 def expandpath(self, loc, default=None):
733 def expandpath(self, loc, default=None):
734 """Return repository location relative to cwd or from [paths]"""
734 """Return repository location relative to cwd or from [paths]"""
735 try:
735 try:
736 p = self.paths.getpath(loc)
736 p = self.paths.getpath(loc)
737 if p:
737 if p:
738 return p.rawloc
738 return p.rawloc
739 except error.RepoError:
739 except error.RepoError:
740 pass
740 pass
741
741
742 if default:
742 if default:
743 try:
743 try:
744 p = self.paths.getpath(default)
744 p = self.paths.getpath(default)
745 if p:
745 if p:
746 return p.rawloc
746 return p.rawloc
747 except error.RepoError:
747 except error.RepoError:
748 pass
748 pass
749
749
750 return loc
750 return loc
751
751
752 @util.propertycache
752 @util.propertycache
753 def paths(self):
753 def paths(self):
754 return paths(self)
754 return paths(self)
755
755
756 def pushbuffer(self, error=False, subproc=False, labeled=False):
756 def pushbuffer(self, error=False, subproc=False, labeled=False):
757 """install a buffer to capture standard output of the ui object
757 """install a buffer to capture standard output of the ui object
758
758
759 If error is True, the error output will be captured too.
759 If error is True, the error output will be captured too.
760
760
761 If subproc is True, output from subprocesses (typically hooks) will be
761 If subproc is True, output from subprocesses (typically hooks) will be
762 captured too.
762 captured too.
763
763
764 If labeled is True, any labels associated with buffered
764 If labeled is True, any labels associated with buffered
765 output will be handled. By default, this has no effect
765 output will be handled. By default, this has no effect
766 on the output returned, but extensions and GUI tools may
766 on the output returned, but extensions and GUI tools may
767 handle this argument and returned styled output. If output
767 handle this argument and returned styled output. If output
768 is being buffered so it can be captured and parsed or
768 is being buffered so it can be captured and parsed or
769 processed, labeled should not be set to True.
769 processed, labeled should not be set to True.
770 """
770 """
771 self._buffers.append([])
771 self._buffers.append([])
772 self._bufferstates.append((error, subproc, labeled))
772 self._bufferstates.append((error, subproc, labeled))
773 self._bufferapplylabels = labeled
773 self._bufferapplylabels = labeled
774
774
775 def popbuffer(self):
775 def popbuffer(self):
776 '''pop the last buffer and return the buffered output'''
776 '''pop the last buffer and return the buffered output'''
777 self._bufferstates.pop()
777 self._bufferstates.pop()
778 if self._bufferstates:
778 if self._bufferstates:
779 self._bufferapplylabels = self._bufferstates[-1][2]
779 self._bufferapplylabels = self._bufferstates[-1][2]
780 else:
780 else:
781 self._bufferapplylabels = None
781 self._bufferapplylabels = None
782
782
783 return "".join(self._buffers.pop())
783 return "".join(self._buffers.pop())
784
784
785 def write(self, *args, **opts):
785 def write(self, *args, **opts):
786 '''write args to output
786 '''write args to output
787
787
788 By default, this method simply writes to the buffer or stdout.
788 By default, this method simply writes to the buffer or stdout.
789 Color mode can be set on the UI class to have the output decorated
789 Color mode can be set on the UI class to have the output decorated
790 with color modifier before being written to stdout.
790 with color modifier before being written to stdout.
791
791
792 The color used is controlled by an optional keyword argument, "label".
792 The color used is controlled by an optional keyword argument, "label".
793 This should be a string containing label names separated by space.
793 This should be a string containing label names separated by space.
794 Label names take the form of "topic.type". For example, ui.debug()
794 Label names take the form of "topic.type". For example, ui.debug()
795 issues a label of "ui.debug".
795 issues a label of "ui.debug".
796
796
797 When labeling output for a specific command, a label of
797 When labeling output for a specific command, a label of
798 "cmdname.type" is recommended. For example, status issues
798 "cmdname.type" is recommended. For example, status issues
799 a label of "status.modified" for modified files.
799 a label of "status.modified" for modified files.
800 '''
800 '''
801 if self._buffers and not opts.get('prompt', False):
801 if self._buffers and not opts.get('prompt', False):
802 if self._bufferapplylabels:
802 if self._bufferapplylabels:
803 label = opts.get('label', '')
803 label = opts.get('label', '')
804 self._buffers[-1].extend(self.label(a, label) for a in args)
804 self._buffers[-1].extend(self.label(a, label) for a in args)
805 else:
805 else:
806 self._buffers[-1].extend(args)
806 self._buffers[-1].extend(args)
807 elif self._colormode == 'win32':
807 elif self._colormode == 'win32':
808 # windows color printing is its own can of crab, defer to
808 # windows color printing is its own can of crab, defer to
809 # the color module and that is it.
809 # the color module and that is it.
810 color.win32print(self, self._write, *args, **opts)
810 color.win32print(self, self._write, *args, **opts)
811 else:
811 else:
812 msgs = args
812 msgs = args
813 if self._colormode is not None:
813 if self._colormode is not None:
814 label = opts.get('label', '')
814 label = opts.get('label', '')
815 msgs = [self.label(a, label) for a in args]
815 msgs = [self.label(a, label) for a in args]
816 self._write(*msgs, **opts)
816 self._write(*msgs, **opts)
817
817
818 def _write(self, *msgs, **opts):
818 def _write(self, *msgs, **opts):
819 self._progclear()
819 self._progclear()
820 # opencode timeblockedsection because this is a critical path
820 # opencode timeblockedsection because this is a critical path
821 starttime = util.timer()
821 starttime = util.timer()
822 try:
822 try:
823 for a in msgs:
823 for a in msgs:
824 self.fout.write(a)
824 self.fout.write(a)
825 finally:
825 finally:
826 self._blockedtimes['stdio_blocked'] += \
826 self._blockedtimes['stdio_blocked'] += \
827 (util.timer() - starttime) * 1000
827 (util.timer() - starttime) * 1000
828
828
829 def write_err(self, *args, **opts):
829 def write_err(self, *args, **opts):
830 self._progclear()
830 self._progclear()
831 if self._bufferstates and self._bufferstates[-1][0]:
831 if self._bufferstates and self._bufferstates[-1][0]:
832 self.write(*args, **opts)
832 self.write(*args, **opts)
833 elif self._colormode == 'win32':
833 elif self._colormode == 'win32':
834 # windows color printing is its own can of crab, defer to
834 # windows color printing is its own can of crab, defer to
835 # the color module and that is it.
835 # the color module and that is it.
836 color.win32print(self, self._write_err, *args, **opts)
836 color.win32print(self, self._write_err, *args, **opts)
837 else:
837 else:
838 msgs = args
838 msgs = args
839 if self._colormode is not None:
839 if self._colormode is not None:
840 label = opts.get('label', '')
840 label = opts.get('label', '')
841 msgs = [self.label(a, label) for a in args]
841 msgs = [self.label(a, label) for a in args]
842 self._write_err(*msgs, **opts)
842 self._write_err(*msgs, **opts)
843
843
844 def _write_err(self, *msgs, **opts):
844 def _write_err(self, *msgs, **opts):
845 try:
845 try:
846 with self.timeblockedsection('stdio'):
846 with self.timeblockedsection('stdio'):
847 if not getattr(self.fout, 'closed', False):
847 if not getattr(self.fout, 'closed', False):
848 self.fout.flush()
848 self.fout.flush()
849 for a in msgs:
849 for a in msgs:
850 self.ferr.write(a)
850 self.ferr.write(a)
851 # stderr may be buffered under win32 when redirected to files,
851 # stderr may be buffered under win32 when redirected to files,
852 # including stdout.
852 # including stdout.
853 if not getattr(self.ferr, 'closed', False):
853 if not getattr(self.ferr, 'closed', False):
854 self.ferr.flush()
854 self.ferr.flush()
855 except IOError as inst:
855 except IOError as inst:
856 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
856 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
857 raise
857 raise
858
858
859 def flush(self):
859 def flush(self):
860 # opencode timeblockedsection because this is a critical path
860 # opencode timeblockedsection because this is a critical path
861 starttime = util.timer()
861 starttime = util.timer()
862 try:
862 try:
863 try: self.fout.flush()
863 try: self.fout.flush()
864 except (IOError, ValueError): pass
864 except (IOError, ValueError): pass
865 try: self.ferr.flush()
865 try: self.ferr.flush()
866 except (IOError, ValueError): pass
866 except (IOError, ValueError): pass
867 finally:
867 finally:
868 self._blockedtimes['stdio_blocked'] += \
868 self._blockedtimes['stdio_blocked'] += \
869 (util.timer() - starttime) * 1000
869 (util.timer() - starttime) * 1000
870
870
871 def _isatty(self, fh):
871 def _isatty(self, fh):
872 if self.configbool('ui', 'nontty', False):
872 if self.configbool('ui', 'nontty', False):
873 return False
873 return False
874 return util.isatty(fh)
874 return util.isatty(fh)
875
875
876 def disablepager(self):
876 def disablepager(self):
877 self._disablepager = True
877 self._disablepager = True
878
878
879 def pager(self, command):
879 def pager(self, command):
880 """Start a pager for subsequent command output.
880 """Start a pager for subsequent command output.
881
881
882 Commands which produce a long stream of output should call
882 Commands which produce a long stream of output should call
883 this function to activate the user's preferred pagination
883 this function to activate the user's preferred pagination
884 mechanism (which may be no pager). Calling this function
884 mechanism (which may be no pager). Calling this function
885 precludes any future use of interactive functionality, such as
885 precludes any future use of interactive functionality, such as
886 prompting the user or activating curses.
886 prompting the user or activating curses.
887
887
888 Args:
888 Args:
889 command: The full, non-aliased name of the command. That is, "log"
889 command: The full, non-aliased name of the command. That is, "log"
890 not "history, "summary" not "summ", etc.
890 not "history, "summary" not "summ", etc.
891 """
891 """
892 if (self._disablepager
892 if (self._disablepager
893 or self.pageractive
893 or self.pageractive
894 or command in self.configlist('pager', 'ignore')
894 or command in self.configlist('pager', 'ignore')
895 or not self.configbool('pager', 'enable', True)
895 or not self.configbool('pager', 'enable', True)
896 or not self.configbool('pager', 'attend-' + command, True)
896 or not self.configbool('pager', 'attend-' + command, True)
897 # TODO: if we want to allow HGPLAINEXCEPT=pager,
897 # TODO: if we want to allow HGPLAINEXCEPT=pager,
898 # formatted() will need some adjustment.
898 # formatted() will need some adjustment.
899 or not self.formatted()
899 or not self.formatted()
900 or self.plain()
900 or self.plain()
901 # TODO: expose debugger-enabled on the UI object
901 # TODO: expose debugger-enabled on the UI object
902 or '--debugger' in sys.argv):
902 or '--debugger' in sys.argv):
903 # We only want to paginate if the ui appears to be
903 # We only want to paginate if the ui appears to be
904 # interactive, the user didn't say HGPLAIN or
904 # interactive, the user didn't say HGPLAIN or
905 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
905 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
906 return
906 return
907
907
908 # TODO: add a "system defaults" config section so this default
908 # TODO: add a "system defaults" config section so this default
909 # of more(1) can be easily replaced with a global
909 # of more(1) can be easily replaced with a global
910 # configuration file. For example, on OS X the sane default is
910 # configuration file. For example, on OS X the sane default is
911 # less(1), not more(1), and on debian it's
911 # less(1), not more(1), and on debian it's
912 # sensible-pager(1). We should probably also give the system
912 # sensible-pager(1). We should probably also give the system
913 # default editor command similar treatment.
913 # default editor command similar treatment.
914 envpager = encoding.environ.get('PAGER', 'more')
914 envpager = encoding.environ.get('PAGER', 'more')
915 pagercmd = self.config('pager', 'pager', envpager)
915 pagercmd = self.config('pager', 'pager', envpager)
916 if not pagercmd:
916 if not pagercmd:
917 return
917 return
918
918
919 self.debug('starting pager for command %r\n' % command)
919 self.debug('starting pager for command %r\n' % command)
920 self.pageractive = True
920 self.pageractive = True
921 # Preserve the formatted-ness of the UI. This is important
921 # Preserve the formatted-ness of the UI. This is important
922 # because we mess with stdout, which might confuse
922 # because we mess with stdout, which might confuse
923 # auto-detection of things being formatted.
923 # auto-detection of things being formatted.
924 self.setconfig('ui', 'formatted', self.formatted(), 'pager')
924 self.setconfig('ui', 'formatted', self.formatted(), 'pager')
925 self.setconfig('ui', 'interactive', False, 'pager')
925 self.setconfig('ui', 'interactive', False, 'pager')
926 if util.safehasattr(signal, "SIGPIPE"):
926 if util.safehasattr(signal, "SIGPIPE"):
927 signal.signal(signal.SIGPIPE, _catchterm)
927 signal.signal(signal.SIGPIPE, _catchterm)
928 self._runpager(pagercmd)
928 self._runpager(pagercmd)
929
929
930 def _runpager(self, command):
930 def _runpager(self, command):
931 """Actually start the pager and set up file descriptors.
931 """Actually start the pager and set up file descriptors.
932
932
933 This is separate in part so that extensions (like chg) can
933 This is separate in part so that extensions (like chg) can
934 override how a pager is invoked.
934 override how a pager is invoked.
935 """
935 """
936 pager = subprocess.Popen(command, shell=True, bufsize=-1,
936 pager = subprocess.Popen(command, shell=True, bufsize=-1,
937 close_fds=util.closefds, stdin=subprocess.PIPE,
937 close_fds=util.closefds, stdin=subprocess.PIPE,
938 stdout=util.stdout, stderr=util.stderr)
938 stdout=util.stdout, stderr=util.stderr)
939
939
940 # back up original file descriptors
940 # back up original file descriptors
941 stdoutfd = os.dup(util.stdout.fileno())
941 stdoutfd = os.dup(util.stdout.fileno())
942 stderrfd = os.dup(util.stderr.fileno())
942 stderrfd = os.dup(util.stderr.fileno())
943
943
944 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
944 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
945 if self._isatty(util.stderr):
945 if self._isatty(util.stderr):
946 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
946 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
947
947
948 @atexit.register
948 @atexit.register
949 def killpager():
949 def killpager():
950 if util.safehasattr(signal, "SIGINT"):
950 if util.safehasattr(signal, "SIGINT"):
951 signal.signal(signal.SIGINT, signal.SIG_IGN)
951 signal.signal(signal.SIGINT, signal.SIG_IGN)
952 # restore original fds, closing pager.stdin copies in the process
952 # restore original fds, closing pager.stdin copies in the process
953 os.dup2(stdoutfd, util.stdout.fileno())
953 os.dup2(stdoutfd, util.stdout.fileno())
954 os.dup2(stderrfd, util.stderr.fileno())
954 os.dup2(stderrfd, util.stderr.fileno())
955 pager.stdin.close()
955 pager.stdin.close()
956 pager.wait()
956 pager.wait()
957
957
958 def interface(self, feature):
958 def interface(self, feature):
959 """what interface to use for interactive console features?
959 """what interface to use for interactive console features?
960
960
961 The interface is controlled by the value of `ui.interface` but also by
961 The interface is controlled by the value of `ui.interface` but also by
962 the value of feature-specific configuration. For example:
962 the value of feature-specific configuration. For example:
963
963
964 ui.interface.histedit = text
964 ui.interface.histedit = text
965 ui.interface.chunkselector = curses
965 ui.interface.chunkselector = curses
966
966
967 Here the features are "histedit" and "chunkselector".
967 Here the features are "histedit" and "chunkselector".
968
968
969 The configuration above means that the default interfaces for commands
969 The configuration above means that the default interfaces for commands
970 is curses, the interface for histedit is text and the interface for
970 is curses, the interface for histedit is text and the interface for
971 selecting chunk is crecord (the best curses interface available).
971 selecting chunk is crecord (the best curses interface available).
972
972
973 Consider the following example:
973 Consider the following example:
974 ui.interface = curses
974 ui.interface = curses
975 ui.interface.histedit = text
975 ui.interface.histedit = text
976
976
977 Then histedit will use the text interface and chunkselector will use
977 Then histedit will use the text interface and chunkselector will use
978 the default curses interface (crecord at the moment).
978 the default curses interface (crecord at the moment).
979 """
979 """
980 alldefaults = frozenset(["text", "curses"])
980 alldefaults = frozenset(["text", "curses"])
981
981
982 featureinterfaces = {
982 featureinterfaces = {
983 "chunkselector": [
983 "chunkselector": [
984 "text",
984 "text",
985 "curses",
985 "curses",
986 ]
986 ]
987 }
987 }
988
988
989 # Feature-specific interface
989 # Feature-specific interface
990 if feature not in featureinterfaces.keys():
990 if feature not in featureinterfaces.keys():
991 # Programming error, not user error
991 # Programming error, not user error
992 raise ValueError("Unknown feature requested %s" % feature)
992 raise ValueError("Unknown feature requested %s" % feature)
993
993
994 availableinterfaces = frozenset(featureinterfaces[feature])
994 availableinterfaces = frozenset(featureinterfaces[feature])
995 if alldefaults > availableinterfaces:
995 if alldefaults > availableinterfaces:
996 # Programming error, not user error. We need a use case to
996 # Programming error, not user error. We need a use case to
997 # define the right thing to do here.
997 # define the right thing to do here.
998 raise ValueError(
998 raise ValueError(
999 "Feature %s does not handle all default interfaces" %
999 "Feature %s does not handle all default interfaces" %
1000 feature)
1000 feature)
1001
1001
1002 if self.plain():
1002 if self.plain():
1003 return "text"
1003 return "text"
1004
1004
1005 # Default interface for all the features
1005 # Default interface for all the features
1006 defaultinterface = "text"
1006 defaultinterface = "text"
1007 i = self.config("ui", "interface", None)
1007 i = self.config("ui", "interface", None)
1008 if i in alldefaults:
1008 if i in alldefaults:
1009 defaultinterface = i
1009 defaultinterface = i
1010
1010
1011 choseninterface = defaultinterface
1011 choseninterface = defaultinterface
1012 f = self.config("ui", "interface.%s" % feature, None)
1012 f = self.config("ui", "interface.%s" % feature, None)
1013 if f in availableinterfaces:
1013 if f in availableinterfaces:
1014 choseninterface = f
1014 choseninterface = f
1015
1015
1016 if i is not None and defaultinterface != i:
1016 if i is not None and defaultinterface != i:
1017 if f is not None:
1017 if f is not None:
1018 self.warn(_("invalid value for ui.interface: %s\n") %
1018 self.warn(_("invalid value for ui.interface: %s\n") %
1019 (i,))
1019 (i,))
1020 else:
1020 else:
1021 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
1021 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
1022 (i, choseninterface))
1022 (i, choseninterface))
1023 if f is not None and choseninterface != f:
1023 if f is not None and choseninterface != f:
1024 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
1024 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
1025 (feature, f, choseninterface))
1025 (feature, f, choseninterface))
1026
1026
1027 return choseninterface
1027 return choseninterface
1028
1028
1029 def interactive(self):
1029 def interactive(self):
1030 '''is interactive input allowed?
1030 '''is interactive input allowed?
1031
1031
1032 An interactive session is a session where input can be reasonably read
1032 An interactive session is a session where input can be reasonably read
1033 from `sys.stdin'. If this function returns false, any attempt to read
1033 from `sys.stdin'. If this function returns false, any attempt to read
1034 from stdin should fail with an error, unless a sensible default has been
1034 from stdin should fail with an error, unless a sensible default has been
1035 specified.
1035 specified.
1036
1036
1037 Interactiveness is triggered by the value of the `ui.interactive'
1037 Interactiveness is triggered by the value of the `ui.interactive'
1038 configuration variable or - if it is unset - when `sys.stdin' points
1038 configuration variable or - if it is unset - when `sys.stdin' points
1039 to a terminal device.
1039 to a terminal device.
1040
1040
1041 This function refers to input only; for output, see `ui.formatted()'.
1041 This function refers to input only; for output, see `ui.formatted()'.
1042 '''
1042 '''
1043 i = self.configbool("ui", "interactive", None)
1043 i = self.configbool("ui", "interactive", None)
1044 if i is None:
1044 if i is None:
1045 # some environments replace stdin without implementing isatty
1045 # some environments replace stdin without implementing isatty
1046 # usually those are non-interactive
1046 # usually those are non-interactive
1047 return self._isatty(self.fin)
1047 return self._isatty(self.fin)
1048
1048
1049 return i
1049 return i
1050
1050
1051 def termwidth(self):
1051 def termwidth(self):
1052 '''how wide is the terminal in columns?
1052 '''how wide is the terminal in columns?
1053 '''
1053 '''
1054 if 'COLUMNS' in encoding.environ:
1054 if 'COLUMNS' in encoding.environ:
1055 try:
1055 try:
1056 return int(encoding.environ['COLUMNS'])
1056 return int(encoding.environ['COLUMNS'])
1057 except ValueError:
1057 except ValueError:
1058 pass
1058 pass
1059 return scmutil.termsize(self)[0]
1059 return scmutil.termsize(self)[0]
1060
1060
1061 def formatted(self):
1061 def formatted(self):
1062 '''should formatted output be used?
1062 '''should formatted output be used?
1063
1063
1064 It is often desirable to format the output to suite the output medium.
1064 It is often desirable to format the output to suite the output medium.
1065 Examples of this are truncating long lines or colorizing messages.
1065 Examples of this are truncating long lines or colorizing messages.
1066 However, this is not often not desirable when piping output into other
1066 However, this is not often not desirable when piping output into other
1067 utilities, e.g. `grep'.
1067 utilities, e.g. `grep'.
1068
1068
1069 Formatted output is triggered by the value of the `ui.formatted'
1069 Formatted output is triggered by the value of the `ui.formatted'
1070 configuration variable or - if it is unset - when `sys.stdout' points
1070 configuration variable or - if it is unset - when `sys.stdout' points
1071 to a terminal device. Please note that `ui.formatted' should be
1071 to a terminal device. Please note that `ui.formatted' should be
1072 considered an implementation detail; it is not intended for use outside
1072 considered an implementation detail; it is not intended for use outside
1073 Mercurial or its extensions.
1073 Mercurial or its extensions.
1074
1074
1075 This function refers to output only; for input, see `ui.interactive()'.
1075 This function refers to output only; for input, see `ui.interactive()'.
1076 This function always returns false when in plain mode, see `ui.plain()'.
1076 This function always returns false when in plain mode, see `ui.plain()'.
1077 '''
1077 '''
1078 if self.plain():
1078 if self.plain():
1079 return False
1079 return False
1080
1080
1081 i = self.configbool("ui", "formatted", None)
1081 i = self.configbool("ui", "formatted", None)
1082 if i is None:
1082 if i is None:
1083 # some environments replace stdout without implementing isatty
1083 # some environments replace stdout without implementing isatty
1084 # usually those are non-interactive
1084 # usually those are non-interactive
1085 return self._isatty(self.fout)
1085 return self._isatty(self.fout)
1086
1086
1087 return i
1087 return i
1088
1088
1089 def _readline(self, prompt=''):
1089 def _readline(self, prompt=''):
1090 if self._isatty(self.fin):
1090 if self._isatty(self.fin):
1091 try:
1091 try:
1092 # magically add command line editing support, where
1092 # magically add command line editing support, where
1093 # available
1093 # available
1094 import readline
1094 import readline
1095 # force demandimport to really load the module
1095 # force demandimport to really load the module
1096 readline.read_history_file
1096 readline.read_history_file
1097 # windows sometimes raises something other than ImportError
1097 # windows sometimes raises something other than ImportError
1098 except Exception:
1098 except Exception:
1099 pass
1099 pass
1100
1100
1101 # call write() so output goes through subclassed implementation
1101 # call write() so output goes through subclassed implementation
1102 # e.g. color extension on Windows
1102 # e.g. color extension on Windows
1103 self.write(prompt, prompt=True)
1103 self.write(prompt, prompt=True)
1104
1104
1105 # instead of trying to emulate raw_input, swap (self.fin,
1105 # instead of trying to emulate raw_input, swap (self.fin,
1106 # self.fout) with (sys.stdin, sys.stdout)
1106 # self.fout) with (sys.stdin, sys.stdout)
1107 oldin = sys.stdin
1107 oldin = sys.stdin
1108 oldout = sys.stdout
1108 oldout = sys.stdout
1109 sys.stdin = self.fin
1109 sys.stdin = self.fin
1110 sys.stdout = self.fout
1110 sys.stdout = self.fout
1111 # prompt ' ' must exist; otherwise readline may delete entire line
1111 # prompt ' ' must exist; otherwise readline may delete entire line
1112 # - http://bugs.python.org/issue12833
1112 # - http://bugs.python.org/issue12833
1113 with self.timeblockedsection('stdio'):
1113 with self.timeblockedsection('stdio'):
1114 line = raw_input(' ')
1114 line = raw_input(' ')
1115 sys.stdin = oldin
1115 sys.stdin = oldin
1116 sys.stdout = oldout
1116 sys.stdout = oldout
1117
1117
1118 # When stdin is in binary mode on Windows, it can cause
1118 # When stdin is in binary mode on Windows, it can cause
1119 # raw_input() to emit an extra trailing carriage return
1119 # raw_input() to emit an extra trailing carriage return
1120 if os.linesep == '\r\n' and line and line[-1] == '\r':
1120 if os.linesep == '\r\n' and line and line[-1] == '\r':
1121 line = line[:-1]
1121 line = line[:-1]
1122 return line
1122 return line
1123
1123
1124 def prompt(self, msg, default="y"):
1124 def prompt(self, msg, default="y"):
1125 """Prompt user with msg, read response.
1125 """Prompt user with msg, read response.
1126 If ui is not interactive, the default is returned.
1126 If ui is not interactive, the default is returned.
1127 """
1127 """
1128 if not self.interactive():
1128 if not self.interactive():
1129 self.write(msg, ' ', default or '', "\n")
1129 self.write(msg, ' ', default or '', "\n")
1130 return default
1130 return default
1131 try:
1131 try:
1132 r = self._readline(self.label(msg, 'ui.prompt'))
1132 r = self._readline(self.label(msg, 'ui.prompt'))
1133 if not r:
1133 if not r:
1134 r = default
1134 r = default
1135 if self.configbool('ui', 'promptecho'):
1135 if self.configbool('ui', 'promptecho'):
1136 self.write(r, "\n")
1136 self.write(r, "\n")
1137 return r
1137 return r
1138 except EOFError:
1138 except EOFError:
1139 raise error.ResponseExpected()
1139 raise error.ResponseExpected()
1140
1140
1141 @staticmethod
1141 @staticmethod
1142 def extractchoices(prompt):
1142 def extractchoices(prompt):
1143 """Extract prompt message and list of choices from specified prompt.
1143 """Extract prompt message and list of choices from specified prompt.
1144
1144
1145 This returns tuple "(message, choices)", and "choices" is the
1145 This returns tuple "(message, choices)", and "choices" is the
1146 list of tuple "(response character, text without &)".
1146 list of tuple "(response character, text without &)".
1147
1147
1148 >>> ui.extractchoices("awake? $$ &Yes $$ &No")
1148 >>> ui.extractchoices("awake? $$ &Yes $$ &No")
1149 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1149 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1150 >>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
1150 >>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
1151 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1151 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1152 >>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
1152 >>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
1153 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1153 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1154 """
1154 """
1155
1155
1156 # Sadly, the prompt string may have been built with a filename
1156 # Sadly, the prompt string may have been built with a filename
1157 # containing "$$" so let's try to find the first valid-looking
1157 # containing "$$" so let's try to find the first valid-looking
1158 # prompt to start parsing. Sadly, we also can't rely on
1158 # prompt to start parsing. Sadly, we also can't rely on
1159 # choices containing spaces, ASCII, or basically anything
1159 # choices containing spaces, ASCII, or basically anything
1160 # except an ampersand followed by a character.
1160 # except an ampersand followed by a character.
1161 m = re.match(r'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
1161 m = re.match(r'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
1162 msg = m.group(1)
1162 msg = m.group(1)
1163 choices = [p.strip(' ') for p in m.group(2).split('$$')]
1163 choices = [p.strip(' ') for p in m.group(2).split('$$')]
1164 return (msg,
1164 return (msg,
1165 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
1165 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
1166 for s in choices])
1166 for s in choices])
1167
1167
1168 def promptchoice(self, prompt, default=0):
1168 def promptchoice(self, prompt, default=0):
1169 """Prompt user with a message, read response, and ensure it matches
1169 """Prompt user with a message, read response, and ensure it matches
1170 one of the provided choices. The prompt is formatted as follows:
1170 one of the provided choices. The prompt is formatted as follows:
1171
1171
1172 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1172 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1173
1173
1174 The index of the choice is returned. Responses are case
1174 The index of the choice is returned. Responses are case
1175 insensitive. If ui is not interactive, the default is
1175 insensitive. If ui is not interactive, the default is
1176 returned.
1176 returned.
1177 """
1177 """
1178
1178
1179 msg, choices = self.extractchoices(prompt)
1179 msg, choices = self.extractchoices(prompt)
1180 resps = [r for r, t in choices]
1180 resps = [r for r, t in choices]
1181 while True:
1181 while True:
1182 r = self.prompt(msg, resps[default])
1182 r = self.prompt(msg, resps[default])
1183 if r.lower() in resps:
1183 if r.lower() in resps:
1184 return resps.index(r.lower())
1184 return resps.index(r.lower())
1185 self.write(_("unrecognized response\n"))
1185 self.write(_("unrecognized response\n"))
1186
1186
1187 def getpass(self, prompt=None, default=None):
1187 def getpass(self, prompt=None, default=None):
1188 if not self.interactive():
1188 if not self.interactive():
1189 return default
1189 return default
1190 try:
1190 try:
1191 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1191 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1192 # disable getpass() only if explicitly specified. it's still valid
1192 # disable getpass() only if explicitly specified. it's still valid
1193 # to interact with tty even if fin is not a tty.
1193 # to interact with tty even if fin is not a tty.
1194 with self.timeblockedsection('stdio'):
1194 with self.timeblockedsection('stdio'):
1195 if self.configbool('ui', 'nontty'):
1195 if self.configbool('ui', 'nontty'):
1196 l = self.fin.readline()
1196 l = self.fin.readline()
1197 if not l:
1197 if not l:
1198 raise EOFError
1198 raise EOFError
1199 return l.rstrip('\n')
1199 return l.rstrip('\n')
1200 else:
1200 else:
1201 return getpass.getpass('')
1201 return getpass.getpass('')
1202 except EOFError:
1202 except EOFError:
1203 raise error.ResponseExpected()
1203 raise error.ResponseExpected()
1204 def status(self, *msg, **opts):
1204 def status(self, *msg, **opts):
1205 '''write status message to output (if ui.quiet is False)
1205 '''write status message to output (if ui.quiet is False)
1206
1206
1207 This adds an output label of "ui.status".
1207 This adds an output label of "ui.status".
1208 '''
1208 '''
1209 if not self.quiet:
1209 if not self.quiet:
1210 opts['label'] = opts.get('label', '') + ' ui.status'
1210 opts['label'] = opts.get('label', '') + ' ui.status'
1211 self.write(*msg, **opts)
1211 self.write(*msg, **opts)
1212 def warn(self, *msg, **opts):
1212 def warn(self, *msg, **opts):
1213 '''write warning message to output (stderr)
1213 '''write warning message to output (stderr)
1214
1214
1215 This adds an output label of "ui.warning".
1215 This adds an output label of "ui.warning".
1216 '''
1216 '''
1217 opts['label'] = opts.get('label', '') + ' ui.warning'
1217 opts['label'] = opts.get('label', '') + ' ui.warning'
1218 self.write_err(*msg, **opts)
1218 self.write_err(*msg, **opts)
1219 def note(self, *msg, **opts):
1219 def note(self, *msg, **opts):
1220 '''write note to output (if ui.verbose is True)
1220 '''write note to output (if ui.verbose is True)
1221
1221
1222 This adds an output label of "ui.note".
1222 This adds an output label of "ui.note".
1223 '''
1223 '''
1224 if self.verbose:
1224 if self.verbose:
1225 opts['label'] = opts.get('label', '') + ' ui.note'
1225 opts['label'] = opts.get('label', '') + ' ui.note'
1226 self.write(*msg, **opts)
1226 self.write(*msg, **opts)
1227 def debug(self, *msg, **opts):
1227 def debug(self, *msg, **opts):
1228 '''write debug message to output (if ui.debugflag is True)
1228 '''write debug message to output (if ui.debugflag is True)
1229
1229
1230 This adds an output label of "ui.debug".
1230 This adds an output label of "ui.debug".
1231 '''
1231 '''
1232 if self.debugflag:
1232 if self.debugflag:
1233 opts['label'] = opts.get('label', '') + ' ui.debug'
1233 opts['label'] = opts.get('label', '') + ' ui.debug'
1234 self.write(*msg, **opts)
1234 self.write(*msg, **opts)
1235
1235
1236 def edit(self, text, user, extra=None, editform=None, pending=None,
1236 def edit(self, text, user, extra=None, editform=None, pending=None,
1237 repopath=None):
1237 repopath=None):
1238 extra_defaults = {
1238 extra_defaults = {
1239 'prefix': 'editor',
1239 'prefix': 'editor',
1240 'suffix': '.txt',
1240 'suffix': '.txt',
1241 }
1241 }
1242 if extra is not None:
1242 if extra is not None:
1243 extra_defaults.update(extra)
1243 extra_defaults.update(extra)
1244 extra = extra_defaults
1244 extra = extra_defaults
1245
1245
1246 rdir = None
1246 rdir = None
1247 if self.configbool('experimental', 'editortmpinhg'):
1247 if self.configbool('experimental', 'editortmpinhg'):
1248 rdir = repopath
1248 rdir = repopath
1249 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1249 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1250 suffix=extra['suffix'], text=True,
1250 suffix=extra['suffix'], text=True,
1251 dir=rdir)
1251 dir=rdir)
1252 try:
1252 try:
1253 f = os.fdopen(fd, pycompat.sysstr("w"))
1253 f = os.fdopen(fd, pycompat.sysstr("w"))
1254 f.write(text)
1254 f.write(text)
1255 f.close()
1255 f.close()
1256
1256
1257 environ = {'HGUSER': user}
1257 environ = {'HGUSER': user}
1258 if 'transplant_source' in extra:
1258 if 'transplant_source' in extra:
1259 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1259 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1260 for label in ('intermediate-source', 'source', 'rebase_source'):
1260 for label in ('intermediate-source', 'source', 'rebase_source'):
1261 if label in extra:
1261 if label in extra:
1262 environ.update({'HGREVISION': extra[label]})
1262 environ.update({'HGREVISION': extra[label]})
1263 break
1263 break
1264 if editform:
1264 if editform:
1265 environ.update({'HGEDITFORM': editform})
1265 environ.update({'HGEDITFORM': editform})
1266 if pending:
1266 if pending:
1267 environ.update({'HG_PENDING': pending})
1267 environ.update({'HG_PENDING': pending})
1268
1268
1269 editor = self.geteditor()
1269 editor = self.geteditor()
1270
1270
1271 self.system("%s \"%s\"" % (editor, name),
1271 self.system("%s \"%s\"" % (editor, name),
1272 environ=environ,
1272 environ=environ,
1273 onerr=error.Abort, errprefix=_("edit failed"),
1273 onerr=error.Abort, errprefix=_("edit failed"),
1274 blockedtag='editor')
1274 blockedtag='editor')
1275
1275
1276 f = open(name)
1276 f = open(name)
1277 t = f.read()
1277 t = f.read()
1278 f.close()
1278 f.close()
1279 finally:
1279 finally:
1280 os.unlink(name)
1280 os.unlink(name)
1281
1281
1282 return t
1282 return t
1283
1283
1284 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None,
1284 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None,
1285 blockedtag=None):
1285 blockedtag=None):
1286 '''execute shell command with appropriate output stream. command
1286 '''execute shell command with appropriate output stream. command
1287 output will be redirected if fout is not stdout.
1287 output will be redirected if fout is not stdout.
1288
1288
1289 if command fails and onerr is None, return status, else raise onerr
1289 if command fails and onerr is None, return status, else raise onerr
1290 object as exception.
1290 object as exception.
1291 '''
1291 '''
1292 if blockedtag is None:
1292 if blockedtag is None:
1293 blockedtag = 'unknown_system_' + cmd.translate(None, _keepalnum)
1293 blockedtag = 'unknown_system_' + cmd.translate(None, _keepalnum)
1294 out = self.fout
1294 out = self.fout
1295 if any(s[1] for s in self._bufferstates):
1295 if any(s[1] for s in self._bufferstates):
1296 out = self
1296 out = self
1297 with self.timeblockedsection(blockedtag):
1297 with self.timeblockedsection(blockedtag):
1298 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1298 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1299 if rc and onerr:
1299 if rc and onerr:
1300 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
1300 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
1301 util.explainexit(rc)[0])
1301 util.explainexit(rc)[0])
1302 if errprefix:
1302 if errprefix:
1303 errmsg = '%s: %s' % (errprefix, errmsg)
1303 errmsg = '%s: %s' % (errprefix, errmsg)
1304 raise onerr(errmsg)
1304 raise onerr(errmsg)
1305 return rc
1305 return rc
1306
1306
1307 def _runsystem(self, cmd, environ, cwd, out):
1307 def _runsystem(self, cmd, environ, cwd, out):
1308 """actually execute the given shell command (can be overridden by
1308 """actually execute the given shell command (can be overridden by
1309 extensions like chg)"""
1309 extensions like chg)"""
1310 return util.system(cmd, environ=environ, cwd=cwd, out=out)
1310 return util.system(cmd, environ=environ, cwd=cwd, out=out)
1311
1311
1312 def traceback(self, exc=None, force=False):
1312 def traceback(self, exc=None, force=False):
1313 '''print exception traceback if traceback printing enabled or forced.
1313 '''print exception traceback if traceback printing enabled or forced.
1314 only to call in exception handler. returns true if traceback
1314 only to call in exception handler. returns true if traceback
1315 printed.'''
1315 printed.'''
1316 if self.tracebackflag or force:
1316 if self.tracebackflag or force:
1317 if exc is None:
1317 if exc is None:
1318 exc = sys.exc_info()
1318 exc = sys.exc_info()
1319 cause = getattr(exc[1], 'cause', None)
1319 cause = getattr(exc[1], 'cause', None)
1320
1320
1321 if cause is not None:
1321 if cause is not None:
1322 causetb = traceback.format_tb(cause[2])
1322 causetb = traceback.format_tb(cause[2])
1323 exctb = traceback.format_tb(exc[2])
1323 exctb = traceback.format_tb(exc[2])
1324 exconly = traceback.format_exception_only(cause[0], cause[1])
1324 exconly = traceback.format_exception_only(cause[0], cause[1])
1325
1325
1326 # exclude frame where 'exc' was chained and rethrown from exctb
1326 # exclude frame where 'exc' was chained and rethrown from exctb
1327 self.write_err('Traceback (most recent call last):\n',
1327 self.write_err('Traceback (most recent call last):\n',
1328 ''.join(exctb[:-1]),
1328 ''.join(exctb[:-1]),
1329 ''.join(causetb),
1329 ''.join(causetb),
1330 ''.join(exconly))
1330 ''.join(exconly))
1331 else:
1331 else:
1332 output = traceback.format_exception(exc[0], exc[1], exc[2])
1332 output = traceback.format_exception(exc[0], exc[1], exc[2])
1333 self.write_err(''.join(output))
1333 self.write_err(''.join(output))
1334 return self.tracebackflag or force
1334 return self.tracebackflag or force
1335
1335
1336 def geteditor(self):
1336 def geteditor(self):
1337 '''return editor to use'''
1337 '''return editor to use'''
1338 if pycompat.sysplatform == 'plan9':
1338 if pycompat.sysplatform == 'plan9':
1339 # vi is the MIPS instruction simulator on Plan 9. We
1339 # vi is the MIPS instruction simulator on Plan 9. We
1340 # instead default to E to plumb commit messages to
1340 # instead default to E to plumb commit messages to
1341 # avoid confusion.
1341 # avoid confusion.
1342 editor = 'E'
1342 editor = 'E'
1343 else:
1343 else:
1344 editor = 'vi'
1344 editor = 'vi'
1345 return (encoding.environ.get("HGEDITOR") or
1345 return (encoding.environ.get("HGEDITOR") or
1346 self.config("ui", "editor") or
1346 self.config("ui", "editor") or
1347 encoding.environ.get("VISUAL") or
1347 encoding.environ.get("VISUAL") or
1348 encoding.environ.get("EDITOR", editor))
1348 encoding.environ.get("EDITOR", editor))
1349
1349
1350 @util.propertycache
1350 @util.propertycache
1351 def _progbar(self):
1351 def _progbar(self):
1352 """setup the progbar singleton to the ui object"""
1352 """setup the progbar singleton to the ui object"""
1353 if (self.quiet or self.debugflag
1353 if (self.quiet or self.debugflag
1354 or self.configbool('progress', 'disable', False)
1354 or self.configbool('progress', 'disable', False)
1355 or not progress.shouldprint(self)):
1355 or not progress.shouldprint(self)):
1356 return None
1356 return None
1357 return getprogbar(self)
1357 return getprogbar(self)
1358
1358
1359 def _progclear(self):
1359 def _progclear(self):
1360 """clear progress bar output if any. use it before any output"""
1360 """clear progress bar output if any. use it before any output"""
1361 if '_progbar' not in vars(self): # nothing loaded yet
1361 if '_progbar' not in vars(self): # nothing loaded yet
1362 return
1362 return
1363 if self._progbar is not None and self._progbar.printed:
1363 if self._progbar is not None and self._progbar.printed:
1364 self._progbar.clear()
1364 self._progbar.clear()
1365
1365
1366 def progress(self, topic, pos, item="", unit="", total=None):
1366 def progress(self, topic, pos, item="", unit="", total=None):
1367 '''show a progress message
1367 '''show a progress message
1368
1368
1369 By default a textual progress bar will be displayed if an operation
1369 By default a textual progress bar will be displayed if an operation
1370 takes too long. 'topic' is the current operation, 'item' is a
1370 takes too long. 'topic' is the current operation, 'item' is a
1371 non-numeric marker of the current position (i.e. the currently
1371 non-numeric marker of the current position (i.e. the currently
1372 in-process file), 'pos' is the current numeric position (i.e.
1372 in-process file), 'pos' is the current numeric position (i.e.
1373 revision, bytes, etc.), unit is a corresponding unit label,
1373 revision, bytes, etc.), unit is a corresponding unit label,
1374 and total is the highest expected pos.
1374 and total is the highest expected pos.
1375
1375
1376 Multiple nested topics may be active at a time.
1376 Multiple nested topics may be active at a time.
1377
1377
1378 All topics should be marked closed by setting pos to None at
1378 All topics should be marked closed by setting pos to None at
1379 termination.
1379 termination.
1380 '''
1380 '''
1381 if self._progbar is not None:
1381 if self._progbar is not None:
1382 self._progbar.progress(topic, pos, item=item, unit=unit,
1382 self._progbar.progress(topic, pos, item=item, unit=unit,
1383 total=total)
1383 total=total)
1384 if pos is None or not self.configbool('progress', 'debug'):
1384 if pos is None or not self.configbool('progress', 'debug'):
1385 return
1385 return
1386
1386
1387 if unit:
1387 if unit:
1388 unit = ' ' + unit
1388 unit = ' ' + unit
1389 if item:
1389 if item:
1390 item = ' ' + item
1390 item = ' ' + item
1391
1391
1392 if total:
1392 if total:
1393 pct = 100.0 * pos / total
1393 pct = 100.0 * pos / total
1394 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
1394 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
1395 % (topic, item, pos, total, unit, pct))
1395 % (topic, item, pos, total, unit, pct))
1396 else:
1396 else:
1397 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
1397 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
1398
1398
1399 def log(self, service, *msg, **opts):
1399 def log(self, service, *msg, **opts):
1400 '''hook for logging facility extensions
1400 '''hook for logging facility extensions
1401
1401
1402 service should be a readily-identifiable subsystem, which will
1402 service should be a readily-identifiable subsystem, which will
1403 allow filtering.
1403 allow filtering.
1404
1404
1405 *msg should be a newline-terminated format string to log, and
1405 *msg should be a newline-terminated format string to log, and
1406 then any values to %-format into that format string.
1406 then any values to %-format into that format string.
1407
1407
1408 **opts currently has no defined meanings.
1408 **opts currently has no defined meanings.
1409 '''
1409 '''
1410
1410
1411 def label(self, msg, label):
1411 def label(self, msg, label):
1412 '''style msg based on supplied label
1412 '''style msg based on supplied label
1413
1413
1414 If some color mode is enabled, this will add the necessary control
1414 If some color mode is enabled, this will add the necessary control
1415 characters to apply such color. In addition, 'debug' color mode adds
1415 characters to apply such color. In addition, 'debug' color mode adds
1416 markup showing which label affects a piece of text.
1416 markup showing which label affects a piece of text.
1417
1417
1418 ui.write(s, 'label') is equivalent to
1418 ui.write(s, 'label') is equivalent to
1419 ui.write(ui.label(s, 'label')).
1419 ui.write(ui.label(s, 'label')).
1420 '''
1420 '''
1421 if self._colormode is not None:
1421 if self._colormode is not None:
1422 return color.colorlabel(self, msg, label)
1422 return color.colorlabel(self, msg, label)
1423 return msg
1423 return msg
1424
1424
1425 def develwarn(self, msg, stacklevel=1, config=None):
1425 def develwarn(self, msg, stacklevel=1, config=None):
1426 """issue a developer warning message
1426 """issue a developer warning message
1427
1427
1428 Use 'stacklevel' to report the offender some layers further up in the
1428 Use 'stacklevel' to report the offender some layers further up in the
1429 stack.
1429 stack.
1430 """
1430 """
1431 if not self.configbool('devel', 'all-warnings'):
1431 if not self.configbool('devel', 'all-warnings'):
1432 if config is not None and not self.configbool('devel', config):
1432 if config is not None and not self.configbool('devel', config):
1433 return
1433 return
1434 msg = 'devel-warn: ' + msg
1434 msg = 'devel-warn: ' + msg
1435 stacklevel += 1 # get in develwarn
1435 stacklevel += 1 # get in develwarn
1436 if self.tracebackflag:
1436 if self.tracebackflag:
1437 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1437 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1438 self.log('develwarn', '%s at:\n%s' %
1438 self.log('develwarn', '%s at:\n%s' %
1439 (msg, ''.join(util.getstackframes(stacklevel))))
1439 (msg, ''.join(util.getstackframes(stacklevel))))
1440 else:
1440 else:
1441 curframe = inspect.currentframe()
1441 curframe = inspect.currentframe()
1442 calframe = inspect.getouterframes(curframe, 2)
1442 calframe = inspect.getouterframes(curframe, 2)
1443 self.write_err('%s at: %s:%s (%s)\n'
1443 self.write_err('%s at: %s:%s (%s)\n'
1444 % ((msg,) + calframe[stacklevel][1:4]))
1444 % ((msg,) + calframe[stacklevel][1:4]))
1445 self.log('develwarn', '%s at: %s:%s (%s)\n',
1445 self.log('develwarn', '%s at: %s:%s (%s)\n',
1446 msg, *calframe[stacklevel][1:4])
1446 msg, *calframe[stacklevel][1:4])
1447 curframe = calframe = None # avoid cycles
1447 curframe = calframe = None # avoid cycles
1448
1448
1449 def deprecwarn(self, msg, version):
1449 def deprecwarn(self, msg, version):
1450 """issue a deprecation warning
1450 """issue a deprecation warning
1451
1451
1452 - msg: message explaining what is deprecated and how to upgrade,
1452 - msg: message explaining what is deprecated and how to upgrade,
1453 - version: last version where the API will be supported,
1453 - version: last version where the API will be supported,
1454 """
1454 """
1455 if not (self.configbool('devel', 'all-warnings')
1455 if not (self.configbool('devel', 'all-warnings')
1456 or self.configbool('devel', 'deprec-warn')):
1456 or self.configbool('devel', 'deprec-warn')):
1457 return
1457 return
1458 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1458 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1459 " update your code.)") % version
1459 " update your code.)") % version
1460 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1460 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1461
1461
1462 def exportableenviron(self):
1462 def exportableenviron(self):
1463 """The environment variables that are safe to export, e.g. through
1463 """The environment variables that are safe to export, e.g. through
1464 hgweb.
1464 hgweb.
1465 """
1465 """
1466 return self._exportableenviron
1466 return self._exportableenviron
1467
1467
1468 @contextlib.contextmanager
1468 @contextlib.contextmanager
1469 def configoverride(self, overrides, source=""):
1469 def configoverride(self, overrides, source=""):
1470 """Context manager for temporary config overrides
1470 """Context manager for temporary config overrides
1471 `overrides` must be a dict of the following structure:
1471 `overrides` must be a dict of the following structure:
1472 {(section, name) : value}"""
1472 {(section, name) : value}"""
1473 backups = {}
1473 backups = {}
1474 try:
1474 try:
1475 for (section, name), value in overrides.items():
1475 for (section, name), value in overrides.items():
1476 backups[(section, name)] = self.backupconfig(section, name)
1476 backups[(section, name)] = self.backupconfig(section, name)
1477 self.setconfig(section, name, value, source)
1477 self.setconfig(section, name, value, source)
1478 yield
1478 yield
1479 finally:
1479 finally:
1480 for __, backup in backups.items():
1480 for __, backup in backups.items():
1481 self.restoreconfig(backup)
1481 self.restoreconfig(backup)
1482 # just restoring ui.quiet config to the previous value is not enough
1482 # just restoring ui.quiet config to the previous value is not enough
1483 # as it does not update ui.quiet class member
1483 # as it does not update ui.quiet class member
1484 if ('ui', 'quiet') in overrides:
1484 if ('ui', 'quiet') in overrides:
1485 self.fixconfig(section='ui')
1485 self.fixconfig(section='ui')
1486
1486
1487 class paths(dict):
1487 class paths(dict):
1488 """Represents a collection of paths and their configs.
1488 """Represents a collection of paths and their configs.
1489
1489
1490 Data is initially derived from ui instances and the config files they have
1490 Data is initially derived from ui instances and the config files they have
1491 loaded.
1491 loaded.
1492 """
1492 """
1493 def __init__(self, ui):
1493 def __init__(self, ui):
1494 dict.__init__(self)
1494 dict.__init__(self)
1495
1495
1496 for name, loc in ui.configitems('paths', ignoresub=True):
1496 for name, loc in ui.configitems('paths', ignoresub=True):
1497 # No location is the same as not existing.
1497 # No location is the same as not existing.
1498 if not loc:
1498 if not loc:
1499 continue
1499 continue
1500 loc, sub = ui.configsuboptions('paths', name)
1500 loc, sub = ui.configsuboptions('paths', name)
1501 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1501 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1502
1502
1503 def getpath(self, name, default=None):
1503 def getpath(self, name, default=None):
1504 """Return a ``path`` from a string, falling back to default.
1504 """Return a ``path`` from a string, falling back to default.
1505
1505
1506 ``name`` can be a named path or locations. Locations are filesystem
1506 ``name`` can be a named path or locations. Locations are filesystem
1507 paths or URIs.
1507 paths or URIs.
1508
1508
1509 Returns None if ``name`` is not a registered path, a URI, or a local
1509 Returns None if ``name`` is not a registered path, a URI, or a local
1510 path to a repo.
1510 path to a repo.
1511 """
1511 """
1512 # Only fall back to default if no path was requested.
1512 # Only fall back to default if no path was requested.
1513 if name is None:
1513 if name is None:
1514 if not default:
1514 if not default:
1515 default = ()
1515 default = ()
1516 elif not isinstance(default, (tuple, list)):
1516 elif not isinstance(default, (tuple, list)):
1517 default = (default,)
1517 default = (default,)
1518 for k in default:
1518 for k in default:
1519 try:
1519 try:
1520 return self[k]
1520 return self[k]
1521 except KeyError:
1521 except KeyError:
1522 continue
1522 continue
1523 return None
1523 return None
1524
1524
1525 # Most likely empty string.
1525 # Most likely empty string.
1526 # This may need to raise in the future.
1526 # This may need to raise in the future.
1527 if not name:
1527 if not name:
1528 return None
1528 return None
1529
1529
1530 try:
1530 try:
1531 return self[name]
1531 return self[name]
1532 except KeyError:
1532 except KeyError:
1533 # Try to resolve as a local path or URI.
1533 # Try to resolve as a local path or URI.
1534 try:
1534 try:
1535 # We don't pass sub-options in, so no need to pass ui instance.
1535 # We don't pass sub-options in, so no need to pass ui instance.
1536 return path(None, None, rawloc=name)
1536 return path(None, None, rawloc=name)
1537 except ValueError:
1537 except ValueError:
1538 raise error.RepoError(_('repository %s does not exist') %
1538 raise error.RepoError(_('repository %s does not exist') %
1539 name)
1539 name)
1540
1540
1541 _pathsuboptions = {}
1541 _pathsuboptions = {}
1542
1542
1543 def pathsuboption(option, attr):
1543 def pathsuboption(option, attr):
1544 """Decorator used to declare a path sub-option.
1544 """Decorator used to declare a path sub-option.
1545
1545
1546 Arguments are the sub-option name and the attribute it should set on
1546 Arguments are the sub-option name and the attribute it should set on
1547 ``path`` instances.
1547 ``path`` instances.
1548
1548
1549 The decorated function will receive as arguments a ``ui`` instance,
1549 The decorated function will receive as arguments a ``ui`` instance,
1550 ``path`` instance, and the string value of this option from the config.
1550 ``path`` instance, and the string value of this option from the config.
1551 The function should return the value that will be set on the ``path``
1551 The function should return the value that will be set on the ``path``
1552 instance.
1552 instance.
1553
1553
1554 This decorator can be used to perform additional verification of
1554 This decorator can be used to perform additional verification of
1555 sub-options and to change the type of sub-options.
1555 sub-options and to change the type of sub-options.
1556 """
1556 """
1557 def register(func):
1557 def register(func):
1558 _pathsuboptions[option] = (attr, func)
1558 _pathsuboptions[option] = (attr, func)
1559 return func
1559 return func
1560 return register
1560 return register
1561
1561
1562 @pathsuboption('pushurl', 'pushloc')
1562 @pathsuboption('pushurl', 'pushloc')
1563 def pushurlpathoption(ui, path, value):
1563 def pushurlpathoption(ui, path, value):
1564 u = util.url(value)
1564 u = util.url(value)
1565 # Actually require a URL.
1565 # Actually require a URL.
1566 if not u.scheme:
1566 if not u.scheme:
1567 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1567 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1568 return None
1568 return None
1569
1569
1570 # Don't support the #foo syntax in the push URL to declare branch to
1570 # Don't support the #foo syntax in the push URL to declare branch to
1571 # push.
1571 # push.
1572 if u.fragment:
1572 if u.fragment:
1573 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1573 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1574 'ignoring)\n') % path.name)
1574 'ignoring)\n') % path.name)
1575 u.fragment = None
1575 u.fragment = None
1576
1576
1577 return str(u)
1577 return str(u)
1578
1578
1579 @pathsuboption('pushrev', 'pushrev')
1579 @pathsuboption('pushrev', 'pushrev')
1580 def pushrevpathoption(ui, path, value):
1580 def pushrevpathoption(ui, path, value):
1581 return value
1581 return value
1582
1582
1583 class path(object):
1583 class path(object):
1584 """Represents an individual path and its configuration."""
1584 """Represents an individual path and its configuration."""
1585
1585
1586 def __init__(self, ui, name, rawloc=None, suboptions=None):
1586 def __init__(self, ui, name, rawloc=None, suboptions=None):
1587 """Construct a path from its config options.
1587 """Construct a path from its config options.
1588
1588
1589 ``ui`` is the ``ui`` instance the path is coming from.
1589 ``ui`` is the ``ui`` instance the path is coming from.
1590 ``name`` is the symbolic name of the path.
1590 ``name`` is the symbolic name of the path.
1591 ``rawloc`` is the raw location, as defined in the config.
1591 ``rawloc`` is the raw location, as defined in the config.
1592 ``pushloc`` is the raw locations pushes should be made to.
1592 ``pushloc`` is the raw locations pushes should be made to.
1593
1593
1594 If ``name`` is not defined, we require that the location be a) a local
1594 If ``name`` is not defined, we require that the location be a) a local
1595 filesystem path with a .hg directory or b) a URL. If not,
1595 filesystem path with a .hg directory or b) a URL. If not,
1596 ``ValueError`` is raised.
1596 ``ValueError`` is raised.
1597 """
1597 """
1598 if not rawloc:
1598 if not rawloc:
1599 raise ValueError('rawloc must be defined')
1599 raise ValueError('rawloc must be defined')
1600
1600
1601 # Locations may define branches via syntax <base>#<branch>.
1601 # Locations may define branches via syntax <base>#<branch>.
1602 u = util.url(rawloc)
1602 u = util.url(rawloc)
1603 branch = None
1603 branch = None
1604 if u.fragment:
1604 if u.fragment:
1605 branch = u.fragment
1605 branch = u.fragment
1606 u.fragment = None
1606 u.fragment = None
1607
1607
1608 self.url = u
1608 self.url = u
1609 self.branch = branch
1609 self.branch = branch
1610
1610
1611 self.name = name
1611 self.name = name
1612 self.rawloc = rawloc
1612 self.rawloc = rawloc
1613 self.loc = str(u)
1613 self.loc = str(u)
1614
1614
1615 # When given a raw location but not a symbolic name, validate the
1615 # When given a raw location but not a symbolic name, validate the
1616 # location is valid.
1616 # location is valid.
1617 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1617 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1618 raise ValueError('location is not a URL or path to a local '
1618 raise ValueError('location is not a URL or path to a local '
1619 'repo: %s' % rawloc)
1619 'repo: %s' % rawloc)
1620
1620
1621 suboptions = suboptions or {}
1621 suboptions = suboptions or {}
1622
1622
1623 # Now process the sub-options. If a sub-option is registered, its
1623 # Now process the sub-options. If a sub-option is registered, its
1624 # attribute will always be present. The value will be None if there
1624 # attribute will always be present. The value will be None if there
1625 # was no valid sub-option.
1625 # was no valid sub-option.
1626 for suboption, (attr, func) in _pathsuboptions.iteritems():
1626 for suboption, (attr, func) in _pathsuboptions.iteritems():
1627 if suboption not in suboptions:
1627 if suboption not in suboptions:
1628 setattr(self, attr, None)
1628 setattr(self, attr, None)
1629 continue
1629 continue
1630
1630
1631 value = func(ui, self, suboptions[suboption])
1631 value = func(ui, self, suboptions[suboption])
1632 setattr(self, attr, value)
1632 setattr(self, attr, value)
1633
1633
1634 def _isvalidlocalpath(self, path):
1634 def _isvalidlocalpath(self, path):
1635 """Returns True if the given path is a potentially valid repository.
1635 """Returns True if the given path is a potentially valid repository.
1636 This is its own function so that extensions can change the definition of
1636 This is its own function so that extensions can change the definition of
1637 'valid' in this case (like when pulling from a git repo into a hg
1637 'valid' in this case (like when pulling from a git repo into a hg
1638 one)."""
1638 one)."""
1639 return os.path.isdir(os.path.join(path, '.hg'))
1639 return os.path.isdir(os.path.join(path, '.hg'))
1640
1640
1641 @property
1641 @property
1642 def suboptions(self):
1642 def suboptions(self):
1643 """Return sub-options and their values for this path.
1643 """Return sub-options and their values for this path.
1644
1644
1645 This is intended to be used for presentation purposes.
1645 This is intended to be used for presentation purposes.
1646 """
1646 """
1647 d = {}
1647 d = {}
1648 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1648 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1649 value = getattr(self, attr)
1649 value = getattr(self, attr)
1650 if value is not None:
1650 if value is not None:
1651 d[subopt] = value
1651 d[subopt] = value
1652 return d
1652 return d
1653
1653
1654 # we instantiate one globally shared progress bar to avoid
1654 # we instantiate one globally shared progress bar to avoid
1655 # competing progress bars when multiple UI objects get created
1655 # competing progress bars when multiple UI objects get created
1656 _progresssingleton = None
1656 _progresssingleton = None
1657
1657
1658 def getprogbar(ui):
1658 def getprogbar(ui):
1659 global _progresssingleton
1659 global _progresssingleton
1660 if _progresssingleton is None:
1660 if _progresssingleton is None:
1661 # passing 'ui' object to the singleton is fishy,
1661 # passing 'ui' object to the singleton is fishy,
1662 # this is how the extension used to work but feel free to rework it.
1662 # this is how the extension used to work but feel free to rework it.
1663 _progresssingleton = progress.progbar(ui)
1663 _progresssingleton = progress.progbar(ui)
1664 return _progresssingleton
1664 return _progresssingleton
@@ -1,224 +1,231 b''
1 # worker.py - master-slave parallelism support
1 # worker.py - master-slave parallelism support
2 #
2 #
3 # Copyright 2013 Facebook, Inc.
3 # Copyright 2013 Facebook, Inc.
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 errno
10 import errno
11 import os
11 import os
12 import signal
12 import signal
13 import sys
13 import sys
14
14
15 from .i18n import _
15 from .i18n import _
16 from . import (
16 from . import (
17 encoding,
17 encoding,
18 error,
18 error,
19 pycompat,
19 pycompat,
20 scmutil,
20 scmutil,
21 util,
21 util,
22 )
22 )
23
23
24 def countcpus():
24 def countcpus():
25 '''try to count the number of CPUs on the system'''
25 '''try to count the number of CPUs on the system'''
26
26
27 # posix
27 # posix
28 try:
28 try:
29 n = int(os.sysconf('SC_NPROCESSORS_ONLN'))
29 n = int(os.sysconf('SC_NPROCESSORS_ONLN'))
30 if n > 0:
30 if n > 0:
31 return n
31 return n
32 except (AttributeError, ValueError):
32 except (AttributeError, ValueError):
33 pass
33 pass
34
34
35 # windows
35 # windows
36 try:
36 try:
37 n = int(encoding.environ['NUMBER_OF_PROCESSORS'])
37 n = int(encoding.environ['NUMBER_OF_PROCESSORS'])
38 if n > 0:
38 if n > 0:
39 return n
39 return n
40 except (KeyError, ValueError):
40 except (KeyError, ValueError):
41 pass
41 pass
42
42
43 return 1
43 return 1
44
44
45 def _numworkers(ui):
45 def _numworkers(ui):
46 s = ui.config('worker', 'numcpus')
46 s = ui.config('worker', 'numcpus')
47 if s:
47 if s:
48 try:
48 try:
49 n = int(s)
49 n = int(s)
50 if n >= 1:
50 if n >= 1:
51 return n
51 return n
52 except ValueError:
52 except ValueError:
53 raise error.Abort(_('number of cpus must be an integer'))
53 raise error.Abort(_('number of cpus must be an integer'))
54 return min(max(countcpus(), 4), 32)
54 return min(max(countcpus(), 4), 32)
55
55
56 if pycompat.osname == 'posix':
56 if pycompat.osname == 'posix':
57 _startupcost = 0.01
57 _startupcost = 0.01
58 else:
58 else:
59 _startupcost = 1e30
59 _startupcost = 1e30
60
60
61 def worthwhile(ui, costperop, nops):
61 def worthwhile(ui, costperop, nops):
62 '''try to determine whether the benefit of multiple processes can
62 '''try to determine whether the benefit of multiple processes can
63 outweigh the cost of starting them'''
63 outweigh the cost of starting them'''
64 linear = costperop * nops
64 linear = costperop * nops
65 workers = _numworkers(ui)
65 workers = _numworkers(ui)
66 benefit = linear - (_startupcost * workers + linear / workers)
66 benefit = linear - (_startupcost * workers + linear / workers)
67 return benefit >= 0.15
67 return benefit >= 0.15
68
68
69 def worker(ui, costperarg, func, staticargs, args):
69 def worker(ui, costperarg, func, staticargs, args):
70 '''run a function, possibly in parallel in multiple worker
70 '''run a function, possibly in parallel in multiple worker
71 processes.
71 processes.
72
72
73 returns a progress iterator
73 returns a progress iterator
74
74
75 costperarg - cost of a single task
75 costperarg - cost of a single task
76
76
77 func - function to run
77 func - function to run
78
78
79 staticargs - arguments to pass to every invocation of the function
79 staticargs - arguments to pass to every invocation of the function
80
80
81 args - arguments to split into chunks, to pass to individual
81 args - arguments to split into chunks, to pass to individual
82 workers
82 workers
83 '''
83 '''
84 if worthwhile(ui, costperarg, len(args)):
84 if worthwhile(ui, costperarg, len(args)):
85 return _platformworker(ui, func, staticargs, args)
85 return _platformworker(ui, func, staticargs, args)
86 return func(*staticargs + (args,))
86 return func(*staticargs + (args,))
87
87
88 def _posixworker(ui, func, staticargs, args):
88 def _posixworker(ui, func, staticargs, args):
89 rfd, wfd = os.pipe()
89 rfd, wfd = os.pipe()
90 workers = _numworkers(ui)
90 workers = _numworkers(ui)
91 oldhandler = signal.getsignal(signal.SIGINT)
91 oldhandler = signal.getsignal(signal.SIGINT)
92 signal.signal(signal.SIGINT, signal.SIG_IGN)
92 signal.signal(signal.SIGINT, signal.SIG_IGN)
93 pids, problem = set(), [0]
93 pids, problem = set(), [0]
94 def killworkers():
94 def killworkers():
95 # unregister SIGCHLD handler as all children will be killed. This
95 # unregister SIGCHLD handler as all children will be killed. This
96 # function shouldn't be interrupted by another SIGCHLD; otherwise pids
96 # function shouldn't be interrupted by another SIGCHLD; otherwise pids
97 # could be updated while iterating, which would cause inconsistency.
97 # could be updated while iterating, which would cause inconsistency.
98 signal.signal(signal.SIGCHLD, oldchldhandler)
98 signal.signal(signal.SIGCHLD, oldchldhandler)
99 # if one worker bails, there's no good reason to wait for the rest
99 # if one worker bails, there's no good reason to wait for the rest
100 for p in pids:
100 for p in pids:
101 try:
101 try:
102 os.kill(p, signal.SIGTERM)
102 os.kill(p, signal.SIGTERM)
103 except OSError as err:
103 except OSError as err:
104 if err.errno != errno.ESRCH:
104 if err.errno != errno.ESRCH:
105 raise
105 raise
106 def waitforworkers(blocking=True):
106 def waitforworkers(blocking=True):
107 for pid in pids.copy():
107 for pid in pids.copy():
108 p = st = 0
108 p = st = 0
109 while True:
109 while True:
110 try:
110 try:
111 p, st = os.waitpid(pid, (0 if blocking else os.WNOHANG))
111 p, st = os.waitpid(pid, (0 if blocking else os.WNOHANG))
112 break
112 break
113 except OSError as e:
113 except OSError as e:
114 if e.errno == errno.EINTR:
114 if e.errno == errno.EINTR:
115 continue
115 continue
116 elif e.errno == errno.ECHILD:
116 elif e.errno == errno.ECHILD:
117 # child would already be reaped, but pids yet been
117 # child would already be reaped, but pids yet been
118 # updated (maybe interrupted just after waitpid)
118 # updated (maybe interrupted just after waitpid)
119 pids.discard(pid)
119 pids.discard(pid)
120 break
120 break
121 else:
121 else:
122 raise
122 raise
123 if p:
123 if not p:
124 pids.discard(p)
124 # skip subsequent steps, because child process should
125 st = _exitstatus(st)
125 # be still running in this case
126 continue
127 pids.discard(p)
128 st = _exitstatus(st)
126 if st and not problem[0]:
129 if st and not problem[0]:
127 problem[0] = st
130 problem[0] = st
128 def sigchldhandler(signum, frame):
131 def sigchldhandler(signum, frame):
129 waitforworkers(blocking=False)
132 waitforworkers(blocking=False)
130 if problem[0]:
133 if problem[0]:
131 killworkers()
134 killworkers()
132 oldchldhandler = signal.signal(signal.SIGCHLD, sigchldhandler)
135 oldchldhandler = signal.signal(signal.SIGCHLD, sigchldhandler)
133 for pargs in partition(args, workers):
136 for pargs in partition(args, workers):
134 pid = os.fork()
137 pid = os.fork()
135 if pid == 0:
138 if pid == 0:
136 signal.signal(signal.SIGINT, oldhandler)
139 signal.signal(signal.SIGINT, oldhandler)
137 signal.signal(signal.SIGCHLD, oldchldhandler)
140 signal.signal(signal.SIGCHLD, oldchldhandler)
138
141
139 def workerfunc():
142 def workerfunc():
140 os.close(rfd)
143 os.close(rfd)
141 for i, item in func(*(staticargs + (pargs,))):
144 for i, item in func(*(staticargs + (pargs,))):
142 os.write(wfd, '%d %s\n' % (i, item))
145 os.write(wfd, '%d %s\n' % (i, item))
143
146
144 # make sure we use os._exit in all code paths. otherwise the worker
147 # make sure we use os._exit in all code paths. otherwise the worker
145 # may do some clean-ups which could cause surprises like deadlock.
148 # may do some clean-ups which could cause surprises like deadlock.
146 # see sshpeer.cleanup for example.
149 # see sshpeer.cleanup for example.
147 try:
150 try:
148 scmutil.callcatch(ui, workerfunc)
151 try:
152 scmutil.callcatch(ui, workerfunc)
153 finally:
154 ui.flush()
149 except KeyboardInterrupt:
155 except KeyboardInterrupt:
150 os._exit(255)
156 os._exit(255)
151 except: # never return, therefore no re-raises
157 except: # never return, therefore no re-raises
152 try:
158 try:
153 ui.traceback()
159 ui.traceback()
160 ui.flush()
154 finally:
161 finally:
155 os._exit(255)
162 os._exit(255)
156 else:
163 else:
157 os._exit(0)
164 os._exit(0)
158 pids.add(pid)
165 pids.add(pid)
159 os.close(wfd)
166 os.close(wfd)
160 fp = os.fdopen(rfd, pycompat.sysstr('rb'), 0)
167 fp = os.fdopen(rfd, pycompat.sysstr('rb'), 0)
161 def cleanup():
168 def cleanup():
162 signal.signal(signal.SIGINT, oldhandler)
169 signal.signal(signal.SIGINT, oldhandler)
163 waitforworkers()
170 waitforworkers()
164 signal.signal(signal.SIGCHLD, oldchldhandler)
171 signal.signal(signal.SIGCHLD, oldchldhandler)
165 status = problem[0]
172 status = problem[0]
166 if status:
173 if status:
167 if status < 0:
174 if status < 0:
168 os.kill(os.getpid(), -status)
175 os.kill(os.getpid(), -status)
169 sys.exit(status)
176 sys.exit(status)
170 try:
177 try:
171 for line in util.iterfile(fp):
178 for line in util.iterfile(fp):
172 l = line.split(' ', 1)
179 l = line.split(' ', 1)
173 yield int(l[0]), l[1][:-1]
180 yield int(l[0]), l[1][:-1]
174 except: # re-raises
181 except: # re-raises
175 killworkers()
182 killworkers()
176 cleanup()
183 cleanup()
177 raise
184 raise
178 cleanup()
185 cleanup()
179
186
180 def _posixexitstatus(code):
187 def _posixexitstatus(code):
181 '''convert a posix exit status into the same form returned by
188 '''convert a posix exit status into the same form returned by
182 os.spawnv
189 os.spawnv
183
190
184 returns None if the process was stopped instead of exiting'''
191 returns None if the process was stopped instead of exiting'''
185 if os.WIFEXITED(code):
192 if os.WIFEXITED(code):
186 return os.WEXITSTATUS(code)
193 return os.WEXITSTATUS(code)
187 elif os.WIFSIGNALED(code):
194 elif os.WIFSIGNALED(code):
188 return -os.WTERMSIG(code)
195 return -os.WTERMSIG(code)
189
196
190 if pycompat.osname != 'nt':
197 if pycompat.osname != 'nt':
191 _platformworker = _posixworker
198 _platformworker = _posixworker
192 _exitstatus = _posixexitstatus
199 _exitstatus = _posixexitstatus
193
200
194 def partition(lst, nslices):
201 def partition(lst, nslices):
195 '''partition a list into N slices of roughly equal size
202 '''partition a list into N slices of roughly equal size
196
203
197 The current strategy takes every Nth element from the input. If
204 The current strategy takes every Nth element from the input. If
198 we ever write workers that need to preserve grouping in input
205 we ever write workers that need to preserve grouping in input
199 we should consider allowing callers to specify a partition strategy.
206 we should consider allowing callers to specify a partition strategy.
200
207
201 mpm is not a fan of this partitioning strategy when files are involved.
208 mpm is not a fan of this partitioning strategy when files are involved.
202 In his words:
209 In his words:
203
210
204 Single-threaded Mercurial makes a point of creating and visiting
211 Single-threaded Mercurial makes a point of creating and visiting
205 files in a fixed order (alphabetical). When creating files in order,
212 files in a fixed order (alphabetical). When creating files in order,
206 a typical filesystem is likely to allocate them on nearby regions on
213 a typical filesystem is likely to allocate them on nearby regions on
207 disk. Thus, when revisiting in the same order, locality is maximized
214 disk. Thus, when revisiting in the same order, locality is maximized
208 and various forms of OS and disk-level caching and read-ahead get a
215 and various forms of OS and disk-level caching and read-ahead get a
209 chance to work.
216 chance to work.
210
217
211 This effect can be quite significant on spinning disks. I discovered it
218 This effect can be quite significant on spinning disks. I discovered it
212 circa Mercurial v0.4 when revlogs were named by hashes of filenames.
219 circa Mercurial v0.4 when revlogs were named by hashes of filenames.
213 Tarring a repo and copying it to another disk effectively randomized
220 Tarring a repo and copying it to another disk effectively randomized
214 the revlog ordering on disk by sorting the revlogs by hash and suddenly
221 the revlog ordering on disk by sorting the revlogs by hash and suddenly
215 performance of my kernel checkout benchmark dropped by ~10x because the
222 performance of my kernel checkout benchmark dropped by ~10x because the
216 "working set" of sectors visited no longer fit in the drive's cache and
223 "working set" of sectors visited no longer fit in the drive's cache and
217 the workload switched from streaming to random I/O.
224 the workload switched from streaming to random I/O.
218
225
219 What we should really be doing is have workers read filenames from a
226 What we should really be doing is have workers read filenames from a
220 ordered queue. This preserves locality and also keeps any worker from
227 ordered queue. This preserves locality and also keeps any worker from
221 getting more than one file out of balance.
228 getting more than one file out of balance.
222 '''
229 '''
223 for i in range(nslices):
230 for i in range(nslices):
224 yield lst[i::nslices]
231 yield lst[i::nslices]
@@ -1,231 +1,231 b''
1 hide outer repo
1 hide outer repo
2 $ hg init
2 $ hg init
3
3
4 Use hgrc within $TESTTMP
4 Use hgrc within $TESTTMP
5
5
6 $ HGRCPATH=`pwd`/hgrc
6 $ HGRCPATH=`pwd`/hgrc
7 $ export HGRCPATH
7 $ export HGRCPATH
8
8
9 Use an alternate var for scribbling on hgrc to keep check-code from
9 Use an alternate var for scribbling on hgrc to keep check-code from
10 complaining about the important settings we may be overwriting:
10 complaining about the important settings we may be overwriting:
11
11
12 $ HGRC=`pwd`/hgrc
12 $ HGRC=`pwd`/hgrc
13 $ export HGRC
13 $ export HGRC
14
14
15 Basic syntax error
15 Basic syntax error
16
16
17 $ echo "invalid" > $HGRC
17 $ echo "invalid" > $HGRC
18 $ hg version
18 $ hg version
19 hg: parse error at $TESTTMP/hgrc:1: invalid
19 hg: parse error at $TESTTMP/hgrc:1: invalid
20 [255]
20 [255]
21 $ echo "" > $HGRC
21 $ echo "" > $HGRC
22
22
23 Issue1199: Can't use '%' in hgrc (eg url encoded username)
23 Issue1199: Can't use '%' in hgrc (eg url encoded username)
24
24
25 $ hg init "foo%bar"
25 $ hg init "foo%bar"
26 $ hg clone "foo%bar" foobar
26 $ hg clone "foo%bar" foobar
27 updating to branch default
27 updating to branch default
28 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 $ cd foobar
29 $ cd foobar
30 $ cat .hg/hgrc
30 $ cat .hg/hgrc
31 # example repository config (see 'hg help config' for more info)
31 # example repository config (see 'hg help config' for more info)
32 [paths]
32 [paths]
33 default = $TESTTMP/foo%bar (glob)
33 default = $TESTTMP/foo%bar (glob)
34
34
35 # path aliases to other clones of this repo in URLs or filesystem paths
35 # path aliases to other clones of this repo in URLs or filesystem paths
36 # (see 'hg help config.paths' for more info)
36 # (see 'hg help config.paths' for more info)
37 #
37 #
38 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
38 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
39 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
39 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
40 # my-clone = /home/jdoe/jdoes-clone
40 # my-clone = /home/jdoe/jdoes-clone
41
41
42 [ui]
42 [ui]
43 # name and email (local to this repository, optional), e.g.
43 # name and email (local to this repository, optional), e.g.
44 # username = Jane Doe <jdoe@example.com>
44 # username = Jane Doe <jdoe@example.com>
45 $ hg paths
45 $ hg paths
46 default = $TESTTMP/foo%bar (glob)
46 default = $TESTTMP/foo%bar (glob)
47 $ hg showconfig
47 $ hg showconfig
48 bundle.mainreporoot=$TESTTMP/foobar (glob)
48 bundle.mainreporoot=$TESTTMP/foobar (glob)
49 paths.default=$TESTTMP/foo%bar (glob)
49 paths.default=$TESTTMP/foo%bar (glob)
50 $ cd ..
50 $ cd ..
51
51
52 issue1829: wrong indentation
52 issue1829: wrong indentation
53
53
54 $ echo '[foo]' > $HGRC
54 $ echo '[foo]' > $HGRC
55 $ echo ' x = y' >> $HGRC
55 $ echo ' x = y' >> $HGRC
56 $ hg version
56 $ hg version
57 hg: parse error at $TESTTMP/hgrc:2: x = y
57 hg: parse error at $TESTTMP/hgrc:2: x = y
58 unexpected leading whitespace
58 unexpected leading whitespace
59 [255]
59 [255]
60
60
61 $ $PYTHON -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
61 $ $PYTHON -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
62 > > $HGRC
62 > > $HGRC
63 $ hg showconfig foo
63 $ hg showconfig foo
64 foo.bar=a\nb\nc\nde\nfg
64 foo.bar=a\nb\nc\nde\nfg
65 foo.baz=bif cb
65 foo.baz=bif cb
66
66
67 $ FAKEPATH=/path/to/nowhere
67 $ FAKEPATH=/path/to/nowhere
68 $ export FAKEPATH
68 $ export FAKEPATH
69 $ echo '%include $FAKEPATH/no-such-file' > $HGRC
69 $ echo '%include $FAKEPATH/no-such-file' > $HGRC
70 $ hg version
70 $ hg version
71 Mercurial Distributed SCM (version *) (glob)
71 Mercurial Distributed SCM (version *) (glob)
72 (see https://mercurial-scm.org for more information)
72 (see https://mercurial-scm.org for more information)
73
73
74 Copyright (C) 2005-* Matt Mackall and others (glob)
74 Copyright (C) 2005-* Matt Mackall and others (glob)
75 This is free software; see the source for copying conditions. There is NO
75 This is free software; see the source for copying conditions. There is NO
76 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
76 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
77 $ unset FAKEPATH
77 $ unset FAKEPATH
78
78
79 make sure global options given on the cmdline take precedence
79 make sure global options given on the cmdline take precedence
80
80
81 $ hg showconfig --config ui.verbose=True --quiet
81 $ hg showconfig --config ui.verbose=True --quiet
82 bundle.mainreporoot=$TESTTMP
82 bundle.mainreporoot=$TESTTMP
83 ui.verbose=False
83 ui.verbose=False
84 ui.debug=False
84 ui.debug=False
85 ui.quiet=True
85 ui.quiet=True
86
86
87 $ touch foobar/untracked
87 $ touch foobar/untracked
88 $ cat >> foobar/.hg/hgrc <<EOF
88 $ cat >> foobar/.hg/hgrc <<EOF
89 > [ui]
89 > [ui]
90 > verbose=True
90 > verbose=True
91 > EOF
91 > EOF
92 $ hg -R foobar st -q
92 $ hg -R foobar st -q
93
93
94 username expansion
94 username expansion
95
95
96 $ olduser=$HGUSER
96 $ olduser=$HGUSER
97 $ unset HGUSER
97 $ unset HGUSER
98
98
99 $ FAKEUSER='John Doe'
99 $ FAKEUSER='John Doe'
100 $ export FAKEUSER
100 $ export FAKEUSER
101 $ echo '[ui]' > $HGRC
101 $ echo '[ui]' > $HGRC
102 $ echo 'username = $FAKEUSER' >> $HGRC
102 $ echo 'username = $FAKEUSER' >> $HGRC
103
103
104 $ hg init usertest
104 $ hg init usertest
105 $ cd usertest
105 $ cd usertest
106 $ touch bar
106 $ touch bar
107 $ hg commit --addremove --quiet -m "added bar"
107 $ hg commit --addremove --quiet -m "added bar"
108 $ hg log --template "{author}\n"
108 $ hg log --template "{author}\n"
109 John Doe
109 John Doe
110 $ cd ..
110 $ cd ..
111
111
112 $ hg showconfig
112 $ hg showconfig
113 bundle.mainreporoot=$TESTTMP
113 bundle.mainreporoot=$TESTTMP
114 ui.username=$FAKEUSER
114 ui.username=$FAKEUSER
115
115
116 $ unset FAKEUSER
116 $ unset FAKEUSER
117 $ HGUSER=$olduser
117 $ HGUSER=$olduser
118 $ export HGUSER
118 $ export HGUSER
119
119
120 showconfig with multiple arguments
120 showconfig with multiple arguments
121
121
122 $ echo "[alias]" > $HGRC
122 $ echo "[alias]" > $HGRC
123 $ echo "log = log -g" >> $HGRC
123 $ echo "log = log -g" >> $HGRC
124 $ echo "[defaults]" >> $HGRC
124 $ echo "[defaults]" >> $HGRC
125 $ echo "identify = -n" >> $HGRC
125 $ echo "identify = -n" >> $HGRC
126 $ hg showconfig alias defaults
126 $ hg showconfig alias defaults
127 alias.log=log -g
127 alias.log=log -g
128 defaults.identify=-n
128 defaults.identify=-n
129 $ hg showconfig alias defaults.identify
129 $ hg showconfig alias defaults.identify
130 abort: only one config item permitted
130 abort: only one config item permitted
131 [255]
131 [255]
132 $ hg showconfig alias.log defaults.identify
132 $ hg showconfig alias.log defaults.identify
133 abort: only one config item permitted
133 abort: only one config item permitted
134 [255]
134 [255]
135
135
136 HGPLAIN
136 HGPLAIN
137
137
138 $ echo "[ui]" > $HGRC
138 $ echo "[ui]" > $HGRC
139 $ echo "debug=true" >> $HGRC
139 $ echo "debug=true" >> $HGRC
140 $ echo "fallbackencoding=ASCII" >> $HGRC
140 $ echo "fallbackencoding=ASCII" >> $HGRC
141 $ echo "quiet=true" >> $HGRC
141 $ echo "quiet=true" >> $HGRC
142 $ echo "slash=true" >> $HGRC
142 $ echo "slash=true" >> $HGRC
143 $ echo "traceback=true" >> $HGRC
143 $ echo "traceback=true" >> $HGRC
144 $ echo "verbose=true" >> $HGRC
144 $ echo "verbose=true" >> $HGRC
145 $ echo "style=~/.hgstyle" >> $HGRC
145 $ echo "style=~/.hgstyle" >> $HGRC
146 $ echo "logtemplate={node}" >> $HGRC
146 $ echo "logtemplate={node}" >> $HGRC
147 $ echo "[defaults]" >> $HGRC
147 $ echo "[defaults]" >> $HGRC
148 $ echo "identify=-n" >> $HGRC
148 $ echo "identify=-n" >> $HGRC
149 $ echo "[alias]" >> $HGRC
149 $ echo "[alias]" >> $HGRC
150 $ echo "log=log -g" >> $HGRC
150 $ echo "log=log -g" >> $HGRC
151
151
152 customized hgrc
152 customized hgrc
153
153
154 $ hg showconfig
154 $ hg showconfig
155 read config from: $TESTTMP/hgrc
155 read config from: $TESTTMP/hgrc
156 $TESTTMP/hgrc:13: alias.log=log -g
156 $TESTTMP/hgrc:13: alias.log=log -g
157 repo: bundle.mainreporoot=$TESTTMP
157 repo: bundle.mainreporoot=$TESTTMP
158 $TESTTMP/hgrc:11: defaults.identify=-n
158 $TESTTMP/hgrc:11: defaults.identify=-n
159 $TESTTMP/hgrc:2: ui.debug=true
159 $TESTTMP/hgrc:2: ui.debug=true
160 $TESTTMP/hgrc:3: ui.fallbackencoding=ASCII
160 $TESTTMP/hgrc:3: ui.fallbackencoding=ASCII
161 $TESTTMP/hgrc:4: ui.quiet=true
161 $TESTTMP/hgrc:4: ui.quiet=true
162 $TESTTMP/hgrc:5: ui.slash=true
162 $TESTTMP/hgrc:5: ui.slash=true
163 $TESTTMP/hgrc:6: ui.traceback=true
163 $TESTTMP/hgrc:6: ui.traceback=true
164 $TESTTMP/hgrc:7: ui.verbose=true
164 $TESTTMP/hgrc:7: ui.verbose=true
165 $TESTTMP/hgrc:8: ui.style=~/.hgstyle
165 $TESTTMP/hgrc:8: ui.style=~/.hgstyle
166 $TESTTMP/hgrc:9: ui.logtemplate={node}
166 $TESTTMP/hgrc:9: ui.logtemplate={node}
167
167
168 plain hgrc
168 plain hgrc
169
169
170 $ HGPLAIN=; export HGPLAIN
170 $ HGPLAIN=; export HGPLAIN
171 $ hg showconfig --config ui.traceback=True --debug
171 $ hg showconfig --config ui.traceback=True --debug
172 read config from: $TESTTMP/hgrc
172 read config from: $TESTTMP/hgrc
173 repo: bundle.mainreporoot=$TESTTMP
173 repo: bundle.mainreporoot=$TESTTMP
174 --config: ui.traceback=True
174 --config: ui.traceback=True
175 --verbose: ui.verbose=False
175 --verbose: ui.verbose=False
176 --debug: ui.debug=True
176 --debug: ui.debug=True
177 --quiet: ui.quiet=False
177 --quiet: ui.quiet=False
178
178
179 plain mode with exceptions
179 plain mode with exceptions
180
180
181 $ cat > plain.py <<EOF
181 $ cat > plain.py <<EOF
182 > from mercurial import commands, extensions
182 > from mercurial import commands, extensions
183 > def _config(orig, ui, repo, *values, **opts):
183 > def _config(orig, ui, repo, *values, **opts):
184 > ui.write('plain: %r\n' % ui.plain())
184 > ui.write('plain: %r\n' % ui.plain())
185 > return orig(ui, repo, *values, **opts)
185 > return orig(ui, repo, *values, **opts)
186 > def uisetup(ui):
186 > def uisetup(ui):
187 > extensions.wrapcommand(commands.table, 'config', _config)
187 > extensions.wrapcommand(commands.table, 'config', _config)
188 > EOF
188 > EOF
189 $ echo "[extensions]" >> $HGRC
189 $ echo "[extensions]" >> $HGRC
190 $ echo "plain=./plain.py" >> $HGRC
190 $ echo "plain=./plain.py" >> $HGRC
191 $ HGPLAINEXCEPT=; export HGPLAINEXCEPT
191 $ HGPLAINEXCEPT=; export HGPLAINEXCEPT
192 $ hg showconfig --config ui.traceback=True --debug
192 $ hg showconfig --config ui.traceback=True --debug
193 plain: True
193 plain: True
194 read config from: $TESTTMP/hgrc
194 read config from: $TESTTMP/hgrc
195 repo: bundle.mainreporoot=$TESTTMP
195 repo: bundle.mainreporoot=$TESTTMP
196 $TESTTMP/hgrc:15: extensions.plain=./plain.py
196 $TESTTMP/hgrc:15: extensions.plain=./plain.py
197 --config: ui.traceback=True
197 --config: ui.traceback=True
198 --verbose: ui.verbose=False
198 --verbose: ui.verbose=False
199 --debug: ui.debug=True
199 --debug: ui.debug=True
200 --quiet: ui.quiet=False
200 --quiet: ui.quiet=False
201 $ unset HGPLAIN
201 $ unset HGPLAIN
202 $ hg showconfig --config ui.traceback=True --debug
202 $ hg showconfig --config ui.traceback=True --debug
203 plain: True
203 plain: True
204 read config from: $TESTTMP/hgrc
204 read config from: $TESTTMP/hgrc
205 repo: bundle.mainreporoot=$TESTTMP
205 repo: bundle.mainreporoot=$TESTTMP
206 $TESTTMP/hgrc:15: extensions.plain=./plain.py
206 $TESTTMP/hgrc:15: extensions.plain=./plain.py
207 --config: ui.traceback=True
207 --config: ui.traceback=True
208 --verbose: ui.verbose=False
208 --verbose: ui.verbose=False
209 --debug: ui.debug=True
209 --debug: ui.debug=True
210 --quiet: ui.quiet=False
210 --quiet: ui.quiet=False
211 $ HGPLAINEXCEPT=i18n; export HGPLAINEXCEPT
211 $ HGPLAINEXCEPT=i18n; export HGPLAINEXCEPT
212 $ hg showconfig --config ui.traceback=True --debug
212 $ hg showconfig --config ui.traceback=True --debug
213 plain: True
213 plain: True
214 read config from: $TESTTMP/hgrc
214 read config from: $TESTTMP/hgrc
215 repo: bundle.mainreporoot=$TESTTMP
215 repo: bundle.mainreporoot=$TESTTMP
216 $TESTTMP/hgrc:15: extensions.plain=./plain.py
216 $TESTTMP/hgrc:15: extensions.plain=./plain.py
217 --config: ui.traceback=True
217 --config: ui.traceback=True
218 --verbose: ui.verbose=False
218 --verbose: ui.verbose=False
219 --debug: ui.debug=True
219 --debug: ui.debug=True
220 --quiet: ui.quiet=False
220 --quiet: ui.quiet=False
221
221
222 source of paths is not mangled
222 source of paths is not mangled
223
223
224 $ cat >> $HGRCPATH <<EOF
224 $ cat >> $HGRCPATH <<EOF
225 > [paths]
225 > [paths]
226 > foo = bar
226 > foo = bar
227 > EOF
227 > EOF
228 $ hg showconfig --debug paths
228 $ hg showconfig --debug paths
229 plain: True
229 plain: True
230 read config from: $TESTTMP/hgrc
230 read config from: $TESTTMP/hgrc
231 $TESTTMP/hgrc:17: paths.foo=$TESTTMP/bar (glob)
231 $TESTTMP/hgrc:17: paths.foo=$TESTTMP/bar (glob)
@@ -1,80 +1,80 b''
1 #require killdaemons
1 #require killdaemons
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo a > a
5 $ echo a > a
6 $ hg ci -Ama
6 $ hg ci -Ama
7 adding a
7 adding a
8 $ cd ..
8 $ cd ..
9 $ hg clone test test2
9 $ hg clone test test2
10 updating to branch default
10 updating to branch default
11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 $ cd test2
12 $ cd test2
13 $ echo a >> a
13 $ echo a >> a
14 $ hg ci -mb
14 $ hg ci -mb
15
15
16 Cloning with a password in the URL should not save the password in .hg/hgrc:
16 Cloning with a password in the URL should not save the password in .hg/hgrc:
17
17
18 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
18 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
19 $ cat hg.pid >> $DAEMON_PIDS
19 $ cat hg.pid >> $DAEMON_PIDS
20 $ hg clone http://foo:xyzzy@localhost:$HGPORT/ test3
20 $ hg clone http://foo:xyzzy@localhost:$HGPORT/ test3
21 requesting all changes
21 requesting all changes
22 adding changesets
22 adding changesets
23 adding manifests
23 adding manifests
24 adding file changes
24 adding file changes
25 added 2 changesets with 2 changes to 1 files
25 added 2 changesets with 2 changes to 1 files
26 updating to branch default
26 updating to branch default
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 $ cat test3/.hg/hgrc
28 $ cat test3/.hg/hgrc
29 # example repository config (see 'hg help config' for more info)
29 # example repository config (see 'hg help config' for more info)
30 [paths]
30 [paths]
31 default = http://foo@localhost:$HGPORT/
31 default = http://foo@localhost:$HGPORT/
32
32
33 # path aliases to other clones of this repo in URLs or filesystem paths
33 # path aliases to other clones of this repo in URLs or filesystem paths
34 # (see 'hg help config.paths' for more info)
34 # (see 'hg help config.paths' for more info)
35 #
35 #
36 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
36 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
37 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
37 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
38 # my-clone = /home/jdoe/jdoes-clone
38 # my-clone = /home/jdoe/jdoes-clone
39
39
40 [ui]
40 [ui]
41 # name and email (local to this repository, optional), e.g.
41 # name and email (local to this repository, optional), e.g.
42 # username = Jane Doe <jdoe@example.com>
42 # username = Jane Doe <jdoe@example.com>
43 $ killdaemons.py
43 $ killdaemons.py
44
44
45 expect error, cloning not allowed
45 expect error, cloning not allowed
46
46
47 $ echo '[web]' > .hg/hgrc
47 $ echo '[web]' > .hg/hgrc
48 $ echo 'allowpull = false' >> .hg/hgrc
48 $ echo 'allowpull = false' >> .hg/hgrc
49 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
49 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
50 $ cat hg.pid >> $DAEMON_PIDS
50 $ cat hg.pid >> $DAEMON_PIDS
51 $ hg clone http://localhost:$HGPORT/ test4 # bundle2+
51 $ hg clone http://localhost:$HGPORT/ test4 # bundle2+
52 requesting all changes
52 requesting all changes
53 abort: authorization failed
53 abort: authorization failed
54 [255]
54 [255]
55 $ hg clone http://localhost:$HGPORT/ test4 --config devel.legacy.exchange=bundle1
55 $ hg clone http://localhost:$HGPORT/ test4 --config devel.legacy.exchange=bundle1
56 abort: authorization failed
56 abort: authorization failed
57 [255]
57 [255]
58 $ killdaemons.py
58 $ killdaemons.py
59
59
60 serve errors
60 serve errors
61
61
62 $ cat errors.log
62 $ cat errors.log
63 $ req() {
63 $ req() {
64 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
64 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
65 > cat hg.pid >> $DAEMON_PIDS
65 > cat hg.pid >> $DAEMON_PIDS
66 > hg --cwd ../test pull http://localhost:$HGPORT/
66 > hg --cwd ../test pull http://localhost:$HGPORT/
67 > killdaemons.py hg.pid
67 > killdaemons.py hg.pid
68 > echo % serve errors
68 > echo % serve errors
69 > cat errors.log
69 > cat errors.log
70 > }
70 > }
71
71
72 expect error, pulling not allowed
72 expect error, pulling not allowed
73
73
74 $ req
74 $ req
75 pulling from http://localhost:$HGPORT/
75 pulling from http://localhost:$HGPORT/
76 searching for changes
76 searching for changes
77 abort: authorization failed
77 abort: authorization failed
78 % serve errors
78 % serve errors
79
79
80 $ cd ..
80 $ cd ..
@@ -1,415 +1,416 b''
1 Create configuration
1 Create configuration
2
2
3 $ echo "[ui]" >> $HGRCPATH
3 $ echo "[ui]" >> $HGRCPATH
4 $ echo "interactive=true" >> $HGRCPATH
4 $ echo "interactive=true" >> $HGRCPATH
5
5
6 help record (no record)
6 help record (no record)
7
7
8 $ hg help record
8 $ hg help record
9 record extension - commands to interactively select changes for
9 record extension - commands to interactively select changes for
10 commit/qrefresh (DEPRECATED)
10 commit/qrefresh (DEPRECATED)
11
11
12 The feature provided by this extension has been moved into core Mercurial as
12 The feature provided by this extension has been moved into core Mercurial as
13 'hg commit --interactive'.
13 'hg commit --interactive'.
14
14
15 (use 'hg help extensions' for information on enabling extensions)
15 (use 'hg help extensions' for information on enabling extensions)
16
16
17 help qrecord (no record)
17 help qrecord (no record)
18
18
19 $ hg help qrecord
19 $ hg help qrecord
20 'qrecord' is provided by the following extension:
20 'qrecord' is provided by the following extension:
21
21
22 record commands to interactively select changes for commit/qrefresh
22 record commands to interactively select changes for commit/qrefresh
23 (DEPRECATED)
23 (DEPRECATED)
24
24
25 (use 'hg help extensions' for information on enabling extensions)
25 (use 'hg help extensions' for information on enabling extensions)
26
26
27 $ echo "[extensions]" >> $HGRCPATH
27 $ echo "[extensions]" >> $HGRCPATH
28 $ echo "record=" >> $HGRCPATH
28 $ echo "record=" >> $HGRCPATH
29
29
30 help record (record)
30 help record (record)
31
31
32 $ hg help record
32 $ hg help record
33 hg record [OPTION]... [FILE]...
33 hg record [OPTION]... [FILE]...
34
34
35 interactively select changes to commit
35 interactively select changes to commit
36
36
37 If a list of files is omitted, all changes reported by 'hg status' will be
37 If a list of files is omitted, all changes reported by 'hg status' will be
38 candidates for recording.
38 candidates for recording.
39
39
40 See 'hg help dates' for a list of formats valid for -d/--date.
40 See 'hg help dates' for a list of formats valid for -d/--date.
41
41
42 You will be prompted for whether to record changes to each modified file,
42 If using the text interface (see 'hg help config'), you will be prompted
43 and for files with multiple changes, for each change to use. For each
43 for whether to record changes to each modified file, and for files with
44 query, the following responses are possible:
44 multiple changes, for each change to use. For each query, the following
45 responses are possible:
45
46
46 y - record this change
47 y - record this change
47 n - skip this change
48 n - skip this change
48 e - edit this change manually
49 e - edit this change manually
49
50
50 s - skip remaining changes to this file
51 s - skip remaining changes to this file
51 f - record remaining changes to this file
52 f - record remaining changes to this file
52
53
53 d - done, skip remaining changes and files
54 d - done, skip remaining changes and files
54 a - record all changes to all remaining files
55 a - record all changes to all remaining files
55 q - quit, recording no changes
56 q - quit, recording no changes
56
57
57 ? - display help
58 ? - display help
58
59
59 This command is not available when committing a merge.
60 This command is not available when committing a merge.
60
61
61 (use 'hg help -e record' to show help for the record extension)
62 (use 'hg help -e record' to show help for the record extension)
62
63
63 options ([+] can be repeated):
64 options ([+] can be repeated):
64
65
65 -A --addremove mark new/missing files as added/removed before
66 -A --addremove mark new/missing files as added/removed before
66 committing
67 committing
67 --close-branch mark a branch head as closed
68 --close-branch mark a branch head as closed
68 --amend amend the parent of the working directory
69 --amend amend the parent of the working directory
69 -s --secret use the secret phase for committing
70 -s --secret use the secret phase for committing
70 -e --edit invoke editor on commit messages
71 -e --edit invoke editor on commit messages
71 -I --include PATTERN [+] include names matching the given patterns
72 -I --include PATTERN [+] include names matching the given patterns
72 -X --exclude PATTERN [+] exclude names matching the given patterns
73 -X --exclude PATTERN [+] exclude names matching the given patterns
73 -m --message TEXT use text as commit message
74 -m --message TEXT use text as commit message
74 -l --logfile FILE read commit message from file
75 -l --logfile FILE read commit message from file
75 -d --date DATE record the specified date as commit date
76 -d --date DATE record the specified date as commit date
76 -u --user USER record the specified user as committer
77 -u --user USER record the specified user as committer
77 -S --subrepos recurse into subrepositories
78 -S --subrepos recurse into subrepositories
78 -w --ignore-all-space ignore white space when comparing lines
79 -w --ignore-all-space ignore white space when comparing lines
79 -b --ignore-space-change ignore changes in the amount of white space
80 -b --ignore-space-change ignore changes in the amount of white space
80 -B --ignore-blank-lines ignore changes whose lines are all blank
81 -B --ignore-blank-lines ignore changes whose lines are all blank
81
82
82 (some details hidden, use --verbose to show complete help)
83 (some details hidden, use --verbose to show complete help)
83
84
84 help (no mq, so no qrecord)
85 help (no mq, so no qrecord)
85
86
86 $ hg help qrecord
87 $ hg help qrecord
87 hg qrecord [OPTION]... PATCH [FILE]...
88 hg qrecord [OPTION]... PATCH [FILE]...
88
89
89 interactively record a new patch
90 interactively record a new patch
90
91
91 See 'hg help qnew' & 'hg help record' for more information and usage.
92 See 'hg help qnew' & 'hg help record' for more information and usage.
92
93
93 (some details hidden, use --verbose to show complete help)
94 (some details hidden, use --verbose to show complete help)
94
95
95 $ hg init a
96 $ hg init a
96
97
97 qrecord (mq not present)
98 qrecord (mq not present)
98
99
99 $ hg -R a qrecord
100 $ hg -R a qrecord
100 hg qrecord: invalid arguments
101 hg qrecord: invalid arguments
101 hg qrecord [OPTION]... PATCH [FILE]...
102 hg qrecord [OPTION]... PATCH [FILE]...
102
103
103 interactively record a new patch
104 interactively record a new patch
104
105
105 (use 'hg qrecord -h' to show more help)
106 (use 'hg qrecord -h' to show more help)
106 [255]
107 [255]
107
108
108 qrecord patch (mq not present)
109 qrecord patch (mq not present)
109
110
110 $ hg -R a qrecord patch
111 $ hg -R a qrecord patch
111 abort: 'mq' extension not loaded
112 abort: 'mq' extension not loaded
112 [255]
113 [255]
113
114
114 help (bad mq)
115 help (bad mq)
115
116
116 $ echo "mq=nonexistent" >> $HGRCPATH
117 $ echo "mq=nonexistent" >> $HGRCPATH
117 $ hg help qrecord
118 $ hg help qrecord
118 *** failed to import extension mq from nonexistent: [Errno *] * (glob)
119 *** failed to import extension mq from nonexistent: [Errno *] * (glob)
119 hg qrecord [OPTION]... PATCH [FILE]...
120 hg qrecord [OPTION]... PATCH [FILE]...
120
121
121 interactively record a new patch
122 interactively record a new patch
122
123
123 See 'hg help qnew' & 'hg help record' for more information and usage.
124 See 'hg help qnew' & 'hg help record' for more information and usage.
124
125
125 (some details hidden, use --verbose to show complete help)
126 (some details hidden, use --verbose to show complete help)
126
127
127 help (mq present)
128 help (mq present)
128
129
129 $ sed 's/mq=nonexistent/mq=/' $HGRCPATH > hgrc.tmp
130 $ sed 's/mq=nonexistent/mq=/' $HGRCPATH > hgrc.tmp
130 $ mv hgrc.tmp $HGRCPATH
131 $ mv hgrc.tmp $HGRCPATH
131
132
132 $ hg help qrecord
133 $ hg help qrecord
133 hg qrecord [OPTION]... PATCH [FILE]...
134 hg qrecord [OPTION]... PATCH [FILE]...
134
135
135 interactively record a new patch
136 interactively record a new patch
136
137
137 See 'hg help qnew' & 'hg help record' for more information and usage.
138 See 'hg help qnew' & 'hg help record' for more information and usage.
138
139
139 options ([+] can be repeated):
140 options ([+] can be repeated):
140
141
141 -e --edit invoke editor on commit messages
142 -e --edit invoke editor on commit messages
142 -g --git use git extended diff format
143 -g --git use git extended diff format
143 -U --currentuser add "From: <current user>" to patch
144 -U --currentuser add "From: <current user>" to patch
144 -u --user USER add "From: <USER>" to patch
145 -u --user USER add "From: <USER>" to patch
145 -D --currentdate add "Date: <current date>" to patch
146 -D --currentdate add "Date: <current date>" to patch
146 -d --date DATE add "Date: <DATE>" to patch
147 -d --date DATE add "Date: <DATE>" to patch
147 -I --include PATTERN [+] include names matching the given patterns
148 -I --include PATTERN [+] include names matching the given patterns
148 -X --exclude PATTERN [+] exclude names matching the given patterns
149 -X --exclude PATTERN [+] exclude names matching the given patterns
149 -m --message TEXT use text as commit message
150 -m --message TEXT use text as commit message
150 -l --logfile FILE read commit message from file
151 -l --logfile FILE read commit message from file
151 -w --ignore-all-space ignore white space when comparing lines
152 -w --ignore-all-space ignore white space when comparing lines
152 -b --ignore-space-change ignore changes in the amount of white space
153 -b --ignore-space-change ignore changes in the amount of white space
153 -B --ignore-blank-lines ignore changes whose lines are all blank
154 -B --ignore-blank-lines ignore changes whose lines are all blank
154 --mq operate on patch repository
155 --mq operate on patch repository
155
156
156 (some details hidden, use --verbose to show complete help)
157 (some details hidden, use --verbose to show complete help)
157
158
158 $ cd a
159 $ cd a
159
160
160 Base commit
161 Base commit
161
162
162 $ cat > 1.txt <<EOF
163 $ cat > 1.txt <<EOF
163 > 1
164 > 1
164 > 2
165 > 2
165 > 3
166 > 3
166 > 4
167 > 4
167 > 5
168 > 5
168 > EOF
169 > EOF
169 $ cat > 2.txt <<EOF
170 $ cat > 2.txt <<EOF
170 > a
171 > a
171 > b
172 > b
172 > c
173 > c
173 > d
174 > d
174 > e
175 > e
175 > f
176 > f
176 > EOF
177 > EOF
177
178
178 $ mkdir dir
179 $ mkdir dir
179 $ cat > dir/a.txt <<EOF
180 $ cat > dir/a.txt <<EOF
180 > hello world
181 > hello world
181 >
182 >
182 > someone
183 > someone
183 > up
184 > up
184 > there
185 > there
185 > loves
186 > loves
186 > me
187 > me
187 > EOF
188 > EOF
188
189
189 $ hg add 1.txt 2.txt dir/a.txt
190 $ hg add 1.txt 2.txt dir/a.txt
190 $ hg commit -m 'initial checkin'
191 $ hg commit -m 'initial checkin'
191
192
192 Changing files
193 Changing files
193
194
194 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
195 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
195 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
196 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
196 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
197 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
197
198
198 $ mv -f 1.txt.new 1.txt
199 $ mv -f 1.txt.new 1.txt
199 $ mv -f 2.txt.new 2.txt
200 $ mv -f 2.txt.new 2.txt
200 $ mv -f dir/a.txt.new dir/a.txt
201 $ mv -f dir/a.txt.new dir/a.txt
201
202
202 Whole diff
203 Whole diff
203
204
204 $ hg diff --nodates
205 $ hg diff --nodates
205 diff -r 1057167b20ef 1.txt
206 diff -r 1057167b20ef 1.txt
206 --- a/1.txt
207 --- a/1.txt
207 +++ b/1.txt
208 +++ b/1.txt
208 @@ -1,5 +1,5 @@
209 @@ -1,5 +1,5 @@
209 1
210 1
210 -2
211 -2
211 +2 2
212 +2 2
212 3
213 3
213 -4
214 -4
214 +4 4
215 +4 4
215 5
216 5
216 diff -r 1057167b20ef 2.txt
217 diff -r 1057167b20ef 2.txt
217 --- a/2.txt
218 --- a/2.txt
218 +++ b/2.txt
219 +++ b/2.txt
219 @@ -1,5 +1,5 @@
220 @@ -1,5 +1,5 @@
220 a
221 a
221 -b
222 -b
222 +b b
223 +b b
223 c
224 c
224 d
225 d
225 e
226 e
226 diff -r 1057167b20ef dir/a.txt
227 diff -r 1057167b20ef dir/a.txt
227 --- a/dir/a.txt
228 --- a/dir/a.txt
228 +++ b/dir/a.txt
229 +++ b/dir/a.txt
229 @@ -1,4 +1,4 @@
230 @@ -1,4 +1,4 @@
230 -hello world
231 -hello world
231 +hello world!
232 +hello world!
232
233
233 someone
234 someone
234 up
235 up
235
236
236 qrecord with bad patch name, should abort before prompting
237 qrecord with bad patch name, should abort before prompting
237
238
238 $ hg qrecord .hg
239 $ hg qrecord .hg
239 abort: patch name cannot begin with ".hg"
240 abort: patch name cannot begin with ".hg"
240 [255]
241 [255]
241
242
242 qrecord a.patch
243 qrecord a.patch
243
244
244 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
245 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
245 > y
246 > y
246 > y
247 > y
247 > n
248 > n
248 > y
249 > y
249 > y
250 > y
250 > n
251 > n
251 > EOF
252 > EOF
252 diff --git a/1.txt b/1.txt
253 diff --git a/1.txt b/1.txt
253 2 hunks, 2 lines changed
254 2 hunks, 2 lines changed
254 examine changes to '1.txt'? [Ynesfdaq?] y
255 examine changes to '1.txt'? [Ynesfdaq?] y
255
256
256 @@ -1,3 +1,3 @@
257 @@ -1,3 +1,3 @@
257 1
258 1
258 -2
259 -2
259 +2 2
260 +2 2
260 3
261 3
261 record change 1/4 to '1.txt'? [Ynesfdaq?] y
262 record change 1/4 to '1.txt'? [Ynesfdaq?] y
262
263
263 @@ -3,3 +3,3 @@
264 @@ -3,3 +3,3 @@
264 3
265 3
265 -4
266 -4
266 +4 4
267 +4 4
267 5
268 5
268 record change 2/4 to '1.txt'? [Ynesfdaq?] n
269 record change 2/4 to '1.txt'? [Ynesfdaq?] n
269
270
270 diff --git a/2.txt b/2.txt
271 diff --git a/2.txt b/2.txt
271 1 hunks, 1 lines changed
272 1 hunks, 1 lines changed
272 examine changes to '2.txt'? [Ynesfdaq?] y
273 examine changes to '2.txt'? [Ynesfdaq?] y
273
274
274 @@ -1,5 +1,5 @@
275 @@ -1,5 +1,5 @@
275 a
276 a
276 -b
277 -b
277 +b b
278 +b b
278 c
279 c
279 d
280 d
280 e
281 e
281 record change 3/4 to '2.txt'? [Ynesfdaq?] y
282 record change 3/4 to '2.txt'? [Ynesfdaq?] y
282
283
283 diff --git a/dir/a.txt b/dir/a.txt
284 diff --git a/dir/a.txt b/dir/a.txt
284 1 hunks, 1 lines changed
285 1 hunks, 1 lines changed
285 examine changes to 'dir/a.txt'? [Ynesfdaq?] n
286 examine changes to 'dir/a.txt'? [Ynesfdaq?] n
286
287
287
288
288 After qrecord a.patch 'tip'"
289 After qrecord a.patch 'tip'"
289
290
290 $ hg tip -p
291 $ hg tip -p
291 changeset: 1:5d1ca63427ee
292 changeset: 1:5d1ca63427ee
292 tag: a.patch
293 tag: a.patch
293 tag: qbase
294 tag: qbase
294 tag: qtip
295 tag: qtip
295 tag: tip
296 tag: tip
296 user: test
297 user: test
297 date: Thu Jan 01 00:00:00 1970 +0000
298 date: Thu Jan 01 00:00:00 1970 +0000
298 summary: aaa
299 summary: aaa
299
300
300 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
301 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
301 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
302 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
302 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
303 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
303 @@ -1,5 +1,5 @@
304 @@ -1,5 +1,5 @@
304 1
305 1
305 -2
306 -2
306 +2 2
307 +2 2
307 3
308 3
308 4
309 4
309 5
310 5
310 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
311 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
311 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
312 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
312 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
313 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
313 @@ -1,5 +1,5 @@
314 @@ -1,5 +1,5 @@
314 a
315 a
315 -b
316 -b
316 +b b
317 +b b
317 c
318 c
318 d
319 d
319 e
320 e
320
321
321
322
322 After qrecord a.patch 'diff'"
323 After qrecord a.patch 'diff'"
323
324
324 $ hg diff --nodates
325 $ hg diff --nodates
325 diff -r 5d1ca63427ee 1.txt
326 diff -r 5d1ca63427ee 1.txt
326 --- a/1.txt
327 --- a/1.txt
327 +++ b/1.txt
328 +++ b/1.txt
328 @@ -1,5 +1,5 @@
329 @@ -1,5 +1,5 @@
329 1
330 1
330 2 2
331 2 2
331 3
332 3
332 -4
333 -4
333 +4 4
334 +4 4
334 5
335 5
335 diff -r 5d1ca63427ee dir/a.txt
336 diff -r 5d1ca63427ee dir/a.txt
336 --- a/dir/a.txt
337 --- a/dir/a.txt
337 +++ b/dir/a.txt
338 +++ b/dir/a.txt
338 @@ -1,4 +1,4 @@
339 @@ -1,4 +1,4 @@
339 -hello world
340 -hello world
340 +hello world!
341 +hello world!
341
342
342 someone
343 someone
343 up
344 up
344
345
345 qrecord b.patch
346 qrecord b.patch
346
347
347 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
348 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
348 > y
349 > y
349 > y
350 > y
350 > y
351 > y
351 > y
352 > y
352 > EOF
353 > EOF
353 diff --git a/1.txt b/1.txt
354 diff --git a/1.txt b/1.txt
354 1 hunks, 1 lines changed
355 1 hunks, 1 lines changed
355 examine changes to '1.txt'? [Ynesfdaq?] y
356 examine changes to '1.txt'? [Ynesfdaq?] y
356
357
357 @@ -1,5 +1,5 @@
358 @@ -1,5 +1,5 @@
358 1
359 1
359 2 2
360 2 2
360 3
361 3
361 -4
362 -4
362 +4 4
363 +4 4
363 5
364 5
364 record change 1/2 to '1.txt'? [Ynesfdaq?] y
365 record change 1/2 to '1.txt'? [Ynesfdaq?] y
365
366
366 diff --git a/dir/a.txt b/dir/a.txt
367 diff --git a/dir/a.txt b/dir/a.txt
367 1 hunks, 1 lines changed
368 1 hunks, 1 lines changed
368 examine changes to 'dir/a.txt'? [Ynesfdaq?] y
369 examine changes to 'dir/a.txt'? [Ynesfdaq?] y
369
370
370 @@ -1,4 +1,4 @@
371 @@ -1,4 +1,4 @@
371 -hello world
372 -hello world
372 +hello world!
373 +hello world!
373
374
374 someone
375 someone
375 up
376 up
376 record change 2/2 to 'dir/a.txt'? [Ynesfdaq?] y
377 record change 2/2 to 'dir/a.txt'? [Ynesfdaq?] y
377
378
378
379
379 After qrecord b.patch 'tip'
380 After qrecord b.patch 'tip'
380
381
381 $ hg tip -p
382 $ hg tip -p
382 changeset: 2:b056198bf878
383 changeset: 2:b056198bf878
383 tag: b.patch
384 tag: b.patch
384 tag: qtip
385 tag: qtip
385 tag: tip
386 tag: tip
386 user: test
387 user: test
387 date: Thu Jan 01 00:00:00 1970 +0000
388 date: Thu Jan 01 00:00:00 1970 +0000
388 summary: bbb
389 summary: bbb
389
390
390 diff -r 5d1ca63427ee -r b056198bf878 1.txt
391 diff -r 5d1ca63427ee -r b056198bf878 1.txt
391 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
392 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
392 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
393 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
393 @@ -1,5 +1,5 @@
394 @@ -1,5 +1,5 @@
394 1
395 1
395 2 2
396 2 2
396 3
397 3
397 -4
398 -4
398 +4 4
399 +4 4
399 5
400 5
400 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
401 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
401 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
402 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
402 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
403 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
403 @@ -1,4 +1,4 @@
404 @@ -1,4 +1,4 @@
404 -hello world
405 -hello world
405 +hello world!
406 +hello world!
406
407
407 someone
408 someone
408 up
409 up
409
410
410
411
411 After qrecord b.patch 'diff'
412 After qrecord b.patch 'diff'
412
413
413 $ hg diff --nodates
414 $ hg diff --nodates
414
415
415 $ cd ..
416 $ cd ..
@@ -1,90 +1,91 b''
1 Set up a repo
1 Set up a repo
2
2
3 $ cat <<EOF >> $HGRCPATH
3 $ cat <<EOF >> $HGRCPATH
4 > [ui]
4 > [ui]
5 > interactive = true
5 > interactive = true
6 > [extensions]
6 > [extensions]
7 > record =
7 > record =
8 > EOF
8 > EOF
9
9
10 $ hg init a
10 $ hg init a
11 $ cd a
11 $ cd a
12
12
13 Record help
13 Record help
14
14
15 $ hg record -h
15 $ hg record -h
16 hg record [OPTION]... [FILE]...
16 hg record [OPTION]... [FILE]...
17
17
18 interactively select changes to commit
18 interactively select changes to commit
19
19
20 If a list of files is omitted, all changes reported by 'hg status' will be
20 If a list of files is omitted, all changes reported by 'hg status' will be
21 candidates for recording.
21 candidates for recording.
22
22
23 See 'hg help dates' for a list of formats valid for -d/--date.
23 See 'hg help dates' for a list of formats valid for -d/--date.
24
24
25 You will be prompted for whether to record changes to each modified file,
25 If using the text interface (see 'hg help config'), you will be prompted
26 and for files with multiple changes, for each change to use. For each
26 for whether to record changes to each modified file, and for files with
27 query, the following responses are possible:
27 multiple changes, for each change to use. For each query, the following
28 responses are possible:
28
29
29 y - record this change
30 y - record this change
30 n - skip this change
31 n - skip this change
31 e - edit this change manually
32 e - edit this change manually
32
33
33 s - skip remaining changes to this file
34 s - skip remaining changes to this file
34 f - record remaining changes to this file
35 f - record remaining changes to this file
35
36
36 d - done, skip remaining changes and files
37 d - done, skip remaining changes and files
37 a - record all changes to all remaining files
38 a - record all changes to all remaining files
38 q - quit, recording no changes
39 q - quit, recording no changes
39
40
40 ? - display help
41 ? - display help
41
42
42 This command is not available when committing a merge.
43 This command is not available when committing a merge.
43
44
44 (use 'hg help -e record' to show help for the record extension)
45 (use 'hg help -e record' to show help for the record extension)
45
46
46 options ([+] can be repeated):
47 options ([+] can be repeated):
47
48
48 -A --addremove mark new/missing files as added/removed before
49 -A --addremove mark new/missing files as added/removed before
49 committing
50 committing
50 --close-branch mark a branch head as closed
51 --close-branch mark a branch head as closed
51 --amend amend the parent of the working directory
52 --amend amend the parent of the working directory
52 -s --secret use the secret phase for committing
53 -s --secret use the secret phase for committing
53 -e --edit invoke editor on commit messages
54 -e --edit invoke editor on commit messages
54 -I --include PATTERN [+] include names matching the given patterns
55 -I --include PATTERN [+] include names matching the given patterns
55 -X --exclude PATTERN [+] exclude names matching the given patterns
56 -X --exclude PATTERN [+] exclude names matching the given patterns
56 -m --message TEXT use text as commit message
57 -m --message TEXT use text as commit message
57 -l --logfile FILE read commit message from file
58 -l --logfile FILE read commit message from file
58 -d --date DATE record the specified date as commit date
59 -d --date DATE record the specified date as commit date
59 -u --user USER record the specified user as committer
60 -u --user USER record the specified user as committer
60 -S --subrepos recurse into subrepositories
61 -S --subrepos recurse into subrepositories
61 -w --ignore-all-space ignore white space when comparing lines
62 -w --ignore-all-space ignore white space when comparing lines
62 -b --ignore-space-change ignore changes in the amount of white space
63 -b --ignore-space-change ignore changes in the amount of white space
63 -B --ignore-blank-lines ignore changes whose lines are all blank
64 -B --ignore-blank-lines ignore changes whose lines are all blank
64
65
65 (some details hidden, use --verbose to show complete help)
66 (some details hidden, use --verbose to show complete help)
66
67
67 Select no files
68 Select no files
68
69
69 $ touch empty-rw
70 $ touch empty-rw
70 $ hg add empty-rw
71 $ hg add empty-rw
71
72
72 $ hg record empty-rw<<EOF
73 $ hg record empty-rw<<EOF
73 > n
74 > n
74 > EOF
75 > EOF
75 diff --git a/empty-rw b/empty-rw
76 diff --git a/empty-rw b/empty-rw
76 new file mode 100644
77 new file mode 100644
77 examine changes to 'empty-rw'? [Ynesfdaq?] n
78 examine changes to 'empty-rw'? [Ynesfdaq?] n
78
79
79 no changes to record
80 no changes to record
80 [1]
81 [1]
81
82
82 $ hg tip -p
83 $ hg tip -p
83 changeset: -1:000000000000
84 changeset: -1:000000000000
84 tag: tip
85 tag: tip
85 user:
86 user:
86 date: Thu Jan 01 00:00:00 1970 +0000
87 date: Thu Jan 01 00:00:00 1970 +0000
87
88
88
89
89
90
90
91
@@ -1,116 +1,116 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [alias]
2 > [alias]
3 > tlog = log --template "{rev}:{node|short}: '{desc}' {branches}\n"
3 > tlog = log --template "{rev}:{node|short}: '{desc}' {branches}\n"
4 > tglog = tlog -G
4 > tglog = tlog -G
5 > tout = out --template "{rev}:{node|short}: '{desc}' {branches}\n"
5 > tout = out --template "{rev}:{node|short}: '{desc}' {branches}\n"
6 > EOF
6 > EOF
7
7
8 $ hg init a
8 $ hg init a
9 $ cd a
9 $ cd a
10
10
11 $ echo a > a
11 $ echo a > a
12 $ hg ci -Aqm0
12 $ hg ci -Aqm0
13
13
14 $ echo foo >> a
14 $ echo foo >> a
15 $ hg ci -Aqm1
15 $ hg ci -Aqm1
16
16
17 $ hg up -q 0
17 $ hg up -q 0
18
18
19 $ hg branch stable
19 $ hg branch stable
20 marked working directory as branch stable
20 marked working directory as branch stable
21 (branches are permanent and global, did you want a bookmark?)
21 (branches are permanent and global, did you want a bookmark?)
22 $ echo bar >> a
22 $ echo bar >> a
23 $ hg ci -qm2
23 $ hg ci -qm2
24
24
25 $ hg tglog
25 $ hg tglog
26 @ 2:7bee6c3bea3a: '2' stable
26 @ 2:7bee6c3bea3a: '2' stable
27 |
27 |
28 | o 1:3560197d8331: '1'
28 | o 1:3560197d8331: '1'
29 |/
29 |/
30 o 0:f7b1eb17ad24: '0'
30 o 0:f7b1eb17ad24: '0'
31
31
32
32
33 $ cd ..
33 $ cd ..
34
34
35 $ hg clone -q a#stable b
35 $ hg clone -q a#stable b
36
36
37 $ cd b
37 $ cd b
38 $ cat .hg/hgrc
38 $ cat .hg/hgrc
39 # example repository config (see 'hg help config' for more info)
39 # example repository config (see 'hg help config' for more info)
40 [paths]
40 [paths]
41 default = $TESTTMP/a#stable (glob)
41 default = $TESTTMP/a#stable (glob)
42
42
43 # path aliases to other clones of this repo in URLs or filesystem paths
43 # path aliases to other clones of this repo in URLs or filesystem paths
44 # (see 'hg help config.paths' for more info)
44 # (see 'hg help config.paths' for more info)
45 #
45 #
46 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
46 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
47 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
47 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
48 # my-clone = /home/jdoe/jdoes-clone
48 # my-clone = /home/jdoe/jdoes-clone
49
49
50 [ui]
50 [ui]
51 # name and email (local to this repository, optional), e.g.
51 # name and email (local to this repository, optional), e.g.
52 # username = Jane Doe <jdoe@example.com>
52 # username = Jane Doe <jdoe@example.com>
53
53
54 $ echo red >> a
54 $ echo red >> a
55 $ hg ci -qm3
55 $ hg ci -qm3
56
56
57 $ hg up -q default
57 $ hg up -q default
58
58
59 $ echo blue >> a
59 $ echo blue >> a
60 $ hg ci -qm4
60 $ hg ci -qm4
61
61
62 $ hg tglog
62 $ hg tglog
63 @ 3:f0461977a3db: '4'
63 @ 3:f0461977a3db: '4'
64 |
64 |
65 | o 2:1d4099801a4e: '3' stable
65 | o 2:1d4099801a4e: '3' stable
66 | |
66 | |
67 | o 1:7bee6c3bea3a: '2' stable
67 | o 1:7bee6c3bea3a: '2' stable
68 |/
68 |/
69 o 0:f7b1eb17ad24: '0'
69 o 0:f7b1eb17ad24: '0'
70
70
71
71
72 $ hg tout
72 $ hg tout
73 comparing with $TESTTMP/a (glob)
73 comparing with $TESTTMP/a (glob)
74 searching for changes
74 searching for changes
75 2:1d4099801a4e: '3' stable
75 2:1d4099801a4e: '3' stable
76
76
77 $ hg tlog -r 'outgoing()'
77 $ hg tlog -r 'outgoing()'
78 2:1d4099801a4e: '3' stable
78 2:1d4099801a4e: '3' stable
79
79
80 $ hg tout ../a#default
80 $ hg tout ../a#default
81 comparing with ../a
81 comparing with ../a
82 searching for changes
82 searching for changes
83 3:f0461977a3db: '4'
83 3:f0461977a3db: '4'
84
84
85 $ hg tlog -r 'outgoing("../a#default")'
85 $ hg tlog -r 'outgoing("../a#default")'
86 3:f0461977a3db: '4'
86 3:f0461977a3db: '4'
87
87
88 $ echo "green = ../a#default" >> .hg/hgrc
88 $ echo "green = ../a#default" >> .hg/hgrc
89
89
90 $ cat .hg/hgrc
90 $ cat .hg/hgrc
91 # example repository config (see 'hg help config' for more info)
91 # example repository config (see 'hg help config' for more info)
92 [paths]
92 [paths]
93 default = $TESTTMP/a#stable (glob)
93 default = $TESTTMP/a#stable (glob)
94
94
95 # path aliases to other clones of this repo in URLs or filesystem paths
95 # path aliases to other clones of this repo in URLs or filesystem paths
96 # (see 'hg help config.paths' for more info)
96 # (see 'hg help config.paths' for more info)
97 #
97 #
98 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
98 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
99 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
99 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
100 # my-clone = /home/jdoe/jdoes-clone
100 # my-clone = /home/jdoe/jdoes-clone
101
101
102 [ui]
102 [ui]
103 # name and email (local to this repository, optional), e.g.
103 # name and email (local to this repository, optional), e.g.
104 # username = Jane Doe <jdoe@example.com>
104 # username = Jane Doe <jdoe@example.com>
105 green = ../a#default
105 green = ../a#default
106
106
107 $ hg tout green
107 $ hg tout green
108 comparing with green
108 comparing with green
109 abort: repository green not found!
109 abort: repository green not found!
110 [255]
110 [255]
111
111
112 $ hg tlog -r 'outgoing("green")'
112 $ hg tlog -r 'outgoing("green")'
113 abort: repository green not found!
113 abort: repository green not found!
114 [255]
114 [255]
115
115
116 $ cd ..
116 $ cd ..
@@ -1,58 +1,93 b''
1 $ hg init test
1 $ hg init test
2 $ cd test
2 $ cd test
3 $ echo foo>foo
3 $ echo foo>foo
4 $ hg addremove
4 $ hg addremove
5 adding foo
5 adding foo
6 $ hg commit -m "1"
6 $ hg commit -m "1"
7
7
8 $ hg verify
8 $ hg verify
9 checking changesets
9 checking changesets
10 checking manifests
10 checking manifests
11 crosschecking files in changesets and manifests
11 crosschecking files in changesets and manifests
12 checking files
12 checking files
13 1 files, 1 changesets, 1 total revisions
13 1 files, 1 changesets, 1 total revisions
14
14
15 $ hg clone . ../branch
15 $ hg clone . ../branch
16 updating to branch default
16 updating to branch default
17 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
18 $ cd ../branch
18 $ cd ../branch
19 $ hg co
19 $ hg co
20 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 $ echo bar>>foo
21 $ echo bar>>foo
22 $ hg commit -m "2"
22 $ hg commit -m "2"
23
23
24 $ cd ../test
24 $ cd ../test
25
25
26 $ hg pull ../branch
26 $ hg pull ../branch
27 pulling from ../branch
27 pulling from ../branch
28 searching for changes
28 searching for changes
29 adding changesets
29 adding changesets
30 adding manifests
30 adding manifests
31 adding file changes
31 adding file changes
32 added 1 changesets with 1 changes to 1 files
32 added 1 changesets with 1 changes to 1 files
33 (run 'hg update' to get a working copy)
33 (run 'hg update' to get a working copy)
34
34
35 $ hg verify
35 $ hg verify
36 checking changesets
36 checking changesets
37 checking manifests
37 checking manifests
38 crosschecking files in changesets and manifests
38 crosschecking files in changesets and manifests
39 checking files
39 checking files
40 1 files, 2 changesets, 2 total revisions
40 1 files, 2 changesets, 2 total revisions
41
41
42 $ hg co
42 $ hg co
43 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44
44
45 $ cat foo
45 $ cat foo
46 foo
46 foo
47 bar
47 bar
48
48
49 $ hg manifest --debug
49 $ hg manifest --debug
50 6f4310b00b9a147241b071a60c28a650827fb03d 644 foo
50 6f4310b00b9a147241b071a60c28a650827fb03d 644 foo
51
51
52 update to rev 0 with a date
52 update to rev 0 with a date
53
53
54 $ hg upd -d foo 0
54 $ hg upd -d foo 0
55 abort: you can't specify a revision and a date
55 abort: you can't specify a revision and a date
56 [255]
56 [255]
57
57
58 $ cd ..
58 $ cd ..
59
60 update with worker processes
61
62 #if no-windows
63
64 $ cat <<EOF > forceworker.py
65 > from mercurial import extensions, worker
66 > def nocost(orig, ui, costperop, nops):
67 > return worker._numworkers(ui) > 1
68 > def uisetup(ui):
69 > extensions.wrapfunction(worker, 'worthwhile', nocost)
70 > EOF
71
72 $ hg init worker
73 $ cd worker
74 $ cat <<EOF >> .hg/hgrc
75 > [extensions]
76 > forceworker = $TESTTMP/forceworker.py
77 > [worker]
78 > numcpus = 4
79 > EOF
80 $ for i in `python $TESTDIR/seq.py 1 100`; do
81 > echo $i > $i
82 > done
83 $ hg ci -qAm 'add 100 files'
84
85 $ hg update null
86 0 files updated, 0 files merged, 100 files removed, 0 files unresolved
87 $ hg update -v | grep 100
88 getting 100
89 100 files updated, 0 files merged, 0 files removed, 0 files unresolved
90
91 $ cd ..
92
93 #endif
@@ -1,1097 +1,1097 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 updating [===========================================>] 1/1\r (no-eol) (esc)
66 updating [===========================================>] 1/1\r (no-eol) (esc)
67 \r (no-eol) (esc)
67 \r (no-eol) (esc)
68 updating to branch default
68 updating to branch default
69 cloning subrepo sub2 from $TESTTMP/sub2
69 cloning subrepo sub2 from $TESTTMP/sub2
70 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 $ hg add -R main
71 $ hg add -R main
72 adding main/.hgsub (glob)
72 adding main/.hgsub (glob)
73 adding main/main (glob)
73 adding main/main (glob)
74 $ hg commit -R main -m "main import"
74 $ hg commit -R main -m "main import"
75
75
76 Cleaning both repositories, just as a clone -U
76 Cleaning both repositories, just as a clone -U
77
77
78 $ hg up -C -R sub2 null
78 $ hg up -C -R sub2 null
79 \r (no-eol) (esc)
79 \r (no-eol) (esc)
80 updating [===========================================>] 1/1\r (no-eol) (esc)
80 updating [===========================================>] 1/1\r (no-eol) (esc)
81 \r (no-eol) (esc)
81 \r (no-eol) (esc)
82 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
82 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
83 $ hg up -C -R sub1 null
83 $ hg up -C -R sub1 null
84 \r (no-eol) (esc)
84 \r (no-eol) (esc)
85 updating [===========================================>] 1/1\r (no-eol) (esc)
85 updating [===========================================>] 1/1\r (no-eol) (esc)
86 \r (no-eol) (esc)
86 \r (no-eol) (esc)
87 \r (no-eol) (esc)
87 \r (no-eol) (esc)
88 updating [===========================================>] 3/3\r (no-eol) (esc)
88 updating [===========================================>] 3/3\r (no-eol) (esc)
89 \r (no-eol) (esc)
89 \r (no-eol) (esc)
90 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
90 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
91 $ hg up -C -R main null
91 $ hg up -C -R main null
92 \r (no-eol) (esc)
92 \r (no-eol) (esc)
93 updating [===========================================>] 1/1\r (no-eol) (esc)
93 updating [===========================================>] 1/1\r (no-eol) (esc)
94 \r (no-eol) (esc)
94 \r (no-eol) (esc)
95 \r (no-eol) (esc)
95 \r (no-eol) (esc)
96 updating [===========================================>] 3/3\r (no-eol) (esc)
96 updating [===========================================>] 3/3\r (no-eol) (esc)
97 \r (no-eol) (esc)
97 \r (no-eol) (esc)
98 \r (no-eol) (esc)
98 \r (no-eol) (esc)
99 updating [===========================================>] 3/3\r (no-eol) (esc)
99 updating [===========================================>] 3/3\r (no-eol) (esc)
100 \r (no-eol) (esc)
100 \r (no-eol) (esc)
101 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
101 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
102 $ rm -rf main/sub1
102 $ rm -rf main/sub1
103 $ rm -rf sub1/sub2
103 $ rm -rf sub1/sub2
104
104
105 Clone main
105 Clone main
106
106
107 $ hg --config extensions.largefiles= clone main cloned
107 $ hg --config extensions.largefiles= clone main cloned
108 \r (no-eol) (esc)
108 \r (no-eol) (esc)
109 linking [ <=> ] 1\r (no-eol) (esc)
109 linking [ <=> ] 1\r (no-eol) (esc)
110 linking [ <=> ] 2\r (no-eol) (esc)
110 linking [ <=> ] 2\r (no-eol) (esc)
111 linking [ <=> ] 3\r (no-eol) (esc)
111 linking [ <=> ] 3\r (no-eol) (esc)
112 linking [ <=> ] 4\r (no-eol) (esc)
112 linking [ <=> ] 4\r (no-eol) (esc)
113 linking [ <=> ] 5\r (no-eol) (esc)
113 linking [ <=> ] 5\r (no-eol) (esc)
114 linking [ <=> ] 6\r (no-eol) (esc)
114 linking [ <=> ] 6\r (no-eol) (esc)
115 linking [ <=> ] 7\r (no-eol) (esc)
115 linking [ <=> ] 7\r (no-eol) (esc)
116 linking [ <=> ] 8\r (no-eol) (esc)
116 linking [ <=> ] 8\r (no-eol) (esc)
117 \r (no-eol) (esc)
117 \r (no-eol) (esc)
118 \r (no-eol) (esc)
118 \r (no-eol) (esc)
119 updating [===========================================>] 3/3\r (no-eol) (esc)
119 updating [===========================================>] 3/3\r (no-eol) (esc)
120 updating [===========================================>] 3/3\r (no-eol) (esc)
120 updating [===========================================>] 3/3\r (no-eol) (esc)
121 updating [===========================================>] 1/1\r (no-eol) (esc)
121 updating [===========================================>] 1/1\r (no-eol) (esc)
122 \r (no-eol) (esc)
122 \r (no-eol) (esc)
123 updating to branch default
123 updating to branch default
124 cloning subrepo sub1 from $TESTTMP/sub1
124 cloning subrepo sub1 from $TESTTMP/sub1
125 cloning subrepo sub1/sub2 from $TESTTMP/sub2 (glob)
125 cloning subrepo sub1/sub2 from $TESTTMP/sub2 (glob)
126 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
126 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
127
127
128 Largefiles is NOT enabled in the clone if the source repo doesn't require it
128 Largefiles is NOT enabled in the clone if the source repo doesn't require it
129 $ cat cloned/.hg/hgrc
129 $ cat cloned/.hg/hgrc
130 # example repository config (see 'hg help config' for more info)
130 # example repository config (see 'hg help config' for more info)
131 [paths]
131 [paths]
132 default = $TESTTMP/main (glob)
132 default = $TESTTMP/main (glob)
133
133
134 # path aliases to other clones of this repo in URLs or filesystem paths
134 # path aliases to other clones of this repo in URLs or filesystem paths
135 # (see 'hg help config.paths' for more info)
135 # (see 'hg help config.paths' for more info)
136 #
136 #
137 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
137 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
138 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
138 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
139 # my-clone = /home/jdoe/jdoes-clone
139 # my-clone = /home/jdoe/jdoes-clone
140
140
141 [ui]
141 [ui]
142 # name and email (local to this repository, optional), e.g.
142 # name and email (local to this repository, optional), e.g.
143 # username = Jane Doe <jdoe@example.com>
143 # username = Jane Doe <jdoe@example.com>
144
144
145 Checking cloned repo ids
145 Checking cloned repo ids
146
146
147 $ printf "cloned " ; hg id -R cloned
147 $ printf "cloned " ; hg id -R cloned
148 cloned 7f491f53a367 tip
148 cloned 7f491f53a367 tip
149 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
149 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
150 cloned/sub1 fc3b4ce2696f tip
150 cloned/sub1 fc3b4ce2696f tip
151 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
151 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
152 cloned/sub1/sub2 c57a0840e3ba tip
152 cloned/sub1/sub2 c57a0840e3ba tip
153
153
154 debugsub output for main and sub1
154 debugsub output for main and sub1
155
155
156 $ hg debugsub -R cloned
156 $ hg debugsub -R cloned
157 path sub1
157 path sub1
158 source ../sub1
158 source ../sub1
159 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
159 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
160 $ hg debugsub -R cloned/sub1
160 $ hg debugsub -R cloned/sub1
161 path sub2
161 path sub2
162 source ../sub2
162 source ../sub2
163 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
163 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
164
164
165 Modifying deeply nested 'sub2'
165 Modifying deeply nested 'sub2'
166
166
167 $ echo modified > cloned/sub1/sub2/sub2
167 $ echo modified > cloned/sub1/sub2/sub2
168 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
168 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
169 committing subrepository sub1
169 committing subrepository sub1
170 committing subrepository sub1/sub2 (glob)
170 committing subrepository sub1/sub2 (glob)
171
171
172 Checking modified node ids
172 Checking modified node ids
173
173
174 $ printf "cloned " ; hg id -R cloned
174 $ printf "cloned " ; hg id -R cloned
175 cloned ffe6649062fe tip
175 cloned ffe6649062fe tip
176 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
176 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
177 cloned/sub1 2ecb03bf44a9 tip
177 cloned/sub1 2ecb03bf44a9 tip
178 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
178 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
179 cloned/sub1/sub2 53dd3430bcaf tip
179 cloned/sub1/sub2 53dd3430bcaf tip
180
180
181 debugsub output for main and sub1
181 debugsub output for main and sub1
182
182
183 $ hg debugsub -R cloned
183 $ hg debugsub -R cloned
184 path sub1
184 path sub1
185 source ../sub1
185 source ../sub1
186 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
186 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
187 $ hg debugsub -R cloned/sub1
187 $ hg debugsub -R cloned/sub1
188 path sub2
188 path sub2
189 source ../sub2
189 source ../sub2
190 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
190 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
191
191
192 Check that deep archiving works
192 Check that deep archiving works
193
193
194 $ cd cloned
194 $ cd cloned
195 $ echo 'test' > sub1/sub2/test.txt
195 $ echo 'test' > sub1/sub2/test.txt
196 $ hg --config extensions.largefiles=! add sub1/sub2/test.txt
196 $ hg --config extensions.largefiles=! add sub1/sub2/test.txt
197 $ mkdir sub1/sub2/folder
197 $ mkdir sub1/sub2/folder
198 $ echo 'subfolder' > sub1/sub2/folder/test.txt
198 $ echo 'subfolder' > sub1/sub2/folder/test.txt
199 $ hg ci -ASm "add test.txt"
199 $ hg ci -ASm "add test.txt"
200 adding sub1/sub2/folder/test.txt
200 adding sub1/sub2/folder/test.txt
201 committing subrepository sub1
201 committing subrepository sub1
202 committing subrepository sub1/sub2 (glob)
202 committing subrepository sub1/sub2 (glob)
203
203
204 .. but first take a detour through some deep removal testing
204 .. but first take a detour through some deep removal testing
205
205
206 $ hg remove -S -I 're:.*.txt' .
206 $ hg remove -S -I 're:.*.txt' .
207 \r (no-eol) (esc)
207 \r (no-eol) (esc)
208 searching [==========================================>] 1/1\r (no-eol) (esc)
208 searching [==========================================>] 1/1\r (no-eol) (esc)
209 searching [==========================================>] 1/1\r (no-eol) (esc)
209 searching [==========================================>] 1/1\r (no-eol) (esc)
210 \r (no-eol) (esc)
210 \r (no-eol) (esc)
211 \r (no-eol) (esc)
211 \r (no-eol) (esc)
212 deleting [=====================> ] 1/2\r (no-eol) (esc)
212 deleting [=====================> ] 1/2\r (no-eol) (esc)
213 \r (no-eol) (esc)
213 \r (no-eol) (esc)
214 \r (no-eol) (esc)
214 \r (no-eol) (esc)
215 deleting [===========================================>] 2/2\r (no-eol) (esc)
215 deleting [===========================================>] 2/2\r (no-eol) (esc)
216 \r (no-eol) (esc)
216 \r (no-eol) (esc)
217 removing sub1/sub2/folder/test.txt (glob)
217 removing sub1/sub2/folder/test.txt (glob)
218 removing sub1/sub2/test.txt (glob)
218 removing sub1/sub2/test.txt (glob)
219 $ hg status -S
219 $ hg status -S
220 R sub1/sub2/folder/test.txt
220 R sub1/sub2/folder/test.txt
221 R sub1/sub2/test.txt
221 R sub1/sub2/test.txt
222 $ hg update -Cq
222 $ hg update -Cq
223 $ hg remove -I 're:.*.txt' sub1
223 $ hg remove -I 're:.*.txt' sub1
224 \r (no-eol) (esc)
224 \r (no-eol) (esc)
225 searching [==========================================>] 1/1\r (no-eol) (esc)
225 searching [==========================================>] 1/1\r (no-eol) (esc)
226 \r (no-eol) (esc)
226 \r (no-eol) (esc)
227 \r (no-eol) (esc)
227 \r (no-eol) (esc)
228 deleting [===========================================>] 1/1\r (no-eol) (esc)
228 deleting [===========================================>] 1/1\r (no-eol) (esc)
229 \r (no-eol) (esc)
229 \r (no-eol) (esc)
230 $ hg status -S
230 $ hg status -S
231 $ hg remove sub1/sub2/folder/test.txt
231 $ hg remove sub1/sub2/folder/test.txt
232 \r (no-eol) (esc)
232 \r (no-eol) (esc)
233 searching [==========================================>] 1/1\r (no-eol) (esc)
233 searching [==========================================>] 1/1\r (no-eol) (esc)
234 searching [==========================================>] 1/1\r (no-eol) (esc)
234 searching [==========================================>] 1/1\r (no-eol) (esc)
235 \r (no-eol) (esc)
235 \r (no-eol) (esc)
236 \r (no-eol) (esc)
236 \r (no-eol) (esc)
237 deleting [===========================================>] 1/1\r (no-eol) (esc)
237 deleting [===========================================>] 1/1\r (no-eol) (esc)
238 \r (no-eol) (esc)
238 \r (no-eol) (esc)
239 \r (no-eol) (esc)
239 \r (no-eol) (esc)
240 deleting [===========================================>] 1/1\r (no-eol) (esc)
240 deleting [===========================================>] 1/1\r (no-eol) (esc)
241 \r (no-eol) (esc)
241 \r (no-eol) (esc)
242 \r (no-eol) (esc)
242 \r (no-eol) (esc)
243 deleting [===========================================>] 1/1\r (no-eol) (esc)
243 deleting [===========================================>] 1/1\r (no-eol) (esc)
244 \r (no-eol) (esc)
244 \r (no-eol) (esc)
245 $ hg remove sub1/.hgsubstate
245 $ hg remove sub1/.hgsubstate
246 \r (no-eol) (esc)
246 \r (no-eol) (esc)
247 searching [==========================================>] 1/1\r (no-eol) (esc)
247 searching [==========================================>] 1/1\r (no-eol) (esc)
248 \r (no-eol) (esc)
248 \r (no-eol) (esc)
249 \r (no-eol) (esc)
249 \r (no-eol) (esc)
250 deleting [===========================================>] 1/1\r (no-eol) (esc)
250 deleting [===========================================>] 1/1\r (no-eol) (esc)
251 \r (no-eol) (esc)
251 \r (no-eol) (esc)
252 \r (no-eol) (esc)
252 \r (no-eol) (esc)
253 deleting [===========================================>] 1/1\r (no-eol) (esc)
253 deleting [===========================================>] 1/1\r (no-eol) (esc)
254 \r (no-eol) (esc)
254 \r (no-eol) (esc)
255 $ mv sub1/.hgsub sub1/x.hgsub
255 $ mv sub1/.hgsub sub1/x.hgsub
256 $ hg status -S
256 $ hg status -S
257 warning: subrepo spec file 'sub1/.hgsub' not found
257 warning: subrepo spec file 'sub1/.hgsub' not found
258 R sub1/.hgsubstate
258 R sub1/.hgsubstate
259 R sub1/sub2/folder/test.txt
259 R sub1/sub2/folder/test.txt
260 ! sub1/.hgsub
260 ! sub1/.hgsub
261 ? sub1/x.hgsub
261 ? sub1/x.hgsub
262 $ mv sub1/x.hgsub sub1/.hgsub
262 $ mv sub1/x.hgsub sub1/.hgsub
263 $ hg update -Cq
263 $ hg update -Cq
264 $ touch sub1/foo
264 $ touch sub1/foo
265 $ hg forget sub1/sub2/folder/test.txt
265 $ hg forget sub1/sub2/folder/test.txt
266 $ rm sub1/sub2/test.txt
266 $ rm sub1/sub2/test.txt
267
267
268 Test relative path printing + subrepos
268 Test relative path printing + subrepos
269 $ mkdir -p foo/bar
269 $ mkdir -p foo/bar
270 $ cd foo
270 $ cd foo
271 $ touch bar/abc
271 $ touch bar/abc
272 $ hg addremove -S ..
272 $ hg addremove -S ..
273 \r (no-eol) (esc)
273 \r (no-eol) (esc)
274 searching for exact renames [ ] 0/1\r (no-eol) (esc)
274 searching for exact renames [ ] 0/1\r (no-eol) (esc)
275 \r (no-eol) (esc)
275 \r (no-eol) (esc)
276 adding ../sub1/sub2/folder/test.txt (glob)
276 adding ../sub1/sub2/folder/test.txt (glob)
277 removing ../sub1/sub2/test.txt (glob)
277 removing ../sub1/sub2/test.txt (glob)
278 adding ../sub1/foo (glob)
278 adding ../sub1/foo (glob)
279 adding bar/abc (glob)
279 adding bar/abc (glob)
280 $ cd ..
280 $ cd ..
281 $ hg status -S
281 $ hg status -S
282 A foo/bar/abc
282 A foo/bar/abc
283 A sub1/foo
283 A sub1/foo
284 R sub1/sub2/test.txt
284 R sub1/sub2/test.txt
285
285
286 Archive wdir() with subrepos
286 Archive wdir() with subrepos
287 $ hg rm main
287 $ hg rm main
288 \r (no-eol) (esc)
288 \r (no-eol) (esc)
289 deleting [===========================================>] 1/1\r (no-eol) (esc)
289 deleting [===========================================>] 1/1\r (no-eol) (esc)
290 \r (no-eol) (esc)
290 \r (no-eol) (esc)
291 $ hg archive -S -r 'wdir()' ../wdir
291 $ hg archive -S -r 'wdir()' ../wdir
292 \r (no-eol) (esc)
292 \r (no-eol) (esc)
293 archiving [ ] 0/3\r (no-eol) (esc)
293 archiving [ ] 0/3\r (no-eol) (esc)
294 archiving [=============> ] 1/3\r (no-eol) (esc)
294 archiving [=============> ] 1/3\r (no-eol) (esc)
295 archiving [===========================> ] 2/3\r (no-eol) (esc)
295 archiving [===========================> ] 2/3\r (no-eol) (esc)
296 archiving [==========================================>] 3/3\r (no-eol) (esc)
296 archiving [==========================================>] 3/3\r (no-eol) (esc)
297 \r (no-eol) (esc)
297 \r (no-eol) (esc)
298 \r (no-eol) (esc)
298 \r (no-eol) (esc)
299 archiving (sub1) [ ] 0/4\r (no-eol) (esc)
299 archiving (sub1) [ ] 0/4\r (no-eol) (esc)
300 archiving (sub1) [========> ] 1/4\r (no-eol) (esc)
300 archiving (sub1) [========> ] 1/4\r (no-eol) (esc)
301 archiving (sub1) [=================> ] 2/4\r (no-eol) (esc)
301 archiving (sub1) [=================> ] 2/4\r (no-eol) (esc)
302 archiving (sub1) [==========================> ] 3/4\r (no-eol) (esc)
302 archiving (sub1) [==========================> ] 3/4\r (no-eol) (esc)
303 archiving (sub1) [===================================>] 4/4\r (no-eol) (esc)
303 archiving (sub1) [===================================>] 4/4\r (no-eol) (esc)
304 \r (no-eol) (esc)
304 \r (no-eol) (esc)
305 \r (no-eol) (esc)
305 \r (no-eol) (esc)
306 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
306 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
307 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
307 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
308 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
308 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
309 \r (no-eol) (esc)
309 \r (no-eol) (esc)
310 $ diff -r . ../wdir | egrep -v '\.hg$|^Common subdirectories:'
310 $ diff -r . ../wdir | egrep -v '\.hg$|^Common subdirectories:'
311 Only in ../wdir: .hg_archival.txt
311 Only in ../wdir: .hg_archival.txt
312
312
313 $ find ../wdir -type f | sort
313 $ find ../wdir -type f | sort
314 ../wdir/.hg_archival.txt
314 ../wdir/.hg_archival.txt
315 ../wdir/.hgsub
315 ../wdir/.hgsub
316 ../wdir/.hgsubstate
316 ../wdir/.hgsubstate
317 ../wdir/foo/bar/abc
317 ../wdir/foo/bar/abc
318 ../wdir/sub1/.hgsub
318 ../wdir/sub1/.hgsub
319 ../wdir/sub1/.hgsubstate
319 ../wdir/sub1/.hgsubstate
320 ../wdir/sub1/foo
320 ../wdir/sub1/foo
321 ../wdir/sub1/sub1
321 ../wdir/sub1/sub1
322 ../wdir/sub1/sub2/folder/test.txt
322 ../wdir/sub1/sub2/folder/test.txt
323 ../wdir/sub1/sub2/sub2
323 ../wdir/sub1/sub2/sub2
324
324
325 $ cat ../wdir/.hg_archival.txt
325 $ cat ../wdir/.hg_archival.txt
326 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
326 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
327 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd+
327 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd+
328 branch: default
328 branch: default
329 latesttag: null
329 latesttag: null
330 latesttagdistance: 4
330 latesttagdistance: 4
331 changessincelatesttag: 4
331 changessincelatesttag: 4
332
332
333 Attempting to archive 'wdir()' with a missing file is handled gracefully
333 Attempting to archive 'wdir()' with a missing file is handled gracefully
334 $ rm sub1/sub1
334 $ rm sub1/sub1
335 $ rm -r ../wdir
335 $ rm -r ../wdir
336 $ hg archive -v -S -r 'wdir()' ../wdir
336 $ hg archive -v -S -r 'wdir()' ../wdir
337 \r (no-eol) (esc)
337 \r (no-eol) (esc)
338 archiving [ ] 0/3\r (no-eol) (esc)
338 archiving [ ] 0/3\r (no-eol) (esc)
339 archiving [=============> ] 1/3\r (no-eol) (esc)
339 archiving [=============> ] 1/3\r (no-eol) (esc)
340 archiving [===========================> ] 2/3\r (no-eol) (esc)
340 archiving [===========================> ] 2/3\r (no-eol) (esc)
341 archiving [==========================================>] 3/3\r (no-eol) (esc)
341 archiving [==========================================>] 3/3\r (no-eol) (esc)
342 \r (no-eol) (esc)
342 \r (no-eol) (esc)
343 \r (no-eol) (esc)
343 \r (no-eol) (esc)
344 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
344 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
345 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
345 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
346 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
346 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
347 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
347 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
348 \r (no-eol) (esc)
348 \r (no-eol) (esc)
349 \r (no-eol) (esc)
349 \r (no-eol) (esc)
350 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
350 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
351 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
351 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
352 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
352 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
353 \r (no-eol) (esc)
353 \r (no-eol) (esc)
354 $ find ../wdir -type f | sort
354 $ find ../wdir -type f | sort
355 ../wdir/.hg_archival.txt
355 ../wdir/.hg_archival.txt
356 ../wdir/.hgsub
356 ../wdir/.hgsub
357 ../wdir/.hgsubstate
357 ../wdir/.hgsubstate
358 ../wdir/foo/bar/abc
358 ../wdir/foo/bar/abc
359 ../wdir/sub1/.hgsub
359 ../wdir/sub1/.hgsub
360 ../wdir/sub1/.hgsubstate
360 ../wdir/sub1/.hgsubstate
361 ../wdir/sub1/foo
361 ../wdir/sub1/foo
362 ../wdir/sub1/sub2/folder/test.txt
362 ../wdir/sub1/sub2/folder/test.txt
363 ../wdir/sub1/sub2/sub2
363 ../wdir/sub1/sub2/sub2
364
364
365 Continue relative path printing + subrepos
365 Continue relative path printing + subrepos
366 $ hg update -Cq
366 $ hg update -Cq
367 $ rm -r ../wdir
367 $ rm -r ../wdir
368 $ hg archive -S -r 'wdir()' ../wdir
368 $ hg archive -S -r 'wdir()' ../wdir
369 \r (no-eol) (esc)
369 \r (no-eol) (esc)
370 archiving [ ] 0/3\r (no-eol) (esc)
370 archiving [ ] 0/3\r (no-eol) (esc)
371 archiving [=============> ] 1/3\r (no-eol) (esc)
371 archiving [=============> ] 1/3\r (no-eol) (esc)
372 archiving [===========================> ] 2/3\r (no-eol) (esc)
372 archiving [===========================> ] 2/3\r (no-eol) (esc)
373 archiving [==========================================>] 3/3\r (no-eol) (esc)
373 archiving [==========================================>] 3/3\r (no-eol) (esc)
374 \r (no-eol) (esc)
374 \r (no-eol) (esc)
375 \r (no-eol) (esc)
375 \r (no-eol) (esc)
376 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
376 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
377 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
377 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
378 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
378 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
379 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
379 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
380 \r (no-eol) (esc)
380 \r (no-eol) (esc)
381 \r (no-eol) (esc)
381 \r (no-eol) (esc)
382 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
382 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
383 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
383 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
384 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
384 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
385 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
385 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
386 \r (no-eol) (esc)
386 \r (no-eol) (esc)
387 $ cat ../wdir/.hg_archival.txt
387 $ cat ../wdir/.hg_archival.txt
388 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
388 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
389 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd
389 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd
390 branch: default
390 branch: default
391 latesttag: null
391 latesttag: null
392 latesttagdistance: 4
392 latesttagdistance: 4
393 changessincelatesttag: 4
393 changessincelatesttag: 4
394
394
395 $ touch sub1/sub2/folder/bar
395 $ touch sub1/sub2/folder/bar
396 $ hg addremove sub1/sub2
396 $ hg addremove sub1/sub2
397 adding sub1/sub2/folder/bar (glob)
397 adding sub1/sub2/folder/bar (glob)
398 $ hg status -S
398 $ hg status -S
399 A sub1/sub2/folder/bar
399 A sub1/sub2/folder/bar
400 ? foo/bar/abc
400 ? foo/bar/abc
401 ? sub1/foo
401 ? sub1/foo
402 $ hg update -Cq
402 $ hg update -Cq
403 $ hg addremove sub1
403 $ hg addremove sub1
404 adding sub1/sub2/folder/bar (glob)
404 adding sub1/sub2/folder/bar (glob)
405 adding sub1/foo (glob)
405 adding sub1/foo (glob)
406 $ hg update -Cq
406 $ hg update -Cq
407 $ rm sub1/sub2/folder/test.txt
407 $ rm sub1/sub2/folder/test.txt
408 $ rm sub1/sub2/test.txt
408 $ rm sub1/sub2/test.txt
409 $ hg ci -ASm "remove test.txt"
409 $ hg ci -ASm "remove test.txt"
410 adding sub1/sub2/folder/bar
410 adding sub1/sub2/folder/bar
411 removing sub1/sub2/folder/test.txt
411 removing sub1/sub2/folder/test.txt
412 removing sub1/sub2/test.txt
412 removing sub1/sub2/test.txt
413 adding sub1/foo
413 adding sub1/foo
414 adding foo/bar/abc
414 adding foo/bar/abc
415 committing subrepository sub1
415 committing subrepository sub1
416 committing subrepository sub1/sub2 (glob)
416 committing subrepository sub1/sub2 (glob)
417
417
418 $ hg forget sub1/sub2/sub2
418 $ hg forget sub1/sub2/sub2
419 $ echo x > sub1/sub2/x.txt
419 $ echo x > sub1/sub2/x.txt
420 $ hg add sub1/sub2/x.txt
420 $ hg add sub1/sub2/x.txt
421
421
422 Files sees uncommitted adds and removes in subrepos
422 Files sees uncommitted adds and removes in subrepos
423 $ hg files -S
423 $ hg files -S
424 .hgsub
424 .hgsub
425 .hgsubstate
425 .hgsubstate
426 foo/bar/abc (glob)
426 foo/bar/abc (glob)
427 main
427 main
428 sub1/.hgsub (glob)
428 sub1/.hgsub (glob)
429 sub1/.hgsubstate (glob)
429 sub1/.hgsubstate (glob)
430 sub1/foo (glob)
430 sub1/foo (glob)
431 sub1/sub1 (glob)
431 sub1/sub1 (glob)
432 sub1/sub2/folder/bar (glob)
432 sub1/sub2/folder/bar (glob)
433 sub1/sub2/x.txt (glob)
433 sub1/sub2/x.txt (glob)
434
434
435 $ hg files -S "set:eol('dos') or eol('unix') or size('<= 0')"
435 $ hg files -S "set:eol('dos') or eol('unix') or size('<= 0')"
436 .hgsub
436 .hgsub
437 .hgsubstate
437 .hgsubstate
438 foo/bar/abc (glob)
438 foo/bar/abc (glob)
439 main
439 main
440 sub1/.hgsub (glob)
440 sub1/.hgsub (glob)
441 sub1/.hgsubstate (glob)
441 sub1/.hgsubstate (glob)
442 sub1/foo (glob)
442 sub1/foo (glob)
443 sub1/sub1 (glob)
443 sub1/sub1 (glob)
444 sub1/sub2/folder/bar (glob)
444 sub1/sub2/folder/bar (glob)
445 sub1/sub2/x.txt (glob)
445 sub1/sub2/x.txt (glob)
446
446
447 $ hg files -r '.^' -S "set:eol('dos') or eol('unix')"
447 $ hg files -r '.^' -S "set:eol('dos') or eol('unix')"
448 .hgsub
448 .hgsub
449 .hgsubstate
449 .hgsubstate
450 main
450 main
451 sub1/.hgsub (glob)
451 sub1/.hgsub (glob)
452 sub1/.hgsubstate (glob)
452 sub1/.hgsubstate (glob)
453 sub1/sub1 (glob)
453 sub1/sub1 (glob)
454 sub1/sub2/folder/test.txt (glob)
454 sub1/sub2/folder/test.txt (glob)
455 sub1/sub2/sub2 (glob)
455 sub1/sub2/sub2 (glob)
456 sub1/sub2/test.txt (glob)
456 sub1/sub2/test.txt (glob)
457
457
458 $ hg files sub1
458 $ hg files sub1
459 sub1/.hgsub (glob)
459 sub1/.hgsub (glob)
460 sub1/.hgsubstate (glob)
460 sub1/.hgsubstate (glob)
461 sub1/foo (glob)
461 sub1/foo (glob)
462 sub1/sub1 (glob)
462 sub1/sub1 (glob)
463 sub1/sub2/folder/bar (glob)
463 sub1/sub2/folder/bar (glob)
464 sub1/sub2/x.txt (glob)
464 sub1/sub2/x.txt (glob)
465
465
466 $ hg files sub1/sub2
466 $ hg files sub1/sub2
467 sub1/sub2/folder/bar (glob)
467 sub1/sub2/folder/bar (glob)
468 sub1/sub2/x.txt (glob)
468 sub1/sub2/x.txt (glob)
469
469
470 $ hg files
470 $ hg files
471 .hgsub
471 .hgsub
472 .hgsubstate
472 .hgsubstate
473 foo/bar/abc (glob)
473 foo/bar/abc (glob)
474 main
474 main
475
475
476 $ hg files -S -r '.^' sub1/sub2/folder
476 $ hg files -S -r '.^' sub1/sub2/folder
477 sub1/sub2/folder/test.txt (glob)
477 sub1/sub2/folder/test.txt (glob)
478
478
479 $ hg files -S -r '.^' sub1/sub2/missing
479 $ hg files -S -r '.^' sub1/sub2/missing
480 sub1/sub2/missing: no such file in rev 78026e779ea6 (glob)
480 sub1/sub2/missing: no such file in rev 78026e779ea6 (glob)
481 [1]
481 [1]
482
482
483 $ hg files -r '.^' sub1/
483 $ hg files -r '.^' sub1/
484 sub1/.hgsub (glob)
484 sub1/.hgsub (glob)
485 sub1/.hgsubstate (glob)
485 sub1/.hgsubstate (glob)
486 sub1/sub1 (glob)
486 sub1/sub1 (glob)
487 sub1/sub2/folder/test.txt (glob)
487 sub1/sub2/folder/test.txt (glob)
488 sub1/sub2/sub2 (glob)
488 sub1/sub2/sub2 (glob)
489 sub1/sub2/test.txt (glob)
489 sub1/sub2/test.txt (glob)
490
490
491 $ hg files -r '.^' sub1/sub2
491 $ hg files -r '.^' sub1/sub2
492 sub1/sub2/folder/test.txt (glob)
492 sub1/sub2/folder/test.txt (glob)
493 sub1/sub2/sub2 (glob)
493 sub1/sub2/sub2 (glob)
494 sub1/sub2/test.txt (glob)
494 sub1/sub2/test.txt (glob)
495
495
496 $ hg rollback -q
496 $ hg rollback -q
497 $ hg up -Cq
497 $ hg up -Cq
498
498
499 $ hg --config extensions.largefiles=! archive -S ../archive_all
499 $ hg --config extensions.largefiles=! archive -S ../archive_all
500 \r (no-eol) (esc)
500 \r (no-eol) (esc)
501 archiving [ ] 0/3\r (no-eol) (esc)
501 archiving [ ] 0/3\r (no-eol) (esc)
502 archiving [=============> ] 1/3\r (no-eol) (esc)
502 archiving [=============> ] 1/3\r (no-eol) (esc)
503 archiving [===========================> ] 2/3\r (no-eol) (esc)
503 archiving [===========================> ] 2/3\r (no-eol) (esc)
504 archiving [==========================================>] 3/3\r (no-eol) (esc)
504 archiving [==========================================>] 3/3\r (no-eol) (esc)
505 \r (no-eol) (esc)
505 \r (no-eol) (esc)
506 \r (no-eol) (esc)
506 \r (no-eol) (esc)
507 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
507 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
508 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
508 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
509 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
509 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
510 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
510 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
511 \r (no-eol) (esc)
511 \r (no-eol) (esc)
512 \r (no-eol) (esc)
512 \r (no-eol) (esc)
513 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
513 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
514 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
514 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
515 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
515 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
516 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
516 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
517 \r (no-eol) (esc)
517 \r (no-eol) (esc)
518 $ find ../archive_all | sort
518 $ find ../archive_all | sort
519 ../archive_all
519 ../archive_all
520 ../archive_all/.hg_archival.txt
520 ../archive_all/.hg_archival.txt
521 ../archive_all/.hgsub
521 ../archive_all/.hgsub
522 ../archive_all/.hgsubstate
522 ../archive_all/.hgsubstate
523 ../archive_all/main
523 ../archive_all/main
524 ../archive_all/sub1
524 ../archive_all/sub1
525 ../archive_all/sub1/.hgsub
525 ../archive_all/sub1/.hgsub
526 ../archive_all/sub1/.hgsubstate
526 ../archive_all/sub1/.hgsubstate
527 ../archive_all/sub1/sub1
527 ../archive_all/sub1/sub1
528 ../archive_all/sub1/sub2
528 ../archive_all/sub1/sub2
529 ../archive_all/sub1/sub2/folder
529 ../archive_all/sub1/sub2/folder
530 ../archive_all/sub1/sub2/folder/test.txt
530 ../archive_all/sub1/sub2/folder/test.txt
531 ../archive_all/sub1/sub2/sub2
531 ../archive_all/sub1/sub2/sub2
532 ../archive_all/sub1/sub2/test.txt
532 ../archive_all/sub1/sub2/test.txt
533
533
534 Check that archive -X works in deep subrepos
534 Check that archive -X works in deep subrepos
535
535
536 $ hg --config extensions.largefiles=! archive -S -X '**test*' ../archive_exclude
536 $ hg --config extensions.largefiles=! archive -S -X '**test*' ../archive_exclude
537 \r (no-eol) (esc)
537 \r (no-eol) (esc)
538 archiving [ ] 0/3\r (no-eol) (esc)
538 archiving [ ] 0/3\r (no-eol) (esc)
539 archiving [=============> ] 1/3\r (no-eol) (esc)
539 archiving [=============> ] 1/3\r (no-eol) (esc)
540 archiving [===========================> ] 2/3\r (no-eol) (esc)
540 archiving [===========================> ] 2/3\r (no-eol) (esc)
541 archiving [==========================================>] 3/3\r (no-eol) (esc)
541 archiving [==========================================>] 3/3\r (no-eol) (esc)
542 \r (no-eol) (esc)
542 \r (no-eol) (esc)
543 \r (no-eol) (esc)
543 \r (no-eol) (esc)
544 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
544 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
545 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
545 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
546 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
546 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
547 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
547 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
548 \r (no-eol) (esc)
548 \r (no-eol) (esc)
549 \r (no-eol) (esc)
549 \r (no-eol) (esc)
550 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
550 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
551 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
551 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
552 \r (no-eol) (esc)
552 \r (no-eol) (esc)
553 $ find ../archive_exclude | sort
553 $ find ../archive_exclude | sort
554 ../archive_exclude
554 ../archive_exclude
555 ../archive_exclude/.hg_archival.txt
555 ../archive_exclude/.hg_archival.txt
556 ../archive_exclude/.hgsub
556 ../archive_exclude/.hgsub
557 ../archive_exclude/.hgsubstate
557 ../archive_exclude/.hgsubstate
558 ../archive_exclude/main
558 ../archive_exclude/main
559 ../archive_exclude/sub1
559 ../archive_exclude/sub1
560 ../archive_exclude/sub1/.hgsub
560 ../archive_exclude/sub1/.hgsub
561 ../archive_exclude/sub1/.hgsubstate
561 ../archive_exclude/sub1/.hgsubstate
562 ../archive_exclude/sub1/sub1
562 ../archive_exclude/sub1/sub1
563 ../archive_exclude/sub1/sub2
563 ../archive_exclude/sub1/sub2
564 ../archive_exclude/sub1/sub2/sub2
564 ../archive_exclude/sub1/sub2/sub2
565
565
566 $ hg --config extensions.largefiles=! archive -S -I '**test*' ../archive_include
566 $ hg --config extensions.largefiles=! archive -S -I '**test*' ../archive_include
567 \r (no-eol) (esc)
567 \r (no-eol) (esc)
568 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
568 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
569 \r (no-eol) (esc)
569 \r (no-eol) (esc)
570 \r (no-eol) (esc)
570 \r (no-eol) (esc)
571 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
571 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
572 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
572 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
573 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
573 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
574 \r (no-eol) (esc)
574 \r (no-eol) (esc)
575 $ find ../archive_include | sort
575 $ find ../archive_include | sort
576 ../archive_include
576 ../archive_include
577 ../archive_include/sub1
577 ../archive_include/sub1
578 ../archive_include/sub1/sub2
578 ../archive_include/sub1/sub2
579 ../archive_include/sub1/sub2/folder
579 ../archive_include/sub1/sub2/folder
580 ../archive_include/sub1/sub2/folder/test.txt
580 ../archive_include/sub1/sub2/folder/test.txt
581 ../archive_include/sub1/sub2/test.txt
581 ../archive_include/sub1/sub2/test.txt
582
582
583 Check that deep archive works with largefiles (which overrides hgsubrepo impl)
583 Check that deep archive works with largefiles (which overrides hgsubrepo impl)
584 This also tests the repo.ui regression in 43fb170a23bd, and that lf subrepo
584 This also tests the repo.ui regression in 43fb170a23bd, and that lf subrepo
585 subrepos are archived properly.
585 subrepos are archived properly.
586 Note that add --large through a subrepo currently adds the file as a normal file
586 Note that add --large through a subrepo currently adds the file as a normal file
587
587
588 $ echo "large" > sub1/sub2/large.bin
588 $ echo "large" > sub1/sub2/large.bin
589 $ hg --config extensions.largefiles= add --large -R sub1/sub2 sub1/sub2/large.bin
589 $ hg --config extensions.largefiles= add --large -R sub1/sub2 sub1/sub2/large.bin
590 $ echo "large" > large.bin
590 $ echo "large" > large.bin
591 $ hg --config extensions.largefiles= add --large large.bin
591 $ hg --config extensions.largefiles= add --large large.bin
592 $ hg --config extensions.largefiles= ci -S -m "add large files"
592 $ hg --config extensions.largefiles= ci -S -m "add large files"
593 committing subrepository sub1
593 committing subrepository sub1
594 committing subrepository sub1/sub2 (glob)
594 committing subrepository sub1/sub2 (glob)
595
595
596 $ hg --config extensions.largefiles= archive -S ../archive_lf
596 $ hg --config extensions.largefiles= archive -S ../archive_lf
597 $ find ../archive_lf | sort
597 $ find ../archive_lf | sort
598 ../archive_lf
598 ../archive_lf
599 ../archive_lf/.hg_archival.txt
599 ../archive_lf/.hg_archival.txt
600 ../archive_lf/.hgsub
600 ../archive_lf/.hgsub
601 ../archive_lf/.hgsubstate
601 ../archive_lf/.hgsubstate
602 ../archive_lf/large.bin
602 ../archive_lf/large.bin
603 ../archive_lf/main
603 ../archive_lf/main
604 ../archive_lf/sub1
604 ../archive_lf/sub1
605 ../archive_lf/sub1/.hgsub
605 ../archive_lf/sub1/.hgsub
606 ../archive_lf/sub1/.hgsubstate
606 ../archive_lf/sub1/.hgsubstate
607 ../archive_lf/sub1/sub1
607 ../archive_lf/sub1/sub1
608 ../archive_lf/sub1/sub2
608 ../archive_lf/sub1/sub2
609 ../archive_lf/sub1/sub2/folder
609 ../archive_lf/sub1/sub2/folder
610 ../archive_lf/sub1/sub2/folder/test.txt
610 ../archive_lf/sub1/sub2/folder/test.txt
611 ../archive_lf/sub1/sub2/large.bin
611 ../archive_lf/sub1/sub2/large.bin
612 ../archive_lf/sub1/sub2/sub2
612 ../archive_lf/sub1/sub2/sub2
613 ../archive_lf/sub1/sub2/test.txt
613 ../archive_lf/sub1/sub2/test.txt
614 $ rm -rf ../archive_lf
614 $ rm -rf ../archive_lf
615
615
616 Exclude large files from main and sub-sub repo
616 Exclude large files from main and sub-sub repo
617
617
618 $ hg --config extensions.largefiles= archive -S -X '**.bin' ../archive_lf
618 $ hg --config extensions.largefiles= archive -S -X '**.bin' ../archive_lf
619 $ find ../archive_lf | sort
619 $ find ../archive_lf | sort
620 ../archive_lf
620 ../archive_lf
621 ../archive_lf/.hg_archival.txt
621 ../archive_lf/.hg_archival.txt
622 ../archive_lf/.hgsub
622 ../archive_lf/.hgsub
623 ../archive_lf/.hgsubstate
623 ../archive_lf/.hgsubstate
624 ../archive_lf/main
624 ../archive_lf/main
625 ../archive_lf/sub1
625 ../archive_lf/sub1
626 ../archive_lf/sub1/.hgsub
626 ../archive_lf/sub1/.hgsub
627 ../archive_lf/sub1/.hgsubstate
627 ../archive_lf/sub1/.hgsubstate
628 ../archive_lf/sub1/sub1
628 ../archive_lf/sub1/sub1
629 ../archive_lf/sub1/sub2
629 ../archive_lf/sub1/sub2
630 ../archive_lf/sub1/sub2/folder
630 ../archive_lf/sub1/sub2/folder
631 ../archive_lf/sub1/sub2/folder/test.txt
631 ../archive_lf/sub1/sub2/folder/test.txt
632 ../archive_lf/sub1/sub2/sub2
632 ../archive_lf/sub1/sub2/sub2
633 ../archive_lf/sub1/sub2/test.txt
633 ../archive_lf/sub1/sub2/test.txt
634 $ rm -rf ../archive_lf
634 $ rm -rf ../archive_lf
635
635
636 Exclude normal files from main and sub-sub repo
636 Exclude normal files from main and sub-sub repo
637
637
638 $ hg --config extensions.largefiles= archive -S -X '**.txt' -p '.' ../archive_lf.tgz
638 $ hg --config extensions.largefiles= archive -S -X '**.txt' -p '.' ../archive_lf.tgz
639 $ tar -tzf ../archive_lf.tgz | sort
639 $ tar -tzf ../archive_lf.tgz | sort
640 .hgsub
640 .hgsub
641 .hgsubstate
641 .hgsubstate
642 large.bin
642 large.bin
643 main
643 main
644 sub1/.hgsub
644 sub1/.hgsub
645 sub1/.hgsubstate
645 sub1/.hgsubstate
646 sub1/sub1
646 sub1/sub1
647 sub1/sub2/large.bin
647 sub1/sub2/large.bin
648 sub1/sub2/sub2
648 sub1/sub2/sub2
649
649
650 Include normal files from within a largefiles subrepo
650 Include normal files from within a largefiles subrepo
651
651
652 $ hg --config extensions.largefiles= archive -S -I '**.txt' ../archive_lf
652 $ hg --config extensions.largefiles= archive -S -I '**.txt' ../archive_lf
653 $ find ../archive_lf | sort
653 $ find ../archive_lf | sort
654 ../archive_lf
654 ../archive_lf
655 ../archive_lf/.hg_archival.txt
655 ../archive_lf/.hg_archival.txt
656 ../archive_lf/sub1
656 ../archive_lf/sub1
657 ../archive_lf/sub1/sub2
657 ../archive_lf/sub1/sub2
658 ../archive_lf/sub1/sub2/folder
658 ../archive_lf/sub1/sub2/folder
659 ../archive_lf/sub1/sub2/folder/test.txt
659 ../archive_lf/sub1/sub2/folder/test.txt
660 ../archive_lf/sub1/sub2/test.txt
660 ../archive_lf/sub1/sub2/test.txt
661 $ rm -rf ../archive_lf
661 $ rm -rf ../archive_lf
662
662
663 Include large files from within a largefiles subrepo
663 Include large files from within a largefiles subrepo
664
664
665 $ hg --config extensions.largefiles= archive -S -I '**.bin' ../archive_lf
665 $ hg --config extensions.largefiles= archive -S -I '**.bin' ../archive_lf
666 $ find ../archive_lf | sort
666 $ find ../archive_lf | sort
667 ../archive_lf
667 ../archive_lf
668 ../archive_lf/large.bin
668 ../archive_lf/large.bin
669 ../archive_lf/sub1
669 ../archive_lf/sub1
670 ../archive_lf/sub1/sub2
670 ../archive_lf/sub1/sub2
671 ../archive_lf/sub1/sub2/large.bin
671 ../archive_lf/sub1/sub2/large.bin
672 $ rm -rf ../archive_lf
672 $ rm -rf ../archive_lf
673
673
674 Find an exact largefile match in a largefiles subrepo
674 Find an exact largefile match in a largefiles subrepo
675
675
676 $ hg --config extensions.largefiles= archive -S -I 'sub1/sub2/large.bin' ../archive_lf
676 $ hg --config extensions.largefiles= archive -S -I 'sub1/sub2/large.bin' ../archive_lf
677 $ find ../archive_lf | sort
677 $ find ../archive_lf | sort
678 ../archive_lf
678 ../archive_lf
679 ../archive_lf/sub1
679 ../archive_lf/sub1
680 ../archive_lf/sub1/sub2
680 ../archive_lf/sub1/sub2
681 ../archive_lf/sub1/sub2/large.bin
681 ../archive_lf/sub1/sub2/large.bin
682 $ rm -rf ../archive_lf
682 $ rm -rf ../archive_lf
683
683
684 The local repo enables largefiles if a largefiles repo is cloned
684 The local repo enables largefiles if a largefiles repo is cloned
685 $ hg showconfig extensions
685 $ hg showconfig extensions
686 abort: repository requires features unknown to this Mercurial: largefiles!
686 abort: repository requires features unknown to this Mercurial: largefiles!
687 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
687 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
688 [255]
688 [255]
689 $ hg --config extensions.largefiles= clone -qU . ../lfclone
689 $ hg --config extensions.largefiles= clone -qU . ../lfclone
690 $ cat ../lfclone/.hg/hgrc
690 $ cat ../lfclone/.hg/hgrc
691 # example repository config (see 'hg help config' for more info)
691 # example repository config (see 'hg help config' for more info)
692 [paths]
692 [paths]
693 default = $TESTTMP/cloned (glob)
693 default = $TESTTMP/cloned (glob)
694
694
695 # path aliases to other clones of this repo in URLs or filesystem paths
695 # path aliases to other clones of this repo in URLs or filesystem paths
696 # (see 'hg help config.paths' for more info)
696 # (see 'hg help config.paths' for more info)
697 #
697 #
698 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
698 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
699 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
699 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
700 # my-clone = /home/jdoe/jdoes-clone
700 # my-clone = /home/jdoe/jdoes-clone
701
701
702 [ui]
702 [ui]
703 # name and email (local to this repository, optional), e.g.
703 # name and email (local to this repository, optional), e.g.
704 # username = Jane Doe <jdoe@example.com>
704 # username = Jane Doe <jdoe@example.com>
705
705
706 [extensions]
706 [extensions]
707 largefiles=
707 largefiles=
708
708
709 Find an exact match to a standin (should archive nothing)
709 Find an exact match to a standin (should archive nothing)
710 $ hg --config extensions.largefiles= archive -S -I 'sub/sub2/.hglf/large.bin' ../archive_lf
710 $ hg --config extensions.largefiles= archive -S -I 'sub/sub2/.hglf/large.bin' ../archive_lf
711 $ find ../archive_lf 2> /dev/null | sort
711 $ find ../archive_lf 2> /dev/null | sort
712
712
713 $ cat >> $HGRCPATH <<EOF
713 $ cat >> $HGRCPATH <<EOF
714 > [extensions]
714 > [extensions]
715 > largefiles=
715 > largefiles=
716 > [largefiles]
716 > [largefiles]
717 > patterns=glob:**.dat
717 > patterns=glob:**.dat
718 > EOF
718 > EOF
719
719
720 Test forget through a deep subrepo with the largefiles extension, both a
720 Test forget through a deep subrepo with the largefiles extension, both a
721 largefile and a normal file. Then a largefile that hasn't been committed yet.
721 largefile and a normal file. Then a largefile that hasn't been committed yet.
722 $ touch sub1/sub2/untracked.txt
722 $ touch sub1/sub2/untracked.txt
723 $ touch sub1/sub2/large.dat
723 $ touch sub1/sub2/large.dat
724 $ hg forget sub1/sub2/large.bin sub1/sub2/test.txt sub1/sub2/untracked.txt
724 $ hg forget sub1/sub2/large.bin sub1/sub2/test.txt sub1/sub2/untracked.txt
725 not removing sub1/sub2/untracked.txt: file is already untracked (glob)
725 not removing sub1/sub2/untracked.txt: file is already untracked (glob)
726 [1]
726 [1]
727 $ hg add --large --dry-run -v sub1/sub2/untracked.txt
727 $ hg add --large --dry-run -v sub1/sub2/untracked.txt
728 adding sub1/sub2/untracked.txt as a largefile (glob)
728 adding sub1/sub2/untracked.txt as a largefile (glob)
729 $ hg add --large -v sub1/sub2/untracked.txt
729 $ hg add --large -v sub1/sub2/untracked.txt
730 adding sub1/sub2/untracked.txt as a largefile (glob)
730 adding sub1/sub2/untracked.txt as a largefile (glob)
731 $ hg add --normal -v sub1/sub2/large.dat
731 $ hg add --normal -v sub1/sub2/large.dat
732 adding sub1/sub2/large.dat (glob)
732 adding sub1/sub2/large.dat (glob)
733 $ hg forget -v sub1/sub2/untracked.txt
733 $ hg forget -v sub1/sub2/untracked.txt
734 removing sub1/sub2/untracked.txt (glob)
734 removing sub1/sub2/untracked.txt (glob)
735 $ hg status -S
735 $ hg status -S
736 A sub1/sub2/large.dat
736 A sub1/sub2/large.dat
737 R sub1/sub2/large.bin
737 R sub1/sub2/large.bin
738 R sub1/sub2/test.txt
738 R sub1/sub2/test.txt
739 ? foo/bar/abc
739 ? foo/bar/abc
740 ? sub1/sub2/untracked.txt
740 ? sub1/sub2/untracked.txt
741 ? sub1/sub2/x.txt
741 ? sub1/sub2/x.txt
742 $ hg add sub1/sub2
742 $ hg add sub1/sub2
743
743
744 $ hg archive -S -r 'wdir()' ../wdir2
744 $ hg archive -S -r 'wdir()' ../wdir2
745 $ diff -r . ../wdir2 | egrep -v '\.hg$|^Common subdirectories:'
745 $ diff -r . ../wdir2 | egrep -v '\.hg$|^Common subdirectories:'
746 Only in ../wdir2: .hg_archival.txt
746 Only in ../wdir2: .hg_archival.txt
747 Only in .: .hglf
747 Only in .: .hglf
748 Only in .: foo
748 Only in .: foo
749 Only in ./sub1/sub2: large.bin
749 Only in ./sub1/sub2: large.bin
750 Only in ./sub1/sub2: test.txt
750 Only in ./sub1/sub2: test.txt
751 Only in ./sub1/sub2: untracked.txt
751 Only in ./sub1/sub2: untracked.txt
752 Only in ./sub1/sub2: x.txt
752 Only in ./sub1/sub2: x.txt
753 $ find ../wdir2 -type f | sort
753 $ find ../wdir2 -type f | sort
754 ../wdir2/.hg_archival.txt
754 ../wdir2/.hg_archival.txt
755 ../wdir2/.hgsub
755 ../wdir2/.hgsub
756 ../wdir2/.hgsubstate
756 ../wdir2/.hgsubstate
757 ../wdir2/large.bin
757 ../wdir2/large.bin
758 ../wdir2/main
758 ../wdir2/main
759 ../wdir2/sub1/.hgsub
759 ../wdir2/sub1/.hgsub
760 ../wdir2/sub1/.hgsubstate
760 ../wdir2/sub1/.hgsubstate
761 ../wdir2/sub1/sub1
761 ../wdir2/sub1/sub1
762 ../wdir2/sub1/sub2/folder/test.txt
762 ../wdir2/sub1/sub2/folder/test.txt
763 ../wdir2/sub1/sub2/large.dat
763 ../wdir2/sub1/sub2/large.dat
764 ../wdir2/sub1/sub2/sub2
764 ../wdir2/sub1/sub2/sub2
765 $ hg status -S -mac -n | sort
765 $ hg status -S -mac -n | sort
766 .hgsub
766 .hgsub
767 .hgsubstate
767 .hgsubstate
768 large.bin
768 large.bin
769 main
769 main
770 sub1/.hgsub
770 sub1/.hgsub
771 sub1/.hgsubstate
771 sub1/.hgsubstate
772 sub1/sub1
772 sub1/sub1
773 sub1/sub2/folder/test.txt
773 sub1/sub2/folder/test.txt
774 sub1/sub2/large.dat
774 sub1/sub2/large.dat
775 sub1/sub2/sub2
775 sub1/sub2/sub2
776
776
777 $ hg ci -Sqm 'forget testing'
777 $ hg ci -Sqm 'forget testing'
778
778
779 Test 'wdir()' modified file archiving with largefiles
779 Test 'wdir()' modified file archiving with largefiles
780 $ echo 'mod' > main
780 $ echo 'mod' > main
781 $ echo 'mod' > large.bin
781 $ echo 'mod' > large.bin
782 $ echo 'mod' > sub1/sub2/large.dat
782 $ echo 'mod' > sub1/sub2/large.dat
783 $ hg archive -S -r 'wdir()' ../wdir3
783 $ hg archive -S -r 'wdir()' ../wdir3
784 $ diff -r . ../wdir3 | egrep -v '\.hg$|^Common subdirectories'
784 $ diff -r . ../wdir3 | egrep -v '\.hg$|^Common subdirectories'
785 Only in ../wdir3: .hg_archival.txt
785 Only in ../wdir3: .hg_archival.txt
786 Only in .: .hglf
786 Only in .: .hglf
787 Only in .: foo
787 Only in .: foo
788 Only in ./sub1/sub2: large.bin
788 Only in ./sub1/sub2: large.bin
789 Only in ./sub1/sub2: test.txt
789 Only in ./sub1/sub2: test.txt
790 Only in ./sub1/sub2: untracked.txt
790 Only in ./sub1/sub2: untracked.txt
791 Only in ./sub1/sub2: x.txt
791 Only in ./sub1/sub2: x.txt
792 $ find ../wdir3 -type f | sort
792 $ find ../wdir3 -type f | sort
793 ../wdir3/.hg_archival.txt
793 ../wdir3/.hg_archival.txt
794 ../wdir3/.hgsub
794 ../wdir3/.hgsub
795 ../wdir3/.hgsubstate
795 ../wdir3/.hgsubstate
796 ../wdir3/large.bin
796 ../wdir3/large.bin
797 ../wdir3/main
797 ../wdir3/main
798 ../wdir3/sub1/.hgsub
798 ../wdir3/sub1/.hgsub
799 ../wdir3/sub1/.hgsubstate
799 ../wdir3/sub1/.hgsubstate
800 ../wdir3/sub1/sub1
800 ../wdir3/sub1/sub1
801 ../wdir3/sub1/sub2/folder/test.txt
801 ../wdir3/sub1/sub2/folder/test.txt
802 ../wdir3/sub1/sub2/large.dat
802 ../wdir3/sub1/sub2/large.dat
803 ../wdir3/sub1/sub2/sub2
803 ../wdir3/sub1/sub2/sub2
804 $ hg up -Cq
804 $ hg up -Cq
805
805
806 Test issue4330: commit a directory where only normal files have changed
806 Test issue4330: commit a directory where only normal files have changed
807 $ touch foo/bar/large.dat
807 $ touch foo/bar/large.dat
808 $ hg add --large foo/bar/large.dat
808 $ hg add --large foo/bar/large.dat
809 $ hg ci -m 'add foo/bar/large.dat'
809 $ hg ci -m 'add foo/bar/large.dat'
810 $ touch a.txt
810 $ touch a.txt
811 $ touch a.dat
811 $ touch a.dat
812 $ hg add -v foo/bar/abc a.txt a.dat
812 $ hg add -v foo/bar/abc a.txt a.dat
813 adding a.dat as a largefile
813 adding a.dat as a largefile
814 adding a.txt
814 adding a.txt
815 adding foo/bar/abc (glob)
815 adding foo/bar/abc (glob)
816 $ hg ci -m 'dir commit with only normal file deltas' foo/bar
816 $ hg ci -m 'dir commit with only normal file deltas' foo/bar
817 $ hg status
817 $ hg status
818 A a.dat
818 A a.dat
819 A a.txt
819 A a.txt
820
820
821 Test a directory commit with a changed largefile and a changed normal file
821 Test a directory commit with a changed largefile and a changed normal file
822 $ echo changed > foo/bar/large.dat
822 $ echo changed > foo/bar/large.dat
823 $ echo changed > foo/bar/abc
823 $ echo changed > foo/bar/abc
824 $ hg ci -m 'dir commit with normal and lf file deltas' foo
824 $ hg ci -m 'dir commit with normal and lf file deltas' foo
825 $ hg status
825 $ hg status
826 A a.dat
826 A a.dat
827 A a.txt
827 A a.txt
828
828
829 $ hg ci -m "add a.*"
829 $ hg ci -m "add a.*"
830 $ hg mv a.dat b.dat
830 $ hg mv a.dat b.dat
831 $ hg mv foo/bar/abc foo/bar/def
831 $ hg mv foo/bar/abc foo/bar/def
832 $ hg status -C
832 $ hg status -C
833 A b.dat
833 A b.dat
834 a.dat
834 a.dat
835 A foo/bar/def
835 A foo/bar/def
836 foo/bar/abc
836 foo/bar/abc
837 R a.dat
837 R a.dat
838 R foo/bar/abc
838 R foo/bar/abc
839
839
840 $ hg ci -m "move large and normal"
840 $ hg ci -m "move large and normal"
841 $ hg status -C --rev '.^' --rev .
841 $ hg status -C --rev '.^' --rev .
842 A b.dat
842 A b.dat
843 a.dat
843 a.dat
844 A foo/bar/def
844 A foo/bar/def
845 foo/bar/abc
845 foo/bar/abc
846 R a.dat
846 R a.dat
847 R foo/bar/abc
847 R foo/bar/abc
848
848
849
849
850 $ echo foo > main
850 $ echo foo > main
851 $ hg ci -m "mod parent only"
851 $ hg ci -m "mod parent only"
852 $ hg init sub3
852 $ hg init sub3
853 $ echo "sub3 = sub3" >> .hgsub
853 $ echo "sub3 = sub3" >> .hgsub
854 $ echo xyz > sub3/a.txt
854 $ echo xyz > sub3/a.txt
855 $ hg add sub3/a.txt
855 $ hg add sub3/a.txt
856 $ hg ci -Sm "add sub3"
856 $ hg ci -Sm "add sub3"
857 committing subrepository sub3
857 committing subrepository sub3
858 $ cat .hgsub | grep -v sub3 > .hgsub1
858 $ cat .hgsub | grep -v sub3 > .hgsub1
859 $ mv .hgsub1 .hgsub
859 $ mv .hgsub1 .hgsub
860 $ hg ci -m "remove sub3"
860 $ hg ci -m "remove sub3"
861
861
862 $ hg log -r "subrepo()" --style compact
862 $ hg log -r "subrepo()" --style compact
863 0 7f491f53a367 1970-01-01 00:00 +0000 test
863 0 7f491f53a367 1970-01-01 00:00 +0000 test
864 main import
864 main import
865
865
866 1 ffe6649062fe 1970-01-01 00:00 +0000 test
866 1 ffe6649062fe 1970-01-01 00:00 +0000 test
867 deep nested modif should trigger a commit
867 deep nested modif should trigger a commit
868
868
869 2 9bb10eebee29 1970-01-01 00:00 +0000 test
869 2 9bb10eebee29 1970-01-01 00:00 +0000 test
870 add test.txt
870 add test.txt
871
871
872 3 7c64f035294f 1970-01-01 00:00 +0000 test
872 3 7c64f035294f 1970-01-01 00:00 +0000 test
873 add large files
873 add large files
874
874
875 4 f734a59e2e35 1970-01-01 00:00 +0000 test
875 4 f734a59e2e35 1970-01-01 00:00 +0000 test
876 forget testing
876 forget testing
877
877
878 11 9685a22af5db 1970-01-01 00:00 +0000 test
878 11 9685a22af5db 1970-01-01 00:00 +0000 test
879 add sub3
879 add sub3
880
880
881 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test
881 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test
882 remove sub3
882 remove sub3
883
883
884 $ hg log -r "subrepo('sub3')" --style compact
884 $ hg log -r "subrepo('sub3')" --style compact
885 11 9685a22af5db 1970-01-01 00:00 +0000 test
885 11 9685a22af5db 1970-01-01 00:00 +0000 test
886 add sub3
886 add sub3
887
887
888 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test
888 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test
889 remove sub3
889 remove sub3
890
890
891 $ hg log -r "subrepo('bogus')" --style compact
891 $ hg log -r "subrepo('bogus')" --style compact
892
892
893
893
894 Test .hgsubstate in the R state
894 Test .hgsubstate in the R state
895
895
896 $ hg rm .hgsub .hgsubstate
896 $ hg rm .hgsub .hgsubstate
897 \r (no-eol) (esc)
897 \r (no-eol) (esc)
898 deleting [=====================> ] 1/2\r (no-eol) (esc)
898 deleting [=====================> ] 1/2\r (no-eol) (esc)
899 deleting [===========================================>] 2/2\r (no-eol) (esc)
899 deleting [===========================================>] 2/2\r (no-eol) (esc)
900 \r (no-eol) (esc)
900 \r (no-eol) (esc)
901 $ hg ci -m 'trash subrepo tracking'
901 $ hg ci -m 'trash subrepo tracking'
902
902
903 $ hg log -r "subrepo('re:sub\d+')" --style compact
903 $ hg log -r "subrepo('re:sub\d+')" --style compact
904 0 7f491f53a367 1970-01-01 00:00 +0000 test
904 0 7f491f53a367 1970-01-01 00:00 +0000 test
905 main import
905 main import
906
906
907 1 ffe6649062fe 1970-01-01 00:00 +0000 test
907 1 ffe6649062fe 1970-01-01 00:00 +0000 test
908 deep nested modif should trigger a commit
908 deep nested modif should trigger a commit
909
909
910 2 9bb10eebee29 1970-01-01 00:00 +0000 test
910 2 9bb10eebee29 1970-01-01 00:00 +0000 test
911 add test.txt
911 add test.txt
912
912
913 3 7c64f035294f 1970-01-01 00:00 +0000 test
913 3 7c64f035294f 1970-01-01 00:00 +0000 test
914 add large files
914 add large files
915
915
916 4 f734a59e2e35 1970-01-01 00:00 +0000 test
916 4 f734a59e2e35 1970-01-01 00:00 +0000 test
917 forget testing
917 forget testing
918
918
919 11 9685a22af5db 1970-01-01 00:00 +0000 test
919 11 9685a22af5db 1970-01-01 00:00 +0000 test
920 add sub3
920 add sub3
921
921
922 12 2e0485b475b9 1970-01-01 00:00 +0000 test
922 12 2e0485b475b9 1970-01-01 00:00 +0000 test
923 remove sub3
923 remove sub3
924
924
925 13[tip] a68b2c361653 1970-01-01 00:00 +0000 test
925 13[tip] a68b2c361653 1970-01-01 00:00 +0000 test
926 trash subrepo tracking
926 trash subrepo tracking
927
927
928
928
929 Restore the trashed subrepo tracking
929 Restore the trashed subrepo tracking
930
930
931 $ hg rollback -q
931 $ hg rollback -q
932 $ hg update -Cq .
932 $ hg update -Cq .
933
933
934 Interaction with extdiff, largefiles and subrepos
934 Interaction with extdiff, largefiles and subrepos
935
935
936 $ hg --config extensions.extdiff= pdiff -S
936 $ hg --config extensions.extdiff= pdiff -S
937
937
938 $ hg --config extensions.extdiff= pdiff -r '.^' -S
938 $ hg --config extensions.extdiff= pdiff -r '.^' -S
939 \r (no-eol) (esc)
939 \r (no-eol) (esc)
940 archiving [ ] 0/2\r (no-eol) (esc)
940 archiving [ ] 0/2\r (no-eol) (esc)
941 archiving [====================> ] 1/2\r (no-eol) (esc)
941 archiving [====================> ] 1/2\r (no-eol) (esc)
942 archiving [==========================================>] 2/2\r (no-eol) (esc)
942 archiving [==========================================>] 2/2\r (no-eol) (esc)
943 \r (no-eol) (esc)
943 \r (no-eol) (esc)
944 \r (no-eol) (esc)
944 \r (no-eol) (esc)
945 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
945 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
946 \r (no-eol) (esc)
946 \r (no-eol) (esc)
947 \r (no-eol) (esc)
947 \r (no-eol) (esc)
948 archiving (sub1/sub2) [ <=> ] 0\r (no-eol) (glob) (esc)
948 archiving (sub1/sub2) [ <=> ] 0\r (no-eol) (glob) (esc)
949 \r (no-eol) (esc)
949 \r (no-eol) (esc)
950 \r (no-eol) (esc)
950 \r (no-eol) (esc)
951 archiving (sub3) [ <=> ] 0\r (no-eol) (esc)
951 archiving (sub3) [ <=> ] 0\r (no-eol) (esc)
952 \r (no-eol) (esc)
952 \r (no-eol) (esc)
953 \r (no-eol) (esc)
953 \r (no-eol) (esc)
954 archiving [ ] 0/2\r (no-eol) (esc)
954 archiving [ ] 0/2\r (no-eol) (esc)
955 archiving [====================> ] 1/2\r (no-eol) (esc)
955 archiving [====================> ] 1/2\r (no-eol) (esc)
956 archiving [==========================================>] 2/2\r (no-eol) (esc)
956 archiving [==========================================>] 2/2\r (no-eol) (esc)
957 \r (no-eol) (esc)
957 \r (no-eol) (esc)
958 \r (no-eol) (esc)
958 \r (no-eol) (esc)
959 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
959 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
960 \r (no-eol) (esc)
960 \r (no-eol) (esc)
961 \r (no-eol) (esc)
961 \r (no-eol) (esc)
962 archiving (sub1/sub2) [ <=> ] 0\r (no-eol) (glob) (esc)
962 archiving (sub1/sub2) [ <=> ] 0\r (no-eol) (glob) (esc)
963 \r (no-eol) (esc)
963 \r (no-eol) (esc)
964 diff -Nru cloned.*/.hgsub cloned/.hgsub (glob)
964 diff -Nru cloned.*/.hgsub cloned/.hgsub (glob)
965 --- cloned.*/.hgsub * (glob)
965 --- cloned.*/.hgsub * (glob)
966 +++ cloned/.hgsub * (glob)
966 +++ cloned/.hgsub * (glob)
967 @@ -1,2 +1* @@ (glob)
967 @@ -1,2 +1* @@ (glob)
968 sub1 = ../sub1
968 sub1 = ../sub1
969 -sub3 = sub3
969 -sub3 = sub3
970 diff -Nru cloned.*/.hgsubstate cloned/.hgsubstate (glob)
970 diff -Nru cloned.*/.hgsubstate cloned/.hgsubstate (glob)
971 --- cloned.*/.hgsubstate * (glob)
971 --- cloned.*/.hgsubstate * (glob)
972 +++ cloned/.hgsubstate * (glob)
972 +++ cloned/.hgsubstate * (glob)
973 @@ -1,2 +1* @@ (glob)
973 @@ -1,2 +1* @@ (glob)
974 7a36fa02b66e61f27f3d4a822809f159479b8ab2 sub1
974 7a36fa02b66e61f27f3d4a822809f159479b8ab2 sub1
975 -b1a26de6f2a045a9f079323693614ee322f1ff7e sub3
975 -b1a26de6f2a045a9f079323693614ee322f1ff7e sub3
976 [1]
976 [1]
977
977
978 $ hg --config extensions.extdiff= pdiff -r 0 -r '.^' -S
978 $ hg --config extensions.extdiff= pdiff -r 0 -r '.^' -S
979 \r (no-eol) (esc)
979 \r (no-eol) (esc)
980 archiving [ ] 0/3\r (no-eol) (esc)
980 archiving [ ] 0/3\r (no-eol) (esc)
981 archiving [=============> ] 1/3\r (no-eol) (esc)
981 archiving [=============> ] 1/3\r (no-eol) (esc)
982 archiving [===========================> ] 2/3\r (no-eol) (esc)
982 archiving [===========================> ] 2/3\r (no-eol) (esc)
983 archiving [==========================================>] 3/3\r (no-eol) (esc)
983 archiving [==========================================>] 3/3\r (no-eol) (esc)
984 \r (no-eol) (esc)
984 \r (no-eol) (esc)
985 \r (no-eol) (esc)
985 \r (no-eol) (esc)
986 archiving (sub1) [ ] 0/1\r (no-eol) (esc)
986 archiving (sub1) [ ] 0/1\r (no-eol) (esc)
987 archiving (sub1) [===================================>] 1/1\r (no-eol) (esc)
987 archiving (sub1) [===================================>] 1/1\r (no-eol) (esc)
988 \r (no-eol) (esc)
988 \r (no-eol) (esc)
989 \r (no-eol) (esc)
989 \r (no-eol) (esc)
990 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
990 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
991 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
991 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
992 \r (no-eol) (esc)
992 \r (no-eol) (esc)
993 \r (no-eol) (esc)
993 \r (no-eol) (esc)
994 archiving [ ] 0/8\r (no-eol) (esc)
994 archiving [ ] 0/8\r (no-eol) (esc)
995 archiving [====> ] 1/8\r (no-eol) (esc)
995 archiving [====> ] 1/8\r (no-eol) (esc)
996 archiving [=========> ] 2/8\r (no-eol) (esc)
996 archiving [=========> ] 2/8\r (no-eol) (esc)
997 archiving [===============> ] 3/8\r (no-eol) (esc)
997 archiving [===============> ] 3/8\r (no-eol) (esc)
998 archiving [====================> ] 4/8\r (no-eol) (esc)
998 archiving [====================> ] 4/8\r (no-eol) (esc)
999 archiving [=========================> ] 5/8\r (no-eol) (esc)
999 archiving [=========================> ] 5/8\r (no-eol) (esc)
1000 archiving [===============================> ] 6/8\r (no-eol) (esc)
1000 archiving [===============================> ] 6/8\r (no-eol) (esc)
1001 archiving [====================================> ] 7/8\r (no-eol) (esc)
1001 archiving [====================================> ] 7/8\r (no-eol) (esc)
1002 archiving [==========================================>] 8/8\r (no-eol) (esc)
1002 archiving [==========================================>] 8/8\r (no-eol) (esc)
1003 \r (no-eol) (esc)
1003 \r (no-eol) (esc)
1004 \r (no-eol) (esc)
1004 \r (no-eol) (esc)
1005 archiving (sub1) [ ] 0/1\r (no-eol) (esc)
1005 archiving (sub1) [ ] 0/1\r (no-eol) (esc)
1006 archiving (sub1) [===================================>] 1/1\r (no-eol) (esc)
1006 archiving (sub1) [===================================>] 1/1\r (no-eol) (esc)
1007 \r (no-eol) (esc)
1007 \r (no-eol) (esc)
1008 \r (no-eol) (esc)
1008 \r (no-eol) (esc)
1009 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
1009 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
1010 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
1010 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
1011 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
1011 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
1012 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
1012 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
1013 \r (no-eol) (esc)
1013 \r (no-eol) (esc)
1014 \r (no-eol) (esc)
1014 \r (no-eol) (esc)
1015 archiving (sub3) [ ] 0/1\r (no-eol) (esc)
1015 archiving (sub3) [ ] 0/1\r (no-eol) (esc)
1016 archiving (sub3) [===================================>] 1/1\r (no-eol) (esc)
1016 archiving (sub3) [===================================>] 1/1\r (no-eol) (esc)
1017 \r (no-eol) (esc)
1017 \r (no-eol) (esc)
1018 diff -Nru cloned.*/.hglf/b.dat cloned.*/.hglf/b.dat (glob)
1018 diff -Nru cloned.*/.hglf/b.dat cloned.*/.hglf/b.dat (glob)
1019 --- cloned.*/.hglf/b.dat * (glob)
1019 --- cloned.*/.hglf/b.dat * (glob)
1020 +++ cloned.*/.hglf/b.dat * (glob)
1020 +++ cloned.*/.hglf/b.dat * (glob)
1021 @@ -*,0 +1* @@ (glob)
1021 @@ -*,0 +1* @@ (glob)
1022 +da39a3ee5e6b4b0d3255bfef95601890afd80709
1022 +da39a3ee5e6b4b0d3255bfef95601890afd80709
1023 diff -Nru cloned.*/.hglf/foo/bar/large.dat cloned.*/.hglf/foo/bar/large.dat (glob)
1023 diff -Nru cloned.*/.hglf/foo/bar/large.dat cloned.*/.hglf/foo/bar/large.dat (glob)
1024 --- cloned.*/.hglf/foo/bar/large.dat * (glob)
1024 --- cloned.*/.hglf/foo/bar/large.dat * (glob)
1025 +++ cloned.*/.hglf/foo/bar/large.dat * (glob)
1025 +++ cloned.*/.hglf/foo/bar/large.dat * (glob)
1026 @@ -*,0 +1* @@ (glob)
1026 @@ -*,0 +1* @@ (glob)
1027 +2f6933b5ee0f5fdd823d9717d8729f3c2523811b
1027 +2f6933b5ee0f5fdd823d9717d8729f3c2523811b
1028 diff -Nru cloned.*/.hglf/large.bin cloned.*/.hglf/large.bin (glob)
1028 diff -Nru cloned.*/.hglf/large.bin cloned.*/.hglf/large.bin (glob)
1029 --- cloned.*/.hglf/large.bin * (glob)
1029 --- cloned.*/.hglf/large.bin * (glob)
1030 +++ cloned.*/.hglf/large.bin * (glob)
1030 +++ cloned.*/.hglf/large.bin * (glob)
1031 @@ -*,0 +1* @@ (glob)
1031 @@ -*,0 +1* @@ (glob)
1032 +7f7097b041ccf68cc5561e9600da4655d21c6d18
1032 +7f7097b041ccf68cc5561e9600da4655d21c6d18
1033 diff -Nru cloned.*/.hgsub cloned.*/.hgsub (glob)
1033 diff -Nru cloned.*/.hgsub cloned.*/.hgsub (glob)
1034 --- cloned.*/.hgsub * (glob)
1034 --- cloned.*/.hgsub * (glob)
1035 +++ cloned.*/.hgsub * (glob)
1035 +++ cloned.*/.hgsub * (glob)
1036 @@ -1* +1,2 @@ (glob)
1036 @@ -1* +1,2 @@ (glob)
1037 sub1 = ../sub1
1037 sub1 = ../sub1
1038 +sub3 = sub3
1038 +sub3 = sub3
1039 diff -Nru cloned.*/.hgsubstate cloned.*/.hgsubstate (glob)
1039 diff -Nru cloned.*/.hgsubstate cloned.*/.hgsubstate (glob)
1040 --- cloned.*/.hgsubstate * (glob)
1040 --- cloned.*/.hgsubstate * (glob)
1041 +++ cloned.*/.hgsubstate * (glob)
1041 +++ cloned.*/.hgsubstate * (glob)
1042 @@ -1* +1,2 @@ (glob)
1042 @@ -1* +1,2 @@ (glob)
1043 -fc3b4ce2696f7741438c79207583768f2ce6b0dd sub1
1043 -fc3b4ce2696f7741438c79207583768f2ce6b0dd sub1
1044 +7a36fa02b66e61f27f3d4a822809f159479b8ab2 sub1
1044 +7a36fa02b66e61f27f3d4a822809f159479b8ab2 sub1
1045 +b1a26de6f2a045a9f079323693614ee322f1ff7e sub3
1045 +b1a26de6f2a045a9f079323693614ee322f1ff7e sub3
1046 diff -Nru cloned.*/foo/bar/def cloned.*/foo/bar/def (glob)
1046 diff -Nru cloned.*/foo/bar/def cloned.*/foo/bar/def (glob)
1047 --- cloned.*/foo/bar/def * (glob)
1047 --- cloned.*/foo/bar/def * (glob)
1048 +++ cloned.*/foo/bar/def * (glob)
1048 +++ cloned.*/foo/bar/def * (glob)
1049 @@ -*,0 +1* @@ (glob)
1049 @@ -*,0 +1* @@ (glob)
1050 +changed
1050 +changed
1051 diff -Nru cloned.*/main cloned.*/main (glob)
1051 diff -Nru cloned.*/main cloned.*/main (glob)
1052 --- cloned.*/main * (glob)
1052 --- cloned.*/main * (glob)
1053 +++ cloned.*/main * (glob)
1053 +++ cloned.*/main * (glob)
1054 @@ -1* +1* @@ (glob)
1054 @@ -1* +1* @@ (glob)
1055 -main
1055 -main
1056 +foo
1056 +foo
1057 diff -Nru cloned.*/sub1/.hgsubstate cloned.*/sub1/.hgsubstate (glob)
1057 diff -Nru cloned.*/sub1/.hgsubstate cloned.*/sub1/.hgsubstate (glob)
1058 --- cloned.*/sub1/.hgsubstate * (glob)
1058 --- cloned.*/sub1/.hgsubstate * (glob)
1059 +++ cloned.*/sub1/.hgsubstate * (glob)
1059 +++ cloned.*/sub1/.hgsubstate * (glob)
1060 @@ -1* +1* @@ (glob)
1060 @@ -1* +1* @@ (glob)
1061 -c57a0840e3badd667ef3c3ef65471609acb2ba3c sub2
1061 -c57a0840e3badd667ef3c3ef65471609acb2ba3c sub2
1062 +c77908c81ccea3794a896c79e98b0e004aee2e9e sub2
1062 +c77908c81ccea3794a896c79e98b0e004aee2e9e sub2
1063 diff -Nru cloned.*/sub1/sub2/folder/test.txt cloned.*/sub1/sub2/folder/test.txt (glob)
1063 diff -Nru cloned.*/sub1/sub2/folder/test.txt cloned.*/sub1/sub2/folder/test.txt (glob)
1064 --- cloned.*/sub1/sub2/folder/test.txt * (glob)
1064 --- cloned.*/sub1/sub2/folder/test.txt * (glob)
1065 +++ cloned.*/sub1/sub2/folder/test.txt * (glob)
1065 +++ cloned.*/sub1/sub2/folder/test.txt * (glob)
1066 @@ -*,0 +1* @@ (glob)
1066 @@ -*,0 +1* @@ (glob)
1067 +subfolder
1067 +subfolder
1068 diff -Nru cloned.*/sub1/sub2/sub2 cloned.*/sub1/sub2/sub2 (glob)
1068 diff -Nru cloned.*/sub1/sub2/sub2 cloned.*/sub1/sub2/sub2 (glob)
1069 --- cloned.*/sub1/sub2/sub2 * (glob)
1069 --- cloned.*/sub1/sub2/sub2 * (glob)
1070 +++ cloned.*/sub1/sub2/sub2 * (glob)
1070 +++ cloned.*/sub1/sub2/sub2 * (glob)
1071 @@ -1* +1* @@ (glob)
1071 @@ -1* +1* @@ (glob)
1072 -sub2
1072 -sub2
1073 +modified
1073 +modified
1074 diff -Nru cloned.*/sub3/a.txt cloned.*/sub3/a.txt (glob)
1074 diff -Nru cloned.*/sub3/a.txt cloned.*/sub3/a.txt (glob)
1075 --- cloned.*/sub3/a.txt * (glob)
1075 --- cloned.*/sub3/a.txt * (glob)
1076 +++ cloned.*/sub3/a.txt * (glob)
1076 +++ cloned.*/sub3/a.txt * (glob)
1077 @@ -*,0 +1* @@ (glob)
1077 @@ -*,0 +1* @@ (glob)
1078 +xyz
1078 +xyz
1079 [1]
1079 [1]
1080
1080
1081 $ echo mod > sub1/sub2/sub2
1081 $ echo mod > sub1/sub2/sub2
1082 $ hg --config extensions.extdiff= pdiff -S
1082 $ hg --config extensions.extdiff= pdiff -S
1083 \r (no-eol) (esc)
1083 \r (no-eol) (esc)
1084 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
1084 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
1085 \r (no-eol) (esc)
1085 \r (no-eol) (esc)
1086 \r (no-eol) (esc)
1086 \r (no-eol) (esc)
1087 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
1087 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
1088 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
1088 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
1089 \r (no-eol) (esc)
1089 \r (no-eol) (esc)
1090 --- */cloned.*/sub1/sub2/sub2 * (glob)
1090 --- */cloned.*/sub1/sub2/sub2 * (glob)
1091 +++ */cloned/sub1/sub2/sub2 * (glob)
1091 +++ */cloned/sub1/sub2/sub2 * (glob)
1092 @@ -1* +1* @@ (glob)
1092 @@ -1* +1* @@ (glob)
1093 -modified
1093 -modified
1094 +mod
1094 +mod
1095 [1]
1095 [1]
1096
1096
1097 $ cd ..
1097 $ cd ..
@@ -1,331 +1,331 b''
1 Test basic functionality of url#rev syntax
1 Test basic functionality of url#rev syntax
2
2
3 $ hg init repo
3 $ hg init repo
4 $ cd repo
4 $ cd repo
5 $ echo a > a
5 $ echo a > a
6 $ hg ci -qAm 'add a'
6 $ hg ci -qAm 'add a'
7 $ hg branch foo
7 $ hg branch foo
8 marked working directory as branch foo
8 marked working directory as branch foo
9 (branches are permanent and global, did you want a bookmark?)
9 (branches are permanent and global, did you want a bookmark?)
10 $ echo >> a
10 $ echo >> a
11 $ hg ci -m 'change a'
11 $ hg ci -m 'change a'
12 $ cd ..
12 $ cd ..
13
13
14 $ hg clone 'repo#foo' clone
14 $ hg clone 'repo#foo' clone
15 adding changesets
15 adding changesets
16 adding manifests
16 adding manifests
17 adding file changes
17 adding file changes
18 added 2 changesets with 2 changes to 1 files
18 added 2 changesets with 2 changes to 1 files
19 updating to branch foo
19 updating to branch foo
20 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21
21
22 $ hg --cwd clone heads
22 $ hg --cwd clone heads
23 changeset: 1:cd2a86ecc814
23 changeset: 1:cd2a86ecc814
24 branch: foo
24 branch: foo
25 tag: tip
25 tag: tip
26 user: test
26 user: test
27 date: Thu Jan 01 00:00:00 1970 +0000
27 date: Thu Jan 01 00:00:00 1970 +0000
28 summary: change a
28 summary: change a
29
29
30 changeset: 0:1f0dee641bb7
30 changeset: 0:1f0dee641bb7
31 user: test
31 user: test
32 date: Thu Jan 01 00:00:00 1970 +0000
32 date: Thu Jan 01 00:00:00 1970 +0000
33 summary: add a
33 summary: add a
34
34
35 $ hg --cwd clone parents
35 $ hg --cwd clone parents
36 changeset: 1:cd2a86ecc814
36 changeset: 1:cd2a86ecc814
37 branch: foo
37 branch: foo
38 tag: tip
38 tag: tip
39 user: test
39 user: test
40 date: Thu Jan 01 00:00:00 1970 +0000
40 date: Thu Jan 01 00:00:00 1970 +0000
41 summary: change a
41 summary: change a
42
42
43 $ cat clone/.hg/hgrc
43 $ cat clone/.hg/hgrc
44 # example repository config (see 'hg help config' for more info)
44 # example repository config (see 'hg help config' for more info)
45 [paths]
45 [paths]
46 default = $TESTTMP/repo#foo (glob)
46 default = $TESTTMP/repo#foo (glob)
47
47
48 # path aliases to other clones of this repo in URLs or filesystem paths
48 # path aliases to other clones of this repo in URLs or filesystem paths
49 # (see 'hg help config.paths' for more info)
49 # (see 'hg help config.paths' for more info)
50 #
50 #
51 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
51 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
52 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
52 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
53 # my-clone = /home/jdoe/jdoes-clone
53 # my-clone = /home/jdoe/jdoes-clone
54
54
55 [ui]
55 [ui]
56 # name and email (local to this repository, optional), e.g.
56 # name and email (local to this repository, optional), e.g.
57 # username = Jane Doe <jdoe@example.com>
57 # username = Jane Doe <jdoe@example.com>
58
58
59 Changing original repo:
59 Changing original repo:
60
60
61 $ cd repo
61 $ cd repo
62
62
63 $ echo >> a
63 $ echo >> a
64 $ hg ci -m 'new head of branch foo'
64 $ hg ci -m 'new head of branch foo'
65
65
66 $ hg up -qC default
66 $ hg up -qC default
67 $ echo bar > bar
67 $ echo bar > bar
68 $ hg ci -qAm 'add bar'
68 $ hg ci -qAm 'add bar'
69
69
70 $ hg log
70 $ hg log
71 changeset: 3:4cd725637392
71 changeset: 3:4cd725637392
72 tag: tip
72 tag: tip
73 parent: 0:1f0dee641bb7
73 parent: 0:1f0dee641bb7
74 user: test
74 user: test
75 date: Thu Jan 01 00:00:00 1970 +0000
75 date: Thu Jan 01 00:00:00 1970 +0000
76 summary: add bar
76 summary: add bar
77
77
78 changeset: 2:faba9097cad4
78 changeset: 2:faba9097cad4
79 branch: foo
79 branch: foo
80 user: test
80 user: test
81 date: Thu Jan 01 00:00:00 1970 +0000
81 date: Thu Jan 01 00:00:00 1970 +0000
82 summary: new head of branch foo
82 summary: new head of branch foo
83
83
84 changeset: 1:cd2a86ecc814
84 changeset: 1:cd2a86ecc814
85 branch: foo
85 branch: foo
86 user: test
86 user: test
87 date: Thu Jan 01 00:00:00 1970 +0000
87 date: Thu Jan 01 00:00:00 1970 +0000
88 summary: change a
88 summary: change a
89
89
90 changeset: 0:1f0dee641bb7
90 changeset: 0:1f0dee641bb7
91 user: test
91 user: test
92 date: Thu Jan 01 00:00:00 1970 +0000
92 date: Thu Jan 01 00:00:00 1970 +0000
93 summary: add a
93 summary: add a
94
94
95 $ hg -q outgoing '../clone'
95 $ hg -q outgoing '../clone'
96 2:faba9097cad4
96 2:faba9097cad4
97 3:4cd725637392
97 3:4cd725637392
98 $ hg summary --remote --config paths.default='../clone'
98 $ hg summary --remote --config paths.default='../clone'
99 parent: 3:4cd725637392 tip
99 parent: 3:4cd725637392 tip
100 add bar
100 add bar
101 branch: default
101 branch: default
102 commit: (clean)
102 commit: (clean)
103 update: (current)
103 update: (current)
104 phases: 4 draft
104 phases: 4 draft
105 remote: 2 outgoing
105 remote: 2 outgoing
106 $ hg -q outgoing '../clone#foo'
106 $ hg -q outgoing '../clone#foo'
107 2:faba9097cad4
107 2:faba9097cad4
108 $ hg summary --remote --config paths.default='../clone#foo'
108 $ hg summary --remote --config paths.default='../clone#foo'
109 parent: 3:4cd725637392 tip
109 parent: 3:4cd725637392 tip
110 add bar
110 add bar
111 branch: default
111 branch: default
112 commit: (clean)
112 commit: (clean)
113 update: (current)
113 update: (current)
114 phases: 4 draft
114 phases: 4 draft
115 remote: 1 outgoing
115 remote: 1 outgoing
116
116
117 $ hg -q --cwd ../clone incoming '../repo#foo'
117 $ hg -q --cwd ../clone incoming '../repo#foo'
118 2:faba9097cad4
118 2:faba9097cad4
119 $ hg --cwd ../clone summary --remote --config paths.default='../repo#foo'
119 $ hg --cwd ../clone summary --remote --config paths.default='../repo#foo'
120 parent: 1:cd2a86ecc814 tip
120 parent: 1:cd2a86ecc814 tip
121 change a
121 change a
122 branch: foo
122 branch: foo
123 commit: (clean)
123 commit: (clean)
124 update: (current)
124 update: (current)
125 remote: 1 or more incoming
125 remote: 1 or more incoming
126
126
127 $ hg -q push '../clone#foo'
127 $ hg -q push '../clone#foo'
128
128
129 $ hg --cwd ../clone heads
129 $ hg --cwd ../clone heads
130 changeset: 2:faba9097cad4
130 changeset: 2:faba9097cad4
131 branch: foo
131 branch: foo
132 tag: tip
132 tag: tip
133 user: test
133 user: test
134 date: Thu Jan 01 00:00:00 1970 +0000
134 date: Thu Jan 01 00:00:00 1970 +0000
135 summary: new head of branch foo
135 summary: new head of branch foo
136
136
137 changeset: 0:1f0dee641bb7
137 changeset: 0:1f0dee641bb7
138 user: test
138 user: test
139 date: Thu Jan 01 00:00:00 1970 +0000
139 date: Thu Jan 01 00:00:00 1970 +0000
140 summary: add a
140 summary: add a
141
141
142 $ hg -q --cwd ../clone incoming '../repo#foo'
142 $ hg -q --cwd ../clone incoming '../repo#foo'
143 [1]
143 [1]
144 $ hg --cwd ../clone summary --remote --config paths.default='../repo#foo'
144 $ hg --cwd ../clone summary --remote --config paths.default='../repo#foo'
145 parent: 1:cd2a86ecc814
145 parent: 1:cd2a86ecc814
146 change a
146 change a
147 branch: foo
147 branch: foo
148 commit: (clean)
148 commit: (clean)
149 update: 1 new changesets (update)
149 update: 1 new changesets (update)
150 remote: (synced)
150 remote: (synced)
151
151
152 $ cd ..
152 $ cd ..
153
153
154 $ cd clone
154 $ cd clone
155 $ hg rollback
155 $ hg rollback
156 repository tip rolled back to revision 1 (undo push)
156 repository tip rolled back to revision 1 (undo push)
157
157
158 $ hg -q incoming
158 $ hg -q incoming
159 2:faba9097cad4
159 2:faba9097cad4
160
160
161 $ hg -q pull
161 $ hg -q pull
162
162
163 $ hg heads
163 $ hg heads
164 changeset: 2:faba9097cad4
164 changeset: 2:faba9097cad4
165 branch: foo
165 branch: foo
166 tag: tip
166 tag: tip
167 user: test
167 user: test
168 date: Thu Jan 01 00:00:00 1970 +0000
168 date: Thu Jan 01 00:00:00 1970 +0000
169 summary: new head of branch foo
169 summary: new head of branch foo
170
170
171 changeset: 0:1f0dee641bb7
171 changeset: 0:1f0dee641bb7
172 user: test
172 user: test
173 date: Thu Jan 01 00:00:00 1970 +0000
173 date: Thu Jan 01 00:00:00 1970 +0000
174 summary: add a
174 summary: add a
175
175
176 Pull should not have updated:
176 Pull should not have updated:
177
177
178 $ hg parents -q
178 $ hg parents -q
179 1:cd2a86ecc814
179 1:cd2a86ecc814
180
180
181 Going back to the default branch:
181 Going back to the default branch:
182
182
183 $ hg up -C 0
183 $ hg up -C 0
184 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
184 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
185
185
186 $ hg parents
186 $ hg parents
187 changeset: 0:1f0dee641bb7
187 changeset: 0:1f0dee641bb7
188 user: test
188 user: test
189 date: Thu Jan 01 00:00:00 1970 +0000
189 date: Thu Jan 01 00:00:00 1970 +0000
190 summary: add a
190 summary: add a
191
191
192 No new revs, no update:
192 No new revs, no update:
193
193
194 $ hg pull -qu
194 $ hg pull -qu
195
195
196 $ hg parents -q
196 $ hg parents -q
197 0:1f0dee641bb7
197 0:1f0dee641bb7
198
198
199 $ hg rollback
199 $ hg rollback
200 repository tip rolled back to revision 1 (undo pull)
200 repository tip rolled back to revision 1 (undo pull)
201
201
202 $ hg parents -q
202 $ hg parents -q
203 0:1f0dee641bb7
203 0:1f0dee641bb7
204
204
205 Pull -u takes us back to branch foo:
205 Pull -u takes us back to branch foo:
206
206
207 $ hg pull -qu
207 $ hg pull -qu
208
208
209 $ hg parents
209 $ hg parents
210 changeset: 2:faba9097cad4
210 changeset: 2:faba9097cad4
211 branch: foo
211 branch: foo
212 tag: tip
212 tag: tip
213 user: test
213 user: test
214 date: Thu Jan 01 00:00:00 1970 +0000
214 date: Thu Jan 01 00:00:00 1970 +0000
215 summary: new head of branch foo
215 summary: new head of branch foo
216
216
217 $ hg rollback
217 $ hg rollback
218 repository tip rolled back to revision 1 (undo pull)
218 repository tip rolled back to revision 1 (undo pull)
219 working directory now based on revision 0
219 working directory now based on revision 0
220
220
221 $ hg up -C 0
221 $ hg up -C 0
222 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
222 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
223
223
224 $ hg parents -q
224 $ hg parents -q
225 0:1f0dee641bb7
225 0:1f0dee641bb7
226
226
227 $ hg heads -q
227 $ hg heads -q
228 1:cd2a86ecc814
228 1:cd2a86ecc814
229 0:1f0dee641bb7
229 0:1f0dee641bb7
230
230
231 $ hg pull -qur default default
231 $ hg pull -qur default default
232
232
233 $ hg parents
233 $ hg parents
234 changeset: 3:4cd725637392
234 changeset: 3:4cd725637392
235 tag: tip
235 tag: tip
236 parent: 0:1f0dee641bb7
236 parent: 0:1f0dee641bb7
237 user: test
237 user: test
238 date: Thu Jan 01 00:00:00 1970 +0000
238 date: Thu Jan 01 00:00:00 1970 +0000
239 summary: add bar
239 summary: add bar
240
240
241 $ hg heads
241 $ hg heads
242 changeset: 3:4cd725637392
242 changeset: 3:4cd725637392
243 tag: tip
243 tag: tip
244 parent: 0:1f0dee641bb7
244 parent: 0:1f0dee641bb7
245 user: test
245 user: test
246 date: Thu Jan 01 00:00:00 1970 +0000
246 date: Thu Jan 01 00:00:00 1970 +0000
247 summary: add bar
247 summary: add bar
248
248
249 changeset: 2:faba9097cad4
249 changeset: 2:faba9097cad4
250 branch: foo
250 branch: foo
251 user: test
251 user: test
252 date: Thu Jan 01 00:00:00 1970 +0000
252 date: Thu Jan 01 00:00:00 1970 +0000
253 summary: new head of branch foo
253 summary: new head of branch foo
254
254
255 Test handling of invalid urls
255 Test handling of invalid urls
256
256
257 $ hg id http://foo/?bar
257 $ hg id http://foo/?bar
258 abort: unsupported URL component: "bar"
258 abort: unsupported URL component: "bar"
259 [255]
259 [255]
260
260
261 $ cd ..
261 $ cd ..
262
262
263 Test handling common incoming revisions between "default" and
263 Test handling common incoming revisions between "default" and
264 "default-push"
264 "default-push"
265
265
266 $ hg -R clone rollback
266 $ hg -R clone rollback
267 repository tip rolled back to revision 1 (undo pull)
267 repository tip rolled back to revision 1 (undo pull)
268 working directory now based on revision 0
268 working directory now based on revision 0
269
269
270 $ cd repo
270 $ cd repo
271
271
272 $ hg update -q -C default
272 $ hg update -q -C default
273 $ echo modified >> bar
273 $ echo modified >> bar
274 $ hg commit -m "new head to push current default head"
274 $ hg commit -m "new head to push current default head"
275 $ hg -q push -r ".^1" '../clone'
275 $ hg -q push -r ".^1" '../clone'
276
276
277 $ hg -q outgoing '../clone'
277 $ hg -q outgoing '../clone'
278 2:faba9097cad4
278 2:faba9097cad4
279 4:d515801a8f3d
279 4:d515801a8f3d
280
280
281 $ hg summary --remote --config paths.default='../clone#default' --config paths.default-push='../clone#foo'
281 $ hg summary --remote --config paths.default='../clone#default' --config paths.default-push='../clone#foo'
282 parent: 4:d515801a8f3d tip
282 parent: 4:d515801a8f3d tip
283 new head to push current default head
283 new head to push current default head
284 branch: default
284 branch: default
285 commit: (clean)
285 commit: (clean)
286 update: (current)
286 update: (current)
287 phases: 1 draft
287 phases: 1 draft
288 remote: 1 outgoing
288 remote: 1 outgoing
289
289
290 $ hg summary --remote --config paths.default='../clone#foo' --config paths.default-push='../clone'
290 $ hg summary --remote --config paths.default='../clone#foo' --config paths.default-push='../clone'
291 parent: 4:d515801a8f3d tip
291 parent: 4:d515801a8f3d tip
292 new head to push current default head
292 new head to push current default head
293 branch: default
293 branch: default
294 commit: (clean)
294 commit: (clean)
295 update: (current)
295 update: (current)
296 phases: 1 draft
296 phases: 1 draft
297 remote: 2 outgoing
297 remote: 2 outgoing
298
298
299 $ hg summary --remote --config paths.default='../clone' --config paths.default-push='../clone#foo'
299 $ hg summary --remote --config paths.default='../clone' --config paths.default-push='../clone#foo'
300 parent: 4:d515801a8f3d tip
300 parent: 4:d515801a8f3d tip
301 new head to push current default head
301 new head to push current default head
302 branch: default
302 branch: default
303 commit: (clean)
303 commit: (clean)
304 update: (current)
304 update: (current)
305 phases: 1 draft
305 phases: 1 draft
306 remote: 1 outgoing
306 remote: 1 outgoing
307
307
308 $ hg clone -q -r 0 . ../another
308 $ hg clone -q -r 0 . ../another
309 $ hg -q outgoing '../another#default'
309 $ hg -q outgoing '../another#default'
310 3:4cd725637392
310 3:4cd725637392
311 4:d515801a8f3d
311 4:d515801a8f3d
312
312
313 $ hg summary --remote --config paths.default='../another#default' --config paths.default-push='../clone#default'
313 $ hg summary --remote --config paths.default='../another#default' --config paths.default-push='../clone#default'
314 parent: 4:d515801a8f3d tip
314 parent: 4:d515801a8f3d tip
315 new head to push current default head
315 new head to push current default head
316 branch: default
316 branch: default
317 commit: (clean)
317 commit: (clean)
318 update: (current)
318 update: (current)
319 phases: 1 draft
319 phases: 1 draft
320 remote: 1 outgoing
320 remote: 1 outgoing
321
321
322 $ cd ..
322 $ cd ..
323
323
324 Test url#rev syntax of local destination path, which should be taken as
324 Test url#rev syntax of local destination path, which should be taken as
325 a 'url#rev' path
325 a 'url#rev' path
326
326
327 $ hg clone repo '#foo'
327 $ hg clone repo '#foo'
328 updating to branch default
328 updating to branch default
329 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 $ hg root -R '#foo'
330 $ hg root -R '#foo'
331 $TESTTMP/#foo (glob)
331 $TESTTMP/#foo (glob)
General Comments 0
You need to be logged in to leave comments. Login now