##// END OF EJS Templates
eol: look up partial nodeid as partial nodeid...
Martin von Zweigbergk -
r37525:9b16a67c default
parent child Browse files
Show More
@@ -1,419 +1,421 b''
1 """automatically manage newlines in repository files
1 """automatically manage newlines in repository files
2
2
3 This extension allows you to manage the type of line endings (CRLF or
3 This extension allows you to manage the type of line endings (CRLF or
4 LF) that are used in the repository and in the local working
4 LF) that are used in the repository and in the local working
5 directory. That way you can get CRLF line endings on Windows and LF on
5 directory. That way you can get CRLF line endings on Windows and LF on
6 Unix/Mac, thereby letting everybody use their OS native line endings.
6 Unix/Mac, thereby letting everybody use their OS native line endings.
7
7
8 The extension reads its configuration from a versioned ``.hgeol``
8 The extension reads its configuration from a versioned ``.hgeol``
9 configuration file found in the root of the working directory. The
9 configuration file found in the root of the working directory. The
10 ``.hgeol`` file use the same syntax as all other Mercurial
10 ``.hgeol`` file use the same syntax as all other Mercurial
11 configuration files. It uses two sections, ``[patterns]`` and
11 configuration files. It uses two sections, ``[patterns]`` and
12 ``[repository]``.
12 ``[repository]``.
13
13
14 The ``[patterns]`` section specifies how line endings should be
14 The ``[patterns]`` section specifies how line endings should be
15 converted between the working directory and the repository. The format is
15 converted between the working directory and the repository. The format is
16 specified by a file pattern. The first match is used, so put more
16 specified by a file pattern. The first match is used, so put more
17 specific patterns first. The available line endings are ``LF``,
17 specific patterns first. The available line endings are ``LF``,
18 ``CRLF``, and ``BIN``.
18 ``CRLF``, and ``BIN``.
19
19
20 Files with the declared format of ``CRLF`` or ``LF`` are always
20 Files with the declared format of ``CRLF`` or ``LF`` are always
21 checked out and stored in the repository in that format and files
21 checked out and stored in the repository in that format and files
22 declared to be binary (``BIN``) are left unchanged. Additionally,
22 declared to be binary (``BIN``) are left unchanged. Additionally,
23 ``native`` is an alias for checking out in the platform's default line
23 ``native`` is an alias for checking out in the platform's default line
24 ending: ``LF`` on Unix (including Mac OS X) and ``CRLF`` on
24 ending: ``LF`` on Unix (including Mac OS X) and ``CRLF`` on
25 Windows. Note that ``BIN`` (do nothing to line endings) is Mercurial's
25 Windows. Note that ``BIN`` (do nothing to line endings) is Mercurial's
26 default behavior; it is only needed if you need to override a later,
26 default behavior; it is only needed if you need to override a later,
27 more general pattern.
27 more general pattern.
28
28
29 The optional ``[repository]`` section specifies the line endings to
29 The optional ``[repository]`` section specifies the line endings to
30 use for files stored in the repository. It has a single setting,
30 use for files stored in the repository. It has a single setting,
31 ``native``, which determines the storage line endings for files
31 ``native``, which determines the storage line endings for files
32 declared as ``native`` in the ``[patterns]`` section. It can be set to
32 declared as ``native`` in the ``[patterns]`` section. It can be set to
33 ``LF`` or ``CRLF``. The default is ``LF``. For example, this means
33 ``LF`` or ``CRLF``. The default is ``LF``. For example, this means
34 that on Windows, files configured as ``native`` (``CRLF`` by default)
34 that on Windows, files configured as ``native`` (``CRLF`` by default)
35 will be converted to ``LF`` when stored in the repository. Files
35 will be converted to ``LF`` when stored in the repository. Files
36 declared as ``LF``, ``CRLF``, or ``BIN`` in the ``[patterns]`` section
36 declared as ``LF``, ``CRLF``, or ``BIN`` in the ``[patterns]`` section
37 are always stored as-is in the repository.
37 are always stored as-is in the repository.
38
38
39 Example versioned ``.hgeol`` file::
39 Example versioned ``.hgeol`` file::
40
40
41 [patterns]
41 [patterns]
42 **.py = native
42 **.py = native
43 **.vcproj = CRLF
43 **.vcproj = CRLF
44 **.txt = native
44 **.txt = native
45 Makefile = LF
45 Makefile = LF
46 **.jpg = BIN
46 **.jpg = BIN
47
47
48 [repository]
48 [repository]
49 native = LF
49 native = LF
50
50
51 .. note::
51 .. note::
52
52
53 The rules will first apply when files are touched in the working
53 The rules will first apply when files are touched in the working
54 directory, e.g. by updating to null and back to tip to touch all files.
54 directory, e.g. by updating to null and back to tip to touch all files.
55
55
56 The extension uses an optional ``[eol]`` section read from both the
56 The extension uses an optional ``[eol]`` section read from both the
57 normal Mercurial configuration files and the ``.hgeol`` file, with the
57 normal Mercurial configuration files and the ``.hgeol`` file, with the
58 latter overriding the former. You can use that section to control the
58 latter overriding the former. You can use that section to control the
59 overall behavior. There are three settings:
59 overall behavior. There are three settings:
60
60
61 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
61 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
62 ``CRLF`` to override the default interpretation of ``native`` for
62 ``CRLF`` to override the default interpretation of ``native`` for
63 checkout. This can be used with :hg:`archive` on Unix, say, to
63 checkout. This can be used with :hg:`archive` on Unix, say, to
64 generate an archive where files have line endings for Windows.
64 generate an archive where files have line endings for Windows.
65
65
66 - ``eol.only-consistent`` (default True) can be set to False to make
66 - ``eol.only-consistent`` (default True) can be set to False to make
67 the extension convert files with inconsistent EOLs. Inconsistent
67 the extension convert files with inconsistent EOLs. Inconsistent
68 means that there is both ``CRLF`` and ``LF`` present in the file.
68 means that there is both ``CRLF`` and ``LF`` present in the file.
69 Such files are normally not touched under the assumption that they
69 Such files are normally not touched under the assumption that they
70 have mixed EOLs on purpose.
70 have mixed EOLs on purpose.
71
71
72 - ``eol.fix-trailing-newline`` (default False) can be set to True to
72 - ``eol.fix-trailing-newline`` (default False) can be set to True to
73 ensure that converted files end with a EOL character (either ``\\n``
73 ensure that converted files end with a EOL character (either ``\\n``
74 or ``\\r\\n`` as per the configured patterns).
74 or ``\\r\\n`` as per the configured patterns).
75
75
76 The extension provides ``cleverencode:`` and ``cleverdecode:`` filters
76 The extension provides ``cleverencode:`` and ``cleverdecode:`` filters
77 like the deprecated win32text extension does. This means that you can
77 like the deprecated win32text extension does. This means that you can
78 disable win32text and enable eol and your filters will still work. You
78 disable win32text and enable eol and your filters will still work. You
79 only need to these filters until you have prepared a ``.hgeol`` file.
79 only need to these filters until you have prepared a ``.hgeol`` file.
80
80
81 The ``win32text.forbid*`` hooks provided by the win32text extension
81 The ``win32text.forbid*`` hooks provided by the win32text extension
82 have been unified into a single hook named ``eol.checkheadshook``. The
82 have been unified into a single hook named ``eol.checkheadshook``. The
83 hook will lookup the expected line endings from the ``.hgeol`` file,
83 hook will lookup the expected line endings from the ``.hgeol`` file,
84 which means you must migrate to a ``.hgeol`` file first before using
84 which means you must migrate to a ``.hgeol`` file first before using
85 the hook. ``eol.checkheadshook`` only checks heads, intermediate
85 the hook. ``eol.checkheadshook`` only checks heads, intermediate
86 invalid revisions will be pushed. To forbid them completely, use the
86 invalid revisions will be pushed. To forbid them completely, use the
87 ``eol.checkallhook`` hook. These hooks are best used as
87 ``eol.checkallhook`` hook. These hooks are best used as
88 ``pretxnchangegroup`` hooks.
88 ``pretxnchangegroup`` hooks.
89
89
90 See :hg:`help patterns` for more information about the glob patterns
90 See :hg:`help patterns` for more information about the glob patterns
91 used.
91 used.
92 """
92 """
93
93
94 from __future__ import absolute_import
94 from __future__ import absolute_import
95
95
96 import os
96 import os
97 import re
97 import re
98 from mercurial.i18n import _
98 from mercurial.i18n import _
99 from mercurial import (
99 from mercurial import (
100 config,
100 config,
101 error as errormod,
101 error as errormod,
102 extensions,
102 extensions,
103 match,
103 match,
104 pycompat,
104 pycompat,
105 registrar,
105 registrar,
106 scmutil,
106 util,
107 util,
107 )
108 )
108 from mercurial.utils import (
109 from mercurial.utils import (
109 stringutil,
110 stringutil,
110 )
111 )
111
112
112 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
113 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
113 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
114 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
114 # be specifying the version(s) of Mercurial they are tested with, or
115 # be specifying the version(s) of Mercurial they are tested with, or
115 # leave the attribute unspecified.
116 # leave the attribute unspecified.
116 testedwith = 'ships-with-hg-core'
117 testedwith = 'ships-with-hg-core'
117
118
118 configtable = {}
119 configtable = {}
119 configitem = registrar.configitem(configtable)
120 configitem = registrar.configitem(configtable)
120
121
121 configitem('eol', 'fix-trailing-newline',
122 configitem('eol', 'fix-trailing-newline',
122 default=False,
123 default=False,
123 )
124 )
124 configitem('eol', 'native',
125 configitem('eol', 'native',
125 default=pycompat.oslinesep,
126 default=pycompat.oslinesep,
126 )
127 )
127 configitem('eol', 'only-consistent',
128 configitem('eol', 'only-consistent',
128 default=True,
129 default=True,
129 )
130 )
130
131
131 # Matches a lone LF, i.e., one that is not part of CRLF.
132 # Matches a lone LF, i.e., one that is not part of CRLF.
132 singlelf = re.compile('(^|[^\r])\n')
133 singlelf = re.compile('(^|[^\r])\n')
133
134
134 def inconsistenteol(data):
135 def inconsistenteol(data):
135 return '\r\n' in data and singlelf.search(data)
136 return '\r\n' in data and singlelf.search(data)
136
137
137 def tolf(s, params, ui, **kwargs):
138 def tolf(s, params, ui, **kwargs):
138 """Filter to convert to LF EOLs."""
139 """Filter to convert to LF EOLs."""
139 if stringutil.binary(s):
140 if stringutil.binary(s):
140 return s
141 return s
141 if ui.configbool('eol', 'only-consistent') and inconsistenteol(s):
142 if ui.configbool('eol', 'only-consistent') and inconsistenteol(s):
142 return s
143 return s
143 if (ui.configbool('eol', 'fix-trailing-newline')
144 if (ui.configbool('eol', 'fix-trailing-newline')
144 and s and s[-1] != '\n'):
145 and s and s[-1] != '\n'):
145 s = s + '\n'
146 s = s + '\n'
146 return util.tolf(s)
147 return util.tolf(s)
147
148
148 def tocrlf(s, params, ui, **kwargs):
149 def tocrlf(s, params, ui, **kwargs):
149 """Filter to convert to CRLF EOLs."""
150 """Filter to convert to CRLF EOLs."""
150 if stringutil.binary(s):
151 if stringutil.binary(s):
151 return s
152 return s
152 if ui.configbool('eol', 'only-consistent') and inconsistenteol(s):
153 if ui.configbool('eol', 'only-consistent') and inconsistenteol(s):
153 return s
154 return s
154 if (ui.configbool('eol', 'fix-trailing-newline')
155 if (ui.configbool('eol', 'fix-trailing-newline')
155 and s and s[-1] != '\n'):
156 and s and s[-1] != '\n'):
156 s = s + '\n'
157 s = s + '\n'
157 return util.tocrlf(s)
158 return util.tocrlf(s)
158
159
159 def isbinary(s, params):
160 def isbinary(s, params):
160 """Filter to do nothing with the file."""
161 """Filter to do nothing with the file."""
161 return s
162 return s
162
163
163 filters = {
164 filters = {
164 'to-lf': tolf,
165 'to-lf': tolf,
165 'to-crlf': tocrlf,
166 'to-crlf': tocrlf,
166 'is-binary': isbinary,
167 'is-binary': isbinary,
167 # The following provide backwards compatibility with win32text
168 # The following provide backwards compatibility with win32text
168 'cleverencode:': tolf,
169 'cleverencode:': tolf,
169 'cleverdecode:': tocrlf
170 'cleverdecode:': tocrlf
170 }
171 }
171
172
172 class eolfile(object):
173 class eolfile(object):
173 def __init__(self, ui, root, data):
174 def __init__(self, ui, root, data):
174 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
175 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
175 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
176 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
176
177
177 self.cfg = config.config()
178 self.cfg = config.config()
178 # Our files should not be touched. The pattern must be
179 # Our files should not be touched. The pattern must be
179 # inserted first override a '** = native' pattern.
180 # inserted first override a '** = native' pattern.
180 self.cfg.set('patterns', '.hg*', 'BIN', 'eol')
181 self.cfg.set('patterns', '.hg*', 'BIN', 'eol')
181 # We can then parse the user's patterns.
182 # We can then parse the user's patterns.
182 self.cfg.parse('.hgeol', data)
183 self.cfg.parse('.hgeol', data)
183
184
184 isrepolf = self.cfg.get('repository', 'native') != 'CRLF'
185 isrepolf = self.cfg.get('repository', 'native') != 'CRLF'
185 self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf'
186 self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf'
186 iswdlf = ui.config('eol', 'native') in ('LF', '\n')
187 iswdlf = ui.config('eol', 'native') in ('LF', '\n')
187 self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf'
188 self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf'
188
189
189 include = []
190 include = []
190 exclude = []
191 exclude = []
191 self.patterns = []
192 self.patterns = []
192 for pattern, style in self.cfg.items('patterns'):
193 for pattern, style in self.cfg.items('patterns'):
193 key = style.upper()
194 key = style.upper()
194 if key == 'BIN':
195 if key == 'BIN':
195 exclude.append(pattern)
196 exclude.append(pattern)
196 else:
197 else:
197 include.append(pattern)
198 include.append(pattern)
198 m = match.match(root, '', [pattern])
199 m = match.match(root, '', [pattern])
199 self.patterns.append((pattern, key, m))
200 self.patterns.append((pattern, key, m))
200 # This will match the files for which we need to care
201 # This will match the files for which we need to care
201 # about inconsistent newlines.
202 # about inconsistent newlines.
202 self.match = match.match(root, '', [], include, exclude)
203 self.match = match.match(root, '', [], include, exclude)
203
204
204 def copytoui(self, ui):
205 def copytoui(self, ui):
205 for pattern, key, m in self.patterns:
206 for pattern, key, m in self.patterns:
206 try:
207 try:
207 ui.setconfig('decode', pattern, self._decode[key], 'eol')
208 ui.setconfig('decode', pattern, self._decode[key], 'eol')
208 ui.setconfig('encode', pattern, self._encode[key], 'eol')
209 ui.setconfig('encode', pattern, self._encode[key], 'eol')
209 except KeyError:
210 except KeyError:
210 ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
211 ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
211 % (key, self.cfg.source('patterns', pattern)))
212 % (key, self.cfg.source('patterns', pattern)))
212 # eol.only-consistent can be specified in ~/.hgrc or .hgeol
213 # eol.only-consistent can be specified in ~/.hgrc or .hgeol
213 for k, v in self.cfg.items('eol'):
214 for k, v in self.cfg.items('eol'):
214 ui.setconfig('eol', k, v, 'eol')
215 ui.setconfig('eol', k, v, 'eol')
215
216
216 def checkrev(self, repo, ctx, files):
217 def checkrev(self, repo, ctx, files):
217 failed = []
218 failed = []
218 for f in (files or ctx.files()):
219 for f in (files or ctx.files()):
219 if f not in ctx:
220 if f not in ctx:
220 continue
221 continue
221 for pattern, key, m in self.patterns:
222 for pattern, key, m in self.patterns:
222 if not m(f):
223 if not m(f):
223 continue
224 continue
224 target = self._encode[key]
225 target = self._encode[key]
225 data = ctx[f].data()
226 data = ctx[f].data()
226 if (target == "to-lf" and "\r\n" in data
227 if (target == "to-lf" and "\r\n" in data
227 or target == "to-crlf" and singlelf.search(data)):
228 or target == "to-crlf" and singlelf.search(data)):
228 failed.append((f, target, bytes(ctx)))
229 failed.append((f, target, bytes(ctx)))
229 break
230 break
230 return failed
231 return failed
231
232
232 def parseeol(ui, repo, nodes):
233 def parseeol(ui, repo, nodes):
233 try:
234 try:
234 for node in nodes:
235 for node in nodes:
235 try:
236 try:
236 if node is None:
237 if node is None:
237 # Cannot use workingctx.data() since it would load
238 # Cannot use workingctx.data() since it would load
238 # and cache the filters before we configure them.
239 # and cache the filters before we configure them.
239 data = repo.wvfs('.hgeol').read()
240 data = repo.wvfs('.hgeol').read()
240 else:
241 else:
241 data = repo[node]['.hgeol'].data()
242 data = repo[node]['.hgeol'].data()
242 return eolfile(ui, repo.root, data)
243 return eolfile(ui, repo.root, data)
243 except (IOError, LookupError):
244 except (IOError, LookupError):
244 pass
245 pass
245 except errormod.ParseError as inst:
246 except errormod.ParseError as inst:
246 ui.warn(_("warning: ignoring .hgeol file due to parse error "
247 ui.warn(_("warning: ignoring .hgeol file due to parse error "
247 "at %s: %s\n") % (inst.args[1], inst.args[0]))
248 "at %s: %s\n") % (inst.args[1], inst.args[0]))
248 return None
249 return None
249
250
250 def ensureenabled(ui):
251 def ensureenabled(ui):
251 """make sure the extension is enabled when used as hook
252 """make sure the extension is enabled when used as hook
252
253
253 When eol is used through hooks, the extension is never formally loaded and
254 When eol is used through hooks, the extension is never formally loaded and
254 enabled. This has some side effect, for example the config declaration is
255 enabled. This has some side effect, for example the config declaration is
255 never loaded. This function ensure the extension is enabled when running
256 never loaded. This function ensure the extension is enabled when running
256 hooks.
257 hooks.
257 """
258 """
258 if 'eol' in ui._knownconfig:
259 if 'eol' in ui._knownconfig:
259 return
260 return
260 ui.setconfig('extensions', 'eol', '', source='internal')
261 ui.setconfig('extensions', 'eol', '', source='internal')
261 extensions.loadall(ui, ['eol'])
262 extensions.loadall(ui, ['eol'])
262
263
263 def _checkhook(ui, repo, node, headsonly):
264 def _checkhook(ui, repo, node, headsonly):
264 # Get revisions to check and touched files at the same time
265 # Get revisions to check and touched files at the same time
265 ensureenabled(ui)
266 ensureenabled(ui)
266 files = set()
267 files = set()
267 revs = set()
268 revs = set()
268 for rev in xrange(repo[node].rev(), len(repo)):
269 for rev in xrange(repo[node].rev(), len(repo)):
269 revs.add(rev)
270 revs.add(rev)
270 if headsonly:
271 if headsonly:
271 ctx = repo[rev]
272 ctx = repo[rev]
272 files.update(ctx.files())
273 files.update(ctx.files())
273 for pctx in ctx.parents():
274 for pctx in ctx.parents():
274 revs.discard(pctx.rev())
275 revs.discard(pctx.rev())
275 failed = []
276 failed = []
276 for rev in revs:
277 for rev in revs:
277 ctx = repo[rev]
278 ctx = repo[rev]
278 eol = parseeol(ui, repo, [ctx.node()])
279 eol = parseeol(ui, repo, [ctx.node()])
279 if eol:
280 if eol:
280 failed.extend(eol.checkrev(repo, ctx, files))
281 failed.extend(eol.checkrev(repo, ctx, files))
281
282
282 if failed:
283 if failed:
283 eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'}
284 eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'}
284 msgs = []
285 msgs = []
285 for f, target, node in sorted(failed):
286 for f, target, node in sorted(failed):
286 msgs.append(_(" %s in %s should not have %s line endings") %
287 msgs.append(_(" %s in %s should not have %s line endings") %
287 (f, node, eols[target]))
288 (f, node, eols[target]))
288 raise errormod.Abort(_("end-of-line check failed:\n") + "\n".join(msgs))
289 raise errormod.Abort(_("end-of-line check failed:\n") + "\n".join(msgs))
289
290
290 def checkallhook(ui, repo, node, hooktype, **kwargs):
291 def checkallhook(ui, repo, node, hooktype, **kwargs):
291 """verify that files have expected EOLs"""
292 """verify that files have expected EOLs"""
292 _checkhook(ui, repo, node, False)
293 _checkhook(ui, repo, node, False)
293
294
294 def checkheadshook(ui, repo, node, hooktype, **kwargs):
295 def checkheadshook(ui, repo, node, hooktype, **kwargs):
295 """verify that files have expected EOLs"""
296 """verify that files have expected EOLs"""
296 _checkhook(ui, repo, node, True)
297 _checkhook(ui, repo, node, True)
297
298
298 # "checkheadshook" used to be called "hook"
299 # "checkheadshook" used to be called "hook"
299 hook = checkheadshook
300 hook = checkheadshook
300
301
301 def preupdate(ui, repo, hooktype, parent1, parent2):
302 def preupdate(ui, repo, hooktype, parent1, parent2):
302 repo.loadeol([parent1])
303 p1node = scmutil.resolvepartialhexnodeid(repo, parent1)
304 repo.loadeol([p1node])
303 return False
305 return False
304
306
305 def uisetup(ui):
307 def uisetup(ui):
306 ui.setconfig('hooks', 'preupdate.eol', preupdate, 'eol')
308 ui.setconfig('hooks', 'preupdate.eol', preupdate, 'eol')
307
309
308 def extsetup(ui):
310 def extsetup(ui):
309 try:
311 try:
310 extensions.find('win32text')
312 extensions.find('win32text')
311 ui.warn(_("the eol extension is incompatible with the "
313 ui.warn(_("the eol extension is incompatible with the "
312 "win32text extension\n"))
314 "win32text extension\n"))
313 except KeyError:
315 except KeyError:
314 pass
316 pass
315
317
316
318
317 def reposetup(ui, repo):
319 def reposetup(ui, repo):
318 uisetup(repo.ui)
320 uisetup(repo.ui)
319
321
320 if not repo.local():
322 if not repo.local():
321 return
323 return
322 for name, fn in filters.iteritems():
324 for name, fn in filters.iteritems():
323 repo.adddatafilter(name, fn)
325 repo.adddatafilter(name, fn)
324
326
325 ui.setconfig('patch', 'eol', 'auto', 'eol')
327 ui.setconfig('patch', 'eol', 'auto', 'eol')
326
328
327 class eolrepo(repo.__class__):
329 class eolrepo(repo.__class__):
328
330
329 def loadeol(self, nodes):
331 def loadeol(self, nodes):
330 eol = parseeol(self.ui, self, nodes)
332 eol = parseeol(self.ui, self, nodes)
331 if eol is None:
333 if eol is None:
332 return None
334 return None
333 eol.copytoui(self.ui)
335 eol.copytoui(self.ui)
334 return eol.match
336 return eol.match
335
337
336 def _hgcleardirstate(self):
338 def _hgcleardirstate(self):
337 self._eolmatch = self.loadeol([None, 'tip'])
339 self._eolmatch = self.loadeol([None, 'tip'])
338 if not self._eolmatch:
340 if not self._eolmatch:
339 self._eolmatch = util.never
341 self._eolmatch = util.never
340 return
342 return
341
343
342 oldeol = None
344 oldeol = None
343 try:
345 try:
344 cachemtime = os.path.getmtime(self.vfs.join("eol.cache"))
346 cachemtime = os.path.getmtime(self.vfs.join("eol.cache"))
345 except OSError:
347 except OSError:
346 cachemtime = 0
348 cachemtime = 0
347 else:
349 else:
348 olddata = self.vfs.read("eol.cache")
350 olddata = self.vfs.read("eol.cache")
349 if olddata:
351 if olddata:
350 oldeol = eolfile(self.ui, self.root, olddata)
352 oldeol = eolfile(self.ui, self.root, olddata)
351
353
352 try:
354 try:
353 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
355 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
354 except OSError:
356 except OSError:
355 eolmtime = 0
357 eolmtime = 0
356
358
357 if eolmtime > cachemtime:
359 if eolmtime > cachemtime:
358 self.ui.debug("eol: detected change in .hgeol\n")
360 self.ui.debug("eol: detected change in .hgeol\n")
359
361
360 hgeoldata = self.wvfs.read('.hgeol')
362 hgeoldata = self.wvfs.read('.hgeol')
361 neweol = eolfile(self.ui, self.root, hgeoldata)
363 neweol = eolfile(self.ui, self.root, hgeoldata)
362
364
363 wlock = None
365 wlock = None
364 try:
366 try:
365 wlock = self.wlock()
367 wlock = self.wlock()
366 for f in self.dirstate:
368 for f in self.dirstate:
367 if self.dirstate[f] != 'n':
369 if self.dirstate[f] != 'n':
368 continue
370 continue
369 if oldeol is not None:
371 if oldeol is not None:
370 if not oldeol.match(f) and not neweol.match(f):
372 if not oldeol.match(f) and not neweol.match(f):
371 continue
373 continue
372 oldkey = None
374 oldkey = None
373 for pattern, key, m in oldeol.patterns:
375 for pattern, key, m in oldeol.patterns:
374 if m(f):
376 if m(f):
375 oldkey = key
377 oldkey = key
376 break
378 break
377 newkey = None
379 newkey = None
378 for pattern, key, m in neweol.patterns:
380 for pattern, key, m in neweol.patterns:
379 if m(f):
381 if m(f):
380 newkey = key
382 newkey = key
381 break
383 break
382 if oldkey == newkey:
384 if oldkey == newkey:
383 continue
385 continue
384 # all normal files need to be looked at again since
386 # all normal files need to be looked at again since
385 # the new .hgeol file specify a different filter
387 # the new .hgeol file specify a different filter
386 self.dirstate.normallookup(f)
388 self.dirstate.normallookup(f)
387 # Write the cache to update mtime and cache .hgeol
389 # Write the cache to update mtime and cache .hgeol
388 with self.vfs("eol.cache", "w") as f:
390 with self.vfs("eol.cache", "w") as f:
389 f.write(hgeoldata)
391 f.write(hgeoldata)
390 except errormod.LockUnavailable:
392 except errormod.LockUnavailable:
391 # If we cannot lock the repository and clear the
393 # If we cannot lock the repository and clear the
392 # dirstate, then a commit might not see all files
394 # dirstate, then a commit might not see all files
393 # as modified. But if we cannot lock the
395 # as modified. But if we cannot lock the
394 # repository, then we can also not make a commit,
396 # repository, then we can also not make a commit,
395 # so ignore the error.
397 # so ignore the error.
396 pass
398 pass
397 finally:
399 finally:
398 if wlock is not None:
400 if wlock is not None:
399 wlock.release()
401 wlock.release()
400
402
401 def commitctx(self, ctx, error=False):
403 def commitctx(self, ctx, error=False):
402 for f in sorted(ctx.added() + ctx.modified()):
404 for f in sorted(ctx.added() + ctx.modified()):
403 if not self._eolmatch(f):
405 if not self._eolmatch(f):
404 continue
406 continue
405 fctx = ctx[f]
407 fctx = ctx[f]
406 if fctx is None:
408 if fctx is None:
407 continue
409 continue
408 data = fctx.data()
410 data = fctx.data()
409 if stringutil.binary(data):
411 if stringutil.binary(data):
410 # We should not abort here, since the user should
412 # We should not abort here, since the user should
411 # be able to say "** = native" to automatically
413 # be able to say "** = native" to automatically
412 # have all non-binary files taken care of.
414 # have all non-binary files taken care of.
413 continue
415 continue
414 if inconsistenteol(data):
416 if inconsistenteol(data):
415 raise errormod.Abort(_("inconsistent newline style "
417 raise errormod.Abort(_("inconsistent newline style "
416 "in %s\n") % f)
418 "in %s\n") % f)
417 return super(eolrepo, self).commitctx(ctx, error)
419 return super(eolrepo, self).commitctx(ctx, error)
418 repo.__class__ = eolrepo
420 repo.__class__ = eolrepo
419 repo._hgcleardirstate()
421 repo._hgcleardirstate()
@@ -1,376 +1,375 b''
1 setup
1 setup
2 $ cat >> $HGRCPATH <<EOF
2 $ cat >> $HGRCPATH <<EOF
3 > [extensions]
3 > [extensions]
4 > blackbox=
4 > blackbox=
5 > mock=$TESTDIR/mockblackbox.py
5 > mock=$TESTDIR/mockblackbox.py
6 > mq=
6 > mq=
7 > [alias]
7 > [alias]
8 > confuse = log --limit 3
8 > confuse = log --limit 3
9 > so-confusing = confuse --style compact
9 > so-confusing = confuse --style compact
10 > EOF
10 > EOF
11 $ hg init blackboxtest
11 $ hg init blackboxtest
12 $ cd blackboxtest
12 $ cd blackboxtest
13
13
14 command, exit codes, and duration
14 command, exit codes, and duration
15
15
16 $ echo a > a
16 $ echo a > a
17 $ hg add a
17 $ hg add a
18 $ hg blackbox --config blackbox.dirty=True
18 $ hg blackbox --config blackbox.dirty=True
19 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest exited 0 after * seconds (glob)
19 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest exited 0 after * seconds (glob)
20 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a
20 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a
21 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a exited 0 after * seconds (glob)
21 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a exited 0 after * seconds (glob)
22 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox --config *blackbox.dirty=True* (glob)
22 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox --config *blackbox.dirty=True* (glob)
23
23
24 alias expansion is logged
24 alias expansion is logged
25 $ rm ./.hg/blackbox.log
25 $ rm ./.hg/blackbox.log
26 $ hg confuse
26 $ hg confuse
27 $ hg blackbox
27 $ hg blackbox
28 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse
28 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse
29 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
29 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
30 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse exited 0 after * seconds (glob)
30 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse exited 0 after * seconds (glob)
31 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
31 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
32
32
33 recursive aliases work correctly
33 recursive aliases work correctly
34 $ rm ./.hg/blackbox.log
34 $ rm ./.hg/blackbox.log
35 $ hg so-confusing
35 $ hg so-confusing
36 $ hg blackbox
36 $ hg blackbox
37 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing
37 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing
38 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'so-confusing' expands to 'confuse --style compact'
38 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'so-confusing' expands to 'confuse --style compact'
39 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
39 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
40 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing exited 0 after * seconds (glob)
40 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing exited 0 after * seconds (glob)
41 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
41 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
42
42
43 incoming change tracking
43 incoming change tracking
44
44
45 create two heads to verify that we only see one change in the log later
45 create two heads to verify that we only see one change in the log later
46 $ hg commit -ma
46 $ hg commit -ma
47 $ hg up null
47 $ hg up null
48 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
48 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
49 $ echo b > b
49 $ echo b > b
50 $ hg commit -Amb
50 $ hg commit -Amb
51 adding b
51 adding b
52 created new head
52 created new head
53
53
54 clone, commit, pull
54 clone, commit, pull
55 $ hg clone . ../blackboxtest2
55 $ hg clone . ../blackboxtest2
56 updating to branch default
56 updating to branch default
57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 $ echo c > c
58 $ echo c > c
59 $ hg commit -Amc
59 $ hg commit -Amc
60 adding c
60 adding c
61 $ cd ../blackboxtest2
61 $ cd ../blackboxtest2
62 $ hg pull
62 $ hg pull
63 pulling from $TESTTMP/blackboxtest
63 pulling from $TESTTMP/blackboxtest
64 searching for changes
64 searching for changes
65 adding changesets
65 adding changesets
66 adding manifests
66 adding manifests
67 adding file changes
67 adding file changes
68 added 1 changesets with 1 changes to 1 files
68 added 1 changesets with 1 changes to 1 files
69 new changesets d02f48003e62
69 new changesets d02f48003e62
70 (run 'hg update' to get a working copy)
70 (run 'hg update' to get a working copy)
71 $ hg blackbox -l 6
71 $ hg blackbox -l 6
72 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull
72 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull
73 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated served branch cache in * seconds (glob)
73 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated served branch cache in * seconds (glob)
74 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote served branch cache with 1 labels and 2 nodes
74 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote served branch cache with 1 labels and 2 nodes
75 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> 1 incoming changes - new heads: d02f48003e62
75 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> 1 incoming changes - new heads: d02f48003e62
76 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull exited 0 after * seconds (glob)
76 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull exited 0 after * seconds (glob)
77 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
77 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
78
78
79 we must not cause a failure if we cannot write to the log
79 we must not cause a failure if we cannot write to the log
80
80
81 $ hg rollback
81 $ hg rollback
82 repository tip rolled back to revision 1 (undo pull)
82 repository tip rolled back to revision 1 (undo pull)
83
83
84 $ mv .hg/blackbox.log .hg/blackbox.log-
84 $ mv .hg/blackbox.log .hg/blackbox.log-
85 $ mkdir .hg/blackbox.log
85 $ mkdir .hg/blackbox.log
86 $ hg --debug incoming
86 $ hg --debug incoming
87 warning: cannot write to blackbox.log: * (glob)
87 warning: cannot write to blackbox.log: * (glob)
88 comparing with $TESTTMP/blackboxtest
88 comparing with $TESTTMP/blackboxtest
89 query 1; heads
89 query 1; heads
90 searching for changes
90 searching for changes
91 all local heads known remotely
91 all local heads known remotely
92 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
92 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
93 tag: tip
93 tag: tip
94 phase: draft
94 phase: draft
95 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
95 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
96 parent: -1:0000000000000000000000000000000000000000
96 parent: -1:0000000000000000000000000000000000000000
97 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
97 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
98 user: test
98 user: test
99 date: Thu Jan 01 00:00:00 1970 +0000
99 date: Thu Jan 01 00:00:00 1970 +0000
100 files+: c
100 files+: c
101 extra: branch=default
101 extra: branch=default
102 description:
102 description:
103 c
103 c
104
104
105
105
106 $ hg pull
106 $ hg pull
107 pulling from $TESTTMP/blackboxtest
107 pulling from $TESTTMP/blackboxtest
108 searching for changes
108 searching for changes
109 adding changesets
109 adding changesets
110 adding manifests
110 adding manifests
111 adding file changes
111 adding file changes
112 added 1 changesets with 1 changes to 1 files
112 added 1 changesets with 1 changes to 1 files
113 new changesets d02f48003e62
113 new changesets d02f48003e62
114 (run 'hg update' to get a working copy)
114 (run 'hg update' to get a working copy)
115
115
116 a failure reading from the log is fatal
116 a failure reading from the log is fatal
117
117
118 $ hg blackbox -l 3
118 $ hg blackbox -l 3
119 abort: *$TESTTMP/blackboxtest2/.hg/blackbox.log* (glob)
119 abort: *$TESTTMP/blackboxtest2/.hg/blackbox.log* (glob)
120 [255]
120 [255]
121
121
122 $ rmdir .hg/blackbox.log
122 $ rmdir .hg/blackbox.log
123 $ mv .hg/blackbox.log- .hg/blackbox.log
123 $ mv .hg/blackbox.log- .hg/blackbox.log
124
124
125 backup bundles get logged
125 backup bundles get logged
126
126
127 $ touch d
127 $ touch d
128 $ hg commit -Amd
128 $ hg commit -Amd
129 adding d
129 adding d
130 created new head
130 created new head
131 $ hg strip tip
131 $ hg strip tip
132 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
132 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
133 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
133 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
134 $ hg blackbox -l 6
134 $ hg blackbox -l 6
135 1970/01/01 00:00:00 bob @73f6ee326b27d820b0472f1a825e3a50f3dc489b (5000)> strip tip
135 1970/01/01 00:00:00 bob @73f6ee326b27d820b0472f1a825e3a50f3dc489b (5000)> strip tip
136 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/73f6ee326b27-7612e004-backup.hg
136 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/73f6ee326b27-7612e004-backup.hg
137 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated base branch cache in * seconds (glob)
137 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated base branch cache in * seconds (glob)
138 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote base branch cache with 1 labels and 2 nodes
138 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote base branch cache with 1 labels and 2 nodes
139 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> strip tip exited 0 after * seconds (glob)
139 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> strip tip exited 0 after * seconds (glob)
140 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
140 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
141
141
142 extension and python hooks - use the eol extension for a pythonhook
142 extension and python hooks - use the eol extension for a pythonhook
143
143
144 $ echo '[extensions]' >> .hg/hgrc
144 $ echo '[extensions]' >> .hg/hgrc
145 $ echo 'eol=' >> .hg/hgrc
145 $ echo 'eol=' >> .hg/hgrc
146 $ echo '[hooks]' >> .hg/hgrc
146 $ echo '[hooks]' >> .hg/hgrc
147 $ echo 'update = echo hooked' >> .hg/hgrc
147 $ echo 'update = echo hooked' >> .hg/hgrc
148 $ hg update
148 $ hg update
149 The fsmonitor extension is incompatible with the eol extension and has been disabled. (fsmonitor !)
149 The fsmonitor extension is incompatible with the eol extension and has been disabled. (fsmonitor !)
150 hooked
150 hooked
151 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
151 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
152 updated to "d02f48003e62: c"
152 updated to "d02f48003e62: c"
153 1 other heads for branch "default"
153 1 other heads for branch "default"
154 $ cat >> .hg/hgrc <<EOF
154 $ cat >> .hg/hgrc <<EOF
155 > [extensions]
155 > [extensions]
156 > # disable eol, because it is not needed for subsequent tests
156 > # disable eol, because it is not needed for subsequent tests
157 > # (in addition, keeping it requires extra care for fsmonitor)
157 > # (in addition, keeping it requires extra care for fsmonitor)
158 > eol=!
158 > eol=!
159 > EOF
159 > EOF
160 $ hg blackbox -l 6
160 $ hg blackbox -l 5
161 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> update (no-chg !)
161 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> update (no-chg !)
162 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> writing .hg/cache/tags2-visible with 0 tags
163 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
162 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
164 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> exthook-update: echo hooked finished in * seconds (glob)
163 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> exthook-update: echo hooked finished in * seconds (glob)
165 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> update exited 0 after * seconds (glob)
164 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> update exited 0 after * seconds (glob)
166 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> serve --cmdserver chgunix --address $TESTTMP.chgsock/server.* --daemon-postexec 'chdir:/' (glob) (chg !)
165 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> serve --cmdserver chgunix --address $TESTTMP.chgsock/server.* --daemon-postexec 'chdir:/' (glob) (chg !)
167 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> blackbox -l 6
166 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> blackbox -l 5
168
167
169 log rotation
168 log rotation
170
169
171 $ echo '[blackbox]' >> .hg/hgrc
170 $ echo '[blackbox]' >> .hg/hgrc
172 $ echo 'maxsize = 20 b' >> .hg/hgrc
171 $ echo 'maxsize = 20 b' >> .hg/hgrc
173 $ echo 'maxfiles = 3' >> .hg/hgrc
172 $ echo 'maxfiles = 3' >> .hg/hgrc
174 $ hg status
173 $ hg status
175 $ hg status
174 $ hg status
176 $ hg status
175 $ hg status
177 $ hg tip -q
176 $ hg tip -q
178 2:d02f48003e62
177 2:d02f48003e62
179 $ ls .hg/blackbox.log*
178 $ ls .hg/blackbox.log*
180 .hg/blackbox.log
179 .hg/blackbox.log
181 .hg/blackbox.log.1
180 .hg/blackbox.log.1
182 .hg/blackbox.log.2
181 .hg/blackbox.log.2
183 $ cd ..
182 $ cd ..
184
183
185 $ hg init blackboxtest3
184 $ hg init blackboxtest3
186 $ cd blackboxtest3
185 $ cd blackboxtest3
187 $ hg blackbox
186 $ hg blackbox
188 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest3 exited 0 after * seconds (glob)
187 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest3 exited 0 after * seconds (glob)
189 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
188 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
190 $ mv .hg/blackbox.log .hg/blackbox.log-
189 $ mv .hg/blackbox.log .hg/blackbox.log-
191 $ mkdir .hg/blackbox.log
190 $ mkdir .hg/blackbox.log
192 $ sed -e 's/\(.*test1.*\)/#\1/; s#\(.*commit2.*\)#os.rmdir(".hg/blackbox.log")\
191 $ sed -e 's/\(.*test1.*\)/#\1/; s#\(.*commit2.*\)#os.rmdir(".hg/blackbox.log")\
193 > os.rename(".hg/blackbox.log-", ".hg/blackbox.log")\
192 > os.rename(".hg/blackbox.log-", ".hg/blackbox.log")\
194 > \1#' $TESTDIR/test-dispatch.py > ../test-dispatch.py
193 > \1#' $TESTDIR/test-dispatch.py > ../test-dispatch.py
195 $ $PYTHON $TESTDIR/blackbox-readonly-dispatch.py
194 $ $PYTHON $TESTDIR/blackbox-readonly-dispatch.py
196 running: --debug add foo
195 running: --debug add foo
197 warning: cannot write to blackbox.log: Is a directory (no-windows !)
196 warning: cannot write to blackbox.log: Is a directory (no-windows !)
198 warning: cannot write to blackbox.log: $TESTTMP/blackboxtest3/.hg/blackbox.log: Access is denied (windows !)
197 warning: cannot write to blackbox.log: $TESTTMP/blackboxtest3/.hg/blackbox.log: Access is denied (windows !)
199 adding foo
198 adding foo
200 result: 0
199 result: 0
201 running: --debug commit -m commit1 -d 2000-01-01 foo
200 running: --debug commit -m commit1 -d 2000-01-01 foo
202 warning: cannot write to blackbox.log: Is a directory (no-windows !)
201 warning: cannot write to blackbox.log: Is a directory (no-windows !)
203 warning: cannot write to blackbox.log: $TESTTMP/blackboxtest3/.hg/blackbox.log: Access is denied (windows !)
202 warning: cannot write to blackbox.log: $TESTTMP/blackboxtest3/.hg/blackbox.log: Access is denied (windows !)
204 committing files:
203 committing files:
205 foo
204 foo
206 committing manifest
205 committing manifest
207 committing changelog
206 committing changelog
208 updating the branch cache
207 updating the branch cache
209 committed changeset 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
208 committed changeset 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
210 result: None
209 result: None
211 running: --debug commit -m commit2 -d 2000-01-02 foo
210 running: --debug commit -m commit2 -d 2000-01-02 foo
212 committing files:
211 committing files:
213 foo
212 foo
214 committing manifest
213 committing manifest
215 committing changelog
214 committing changelog
216 updating the branch cache
215 updating the branch cache
217 committed changeset 1:45589e459b2edfbf3dbde7e01f611d2c1e7453d7
216 committed changeset 1:45589e459b2edfbf3dbde7e01f611d2c1e7453d7
218 result: None
217 result: None
219 running: --debug log -r 0
218 running: --debug log -r 0
220 changeset: 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
219 changeset: 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
221 phase: draft
220 phase: draft
222 parent: -1:0000000000000000000000000000000000000000
221 parent: -1:0000000000000000000000000000000000000000
223 parent: -1:0000000000000000000000000000000000000000
222 parent: -1:0000000000000000000000000000000000000000
224 manifest: 0:9091aa5df980aea60860a2e39c95182e68d1ddec
223 manifest: 0:9091aa5df980aea60860a2e39c95182e68d1ddec
225 user: test
224 user: test
226 date: Sat Jan 01 00:00:00 2000 +0000
225 date: Sat Jan 01 00:00:00 2000 +0000
227 files+: foo
226 files+: foo
228 extra: branch=default
227 extra: branch=default
229 description:
228 description:
230 commit1
229 commit1
231
230
232
231
233 result: None
232 result: None
234 running: --debug log -r tip
233 running: --debug log -r tip
235 changeset: 1:45589e459b2edfbf3dbde7e01f611d2c1e7453d7
234 changeset: 1:45589e459b2edfbf3dbde7e01f611d2c1e7453d7
236 tag: tip
235 tag: tip
237 phase: draft
236 phase: draft
238 parent: 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
237 parent: 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
239 parent: -1:0000000000000000000000000000000000000000
238 parent: -1:0000000000000000000000000000000000000000
240 manifest: 1:895aa9b7886f89dd017a6d62524e1f9180b04df9
239 manifest: 1:895aa9b7886f89dd017a6d62524e1f9180b04df9
241 user: test
240 user: test
242 date: Sun Jan 02 00:00:00 2000 +0000
241 date: Sun Jan 02 00:00:00 2000 +0000
243 files: foo
242 files: foo
244 extra: branch=default
243 extra: branch=default
245 description:
244 description:
246 commit2
245 commit2
247
246
248
247
249 result: None
248 result: None
250 $ hg blackbox
249 $ hg blackbox
251 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> updating the branch cache
250 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> updating the branch cache
252 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> updated served branch cache in * seconds (glob)
251 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> updated served branch cache in * seconds (glob)
253 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> wrote served branch cache with 1 labels and 1 nodes
252 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> wrote served branch cache with 1 labels and 1 nodes
254 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug commit -m commit2 -d 2000-01-02 foo exited 0 after *.?? seconds (glob)
253 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug commit -m commit2 -d 2000-01-02 foo exited 0 after *.?? seconds (glob)
255 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r 0
254 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r 0
256 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> writing .hg/cache/tags2-visible with 0 tags
255 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> writing .hg/cache/tags2-visible with 0 tags
257 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r 0 exited 0 after *.?? seconds (glob)
256 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r 0 exited 0 after *.?? seconds (glob)
258 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r tip
257 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r tip
259 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r tip exited 0 after *.?? seconds (glob)
258 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r tip exited 0 after *.?? seconds (glob)
260 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> blackbox
259 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> blackbox
261
260
262 Test log recursion from dirty status check
261 Test log recursion from dirty status check
263
262
264 $ cat > ../r.py <<EOF
263 $ cat > ../r.py <<EOF
265 > from mercurial import context, error, extensions
264 > from mercurial import context, error, extensions
266 > x=[False]
265 > x=[False]
267 > def status(orig, *args, **opts):
266 > def status(orig, *args, **opts):
268 > args[0].repo().ui.log(b"broken", b"recursion?")
267 > args[0].repo().ui.log(b"broken", b"recursion?")
269 > return orig(*args, **opts)
268 > return orig(*args, **opts)
270 > def reposetup(ui, repo):
269 > def reposetup(ui, repo):
271 > extensions.wrapfunction(context.basectx, 'status', status)
270 > extensions.wrapfunction(context.basectx, 'status', status)
272 > EOF
271 > EOF
273 $ hg id --config extensions.x=../r.py --config blackbox.dirty=True
272 $ hg id --config extensions.x=../r.py --config blackbox.dirty=True
274 45589e459b2e tip
273 45589e459b2e tip
275
274
276 cleanup
275 cleanup
277 $ cd ..
276 $ cd ..
278
277
279 #if chg
278 #if chg
280
279
281 when using chg, blackbox.log should get rotated correctly
280 when using chg, blackbox.log should get rotated correctly
282
281
283 $ cat > $TESTTMP/noop.py << EOF
282 $ cat > $TESTTMP/noop.py << EOF
284 > from __future__ import absolute_import
283 > from __future__ import absolute_import
285 > import time
284 > import time
286 > from mercurial import registrar, scmutil
285 > from mercurial import registrar, scmutil
287 > cmdtable = {}
286 > cmdtable = {}
288 > command = registrar.command(cmdtable)
287 > command = registrar.command(cmdtable)
289 > @command('noop')
288 > @command('noop')
290 > def noop(ui, repo):
289 > def noop(ui, repo):
291 > pass
290 > pass
292 > EOF
291 > EOF
293
292
294 $ hg init blackbox-chg
293 $ hg init blackbox-chg
295 $ cd blackbox-chg
294 $ cd blackbox-chg
296
295
297 $ cat > .hg/hgrc << EOF
296 $ cat > .hg/hgrc << EOF
298 > [blackbox]
297 > [blackbox]
299 > maxsize = 500B
298 > maxsize = 500B
300 > [extensions]
299 > [extensions]
301 > # extension change forces chg to restart
300 > # extension change forces chg to restart
302 > noop=$TESTTMP/noop.py
301 > noop=$TESTTMP/noop.py
303 > EOF
302 > EOF
304
303
305 $ $PYTHON -c 'print("a" * 400)' > .hg/blackbox.log
304 $ $PYTHON -c 'print("a" * 400)' > .hg/blackbox.log
306 $ chg noop
305 $ chg noop
307 $ chg noop
306 $ chg noop
308 $ chg noop
307 $ chg noop
309 $ chg noop
308 $ chg noop
310 $ chg noop
309 $ chg noop
311
310
312 $ cat > showsize.py << 'EOF'
311 $ cat > showsize.py << 'EOF'
313 > import os, sys
312 > import os, sys
314 > limit = 500
313 > limit = 500
315 > for p in sys.argv[1:]:
314 > for p in sys.argv[1:]:
316 > size = os.stat(p).st_size
315 > size = os.stat(p).st_size
317 > if size >= limit:
316 > if size >= limit:
318 > desc = '>='
317 > desc = '>='
319 > else:
318 > else:
320 > desc = '<'
319 > desc = '<'
321 > print('%s: %s %d' % (p, desc, limit))
320 > print('%s: %s %d' % (p, desc, limit))
322 > EOF
321 > EOF
323
322
324 $ $PYTHON showsize.py .hg/blackbox*
323 $ $PYTHON showsize.py .hg/blackbox*
325 .hg/blackbox.log: < 500
324 .hg/blackbox.log: < 500
326 .hg/blackbox.log.1: >= 500
325 .hg/blackbox.log.1: >= 500
327 .hg/blackbox.log.2: >= 500
326 .hg/blackbox.log.2: >= 500
328
327
329 $ cd ..
328 $ cd ..
330
329
331 With chg, blackbox should not create the log file if the repo is gone
330 With chg, blackbox should not create the log file if the repo is gone
332
331
333 $ hg init repo1
332 $ hg init repo1
334 $ hg --config extensions.a=! -R repo1 log
333 $ hg --config extensions.a=! -R repo1 log
335 $ rm -rf $TESTTMP/repo1
334 $ rm -rf $TESTTMP/repo1
336 $ hg --config extensions.a=! init repo1
335 $ hg --config extensions.a=! init repo1
337
336
338 #endif
337 #endif
339
338
340 blackbox should work if repo.ui.log is not called (issue5518)
339 blackbox should work if repo.ui.log is not called (issue5518)
341
340
342 $ cat > $TESTTMP/raise.py << EOF
341 $ cat > $TESTTMP/raise.py << EOF
343 > from __future__ import absolute_import
342 > from __future__ import absolute_import
344 > from mercurial import registrar, scmutil
343 > from mercurial import registrar, scmutil
345 > cmdtable = {}
344 > cmdtable = {}
346 > command = registrar.command(cmdtable)
345 > command = registrar.command(cmdtable)
347 > @command(b'raise')
346 > @command(b'raise')
348 > def raisecmd(*args):
347 > def raisecmd(*args):
349 > raise RuntimeError('raise')
348 > raise RuntimeError('raise')
350 > EOF
349 > EOF
351
350
352 $ cat >> $HGRCPATH << EOF
351 $ cat >> $HGRCPATH << EOF
353 > [blackbox]
352 > [blackbox]
354 > track = commandexception
353 > track = commandexception
355 > [extensions]
354 > [extensions]
356 > raise=$TESTTMP/raise.py
355 > raise=$TESTTMP/raise.py
357 > EOF
356 > EOF
358
357
359 $ hg init $TESTTMP/blackbox-exception-only
358 $ hg init $TESTTMP/blackbox-exception-only
360 $ cd $TESTTMP/blackbox-exception-only
359 $ cd $TESTTMP/blackbox-exception-only
361
360
362 #if chg
361 #if chg
363 (chg exits 255 because it fails to receive an exit code)
362 (chg exits 255 because it fails to receive an exit code)
364 $ hg raise 2>/dev/null
363 $ hg raise 2>/dev/null
365 [255]
364 [255]
366 #else
365 #else
367 (hg exits 1 because Python default exit code for uncaught exception is 1)
366 (hg exits 1 because Python default exit code for uncaught exception is 1)
368 $ hg raise 2>/dev/null
367 $ hg raise 2>/dev/null
369 [1]
368 [1]
370 #endif
369 #endif
371
370
372 $ head -1 .hg/blackbox.log
371 $ head -1 .hg/blackbox.log
373 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> ** Unknown exception encountered with possibly-broken third-party extension mock
372 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> ** Unknown exception encountered with possibly-broken third-party extension mock
374 $ tail -2 .hg/blackbox.log
373 $ tail -2 .hg/blackbox.log
375 RuntimeError: raise
374 RuntimeError: raise
376
375
General Comments 0
You need to be logged in to leave comments. Login now