##// END OF EJS Templates
eol: import 'error' as 'errormod'...
marmoute -
r32995:74930cf4 stable
parent child Browse files
Show More
@@ -1,388 +1,388 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,
101 error as errormod,
102 extensions,
102 extensions,
103 match,
103 match,
104 pycompat,
104 pycompat,
105 util,
105 util,
106 )
106 )
107
107
108 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
108 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
109 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
109 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
110 # be specifying the version(s) of Mercurial they are tested with, or
110 # be specifying the version(s) of Mercurial they are tested with, or
111 # leave the attribute unspecified.
111 # leave the attribute unspecified.
112 testedwith = 'ships-with-hg-core'
112 testedwith = 'ships-with-hg-core'
113
113
114 # Matches a lone LF, i.e., one that is not part of CRLF.
114 # Matches a lone LF, i.e., one that is not part of CRLF.
115 singlelf = re.compile('(^|[^\r])\n')
115 singlelf = re.compile('(^|[^\r])\n')
116
116
117 def inconsistenteol(data):
117 def inconsistenteol(data):
118 return '\r\n' in data and singlelf.search(data)
118 return '\r\n' in data and singlelf.search(data)
119
119
120 def tolf(s, params, ui, **kwargs):
120 def tolf(s, params, ui, **kwargs):
121 """Filter to convert to LF EOLs."""
121 """Filter to convert to LF EOLs."""
122 if util.binary(s):
122 if util.binary(s):
123 return s
123 return s
124 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
124 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
125 return s
125 return s
126 if (ui.configbool('eol', 'fix-trailing-newline', False)
126 if (ui.configbool('eol', 'fix-trailing-newline', False)
127 and s and s[-1] != '\n'):
127 and s and s[-1] != '\n'):
128 s = s + '\n'
128 s = s + '\n'
129 return util.tolf(s)
129 return util.tolf(s)
130
130
131 def tocrlf(s, params, ui, **kwargs):
131 def tocrlf(s, params, ui, **kwargs):
132 """Filter to convert to CRLF EOLs."""
132 """Filter to convert to CRLF EOLs."""
133 if util.binary(s):
133 if util.binary(s):
134 return s
134 return s
135 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
135 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
136 return s
136 return s
137 if (ui.configbool('eol', 'fix-trailing-newline', False)
137 if (ui.configbool('eol', 'fix-trailing-newline', False)
138 and s and s[-1] != '\n'):
138 and s and s[-1] != '\n'):
139 s = s + '\n'
139 s = s + '\n'
140 return util.tocrlf(s)
140 return util.tocrlf(s)
141
141
142 def isbinary(s, params):
142 def isbinary(s, params):
143 """Filter to do nothing with the file."""
143 """Filter to do nothing with the file."""
144 return s
144 return s
145
145
146 filters = {
146 filters = {
147 'to-lf': tolf,
147 'to-lf': tolf,
148 'to-crlf': tocrlf,
148 'to-crlf': tocrlf,
149 'is-binary': isbinary,
149 'is-binary': isbinary,
150 # The following provide backwards compatibility with win32text
150 # The following provide backwards compatibility with win32text
151 'cleverencode:': tolf,
151 'cleverencode:': tolf,
152 'cleverdecode:': tocrlf
152 'cleverdecode:': tocrlf
153 }
153 }
154
154
155 class eolfile(object):
155 class eolfile(object):
156 def __init__(self, ui, root, data):
156 def __init__(self, ui, root, data):
157 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
157 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
158 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
158 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
159
159
160 self.cfg = config.config()
160 self.cfg = config.config()
161 # Our files should not be touched. The pattern must be
161 # Our files should not be touched. The pattern must be
162 # inserted first override a '** = native' pattern.
162 # inserted first override a '** = native' pattern.
163 self.cfg.set('patterns', '.hg*', 'BIN', 'eol')
163 self.cfg.set('patterns', '.hg*', 'BIN', 'eol')
164 # We can then parse the user's patterns.
164 # We can then parse the user's patterns.
165 self.cfg.parse('.hgeol', data)
165 self.cfg.parse('.hgeol', data)
166
166
167 isrepolf = self.cfg.get('repository', 'native') != 'CRLF'
167 isrepolf = self.cfg.get('repository', 'native') != 'CRLF'
168 self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf'
168 self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf'
169 iswdlf = ui.config('eol', 'native', pycompat.oslinesep) in ('LF', '\n')
169 iswdlf = ui.config('eol', 'native', pycompat.oslinesep) in ('LF', '\n')
170 self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf'
170 self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf'
171
171
172 include = []
172 include = []
173 exclude = []
173 exclude = []
174 self.patterns = []
174 self.patterns = []
175 for pattern, style in self.cfg.items('patterns'):
175 for pattern, style in self.cfg.items('patterns'):
176 key = style.upper()
176 key = style.upper()
177 if key == 'BIN':
177 if key == 'BIN':
178 exclude.append(pattern)
178 exclude.append(pattern)
179 else:
179 else:
180 include.append(pattern)
180 include.append(pattern)
181 m = match.match(root, '', [pattern])
181 m = match.match(root, '', [pattern])
182 self.patterns.append((pattern, key, m))
182 self.patterns.append((pattern, key, m))
183 # This will match the files for which we need to care
183 # This will match the files for which we need to care
184 # about inconsistent newlines.
184 # about inconsistent newlines.
185 self.match = match.match(root, '', [], include, exclude)
185 self.match = match.match(root, '', [], include, exclude)
186
186
187 def copytoui(self, ui):
187 def copytoui(self, ui):
188 for pattern, key, m in self.patterns:
188 for pattern, key, m in self.patterns:
189 try:
189 try:
190 ui.setconfig('decode', pattern, self._decode[key], 'eol')
190 ui.setconfig('decode', pattern, self._decode[key], 'eol')
191 ui.setconfig('encode', pattern, self._encode[key], 'eol')
191 ui.setconfig('encode', pattern, self._encode[key], 'eol')
192 except KeyError:
192 except KeyError:
193 ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
193 ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
194 % (key, self.cfg.source('patterns', pattern)))
194 % (key, self.cfg.source('patterns', pattern)))
195 # eol.only-consistent can be specified in ~/.hgrc or .hgeol
195 # eol.only-consistent can be specified in ~/.hgrc or .hgeol
196 for k, v in self.cfg.items('eol'):
196 for k, v in self.cfg.items('eol'):
197 ui.setconfig('eol', k, v, 'eol')
197 ui.setconfig('eol', k, v, 'eol')
198
198
199 def checkrev(self, repo, ctx, files):
199 def checkrev(self, repo, ctx, files):
200 failed = []
200 failed = []
201 for f in (files or ctx.files()):
201 for f in (files or ctx.files()):
202 if f not in ctx:
202 if f not in ctx:
203 continue
203 continue
204 for pattern, key, m in self.patterns:
204 for pattern, key, m in self.patterns:
205 if not m(f):
205 if not m(f):
206 continue
206 continue
207 target = self._encode[key]
207 target = self._encode[key]
208 data = ctx[f].data()
208 data = ctx[f].data()
209 if (target == "to-lf" and "\r\n" in data
209 if (target == "to-lf" and "\r\n" in data
210 or target == "to-crlf" and singlelf.search(data)):
210 or target == "to-crlf" and singlelf.search(data)):
211 failed.append((f, target, str(ctx)))
211 failed.append((f, target, str(ctx)))
212 break
212 break
213 return failed
213 return failed
214
214
215 def parseeol(ui, repo, nodes):
215 def parseeol(ui, repo, nodes):
216 try:
216 try:
217 for node in nodes:
217 for node in nodes:
218 try:
218 try:
219 if node is None:
219 if node is None:
220 # Cannot use workingctx.data() since it would load
220 # Cannot use workingctx.data() since it would load
221 # and cache the filters before we configure them.
221 # and cache the filters before we configure them.
222 data = repo.wvfs('.hgeol').read()
222 data = repo.wvfs('.hgeol').read()
223 else:
223 else:
224 data = repo[node]['.hgeol'].data()
224 data = repo[node]['.hgeol'].data()
225 return eolfile(ui, repo.root, data)
225 return eolfile(ui, repo.root, data)
226 except (IOError, LookupError):
226 except (IOError, LookupError):
227 pass
227 pass
228 except error.ParseError as inst:
228 except errormod.ParseError as inst:
229 ui.warn(_("warning: ignoring .hgeol file due to parse error "
229 ui.warn(_("warning: ignoring .hgeol file due to parse error "
230 "at %s: %s\n") % (inst.args[1], inst.args[0]))
230 "at %s: %s\n") % (inst.args[1], inst.args[0]))
231 return None
231 return None
232
232
233 def _checkhook(ui, repo, node, headsonly):
233 def _checkhook(ui, repo, node, headsonly):
234 # Get revisions to check and touched files at the same time
234 # Get revisions to check and touched files at the same time
235 files = set()
235 files = set()
236 revs = set()
236 revs = set()
237 for rev in xrange(repo[node].rev(), len(repo)):
237 for rev in xrange(repo[node].rev(), len(repo)):
238 revs.add(rev)
238 revs.add(rev)
239 if headsonly:
239 if headsonly:
240 ctx = repo[rev]
240 ctx = repo[rev]
241 files.update(ctx.files())
241 files.update(ctx.files())
242 for pctx in ctx.parents():
242 for pctx in ctx.parents():
243 revs.discard(pctx.rev())
243 revs.discard(pctx.rev())
244 failed = []
244 failed = []
245 for rev in revs:
245 for rev in revs:
246 ctx = repo[rev]
246 ctx = repo[rev]
247 eol = parseeol(ui, repo, [ctx.node()])
247 eol = parseeol(ui, repo, [ctx.node()])
248 if eol:
248 if eol:
249 failed.extend(eol.checkrev(repo, ctx, files))
249 failed.extend(eol.checkrev(repo, ctx, files))
250
250
251 if failed:
251 if failed:
252 eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'}
252 eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'}
253 msgs = []
253 msgs = []
254 for f, target, node in sorted(failed):
254 for f, target, node in sorted(failed):
255 msgs.append(_(" %s in %s should not have %s line endings") %
255 msgs.append(_(" %s in %s should not have %s line endings") %
256 (f, node, eols[target]))
256 (f, node, eols[target]))
257 raise error.Abort(_("end-of-line check failed:\n") + "\n".join(msgs))
257 raise errormod.Abort(_("end-of-line check failed:\n") + "\n".join(msgs))
258
258
259 def checkallhook(ui, repo, node, hooktype, **kwargs):
259 def checkallhook(ui, repo, node, hooktype, **kwargs):
260 """verify that files have expected EOLs"""
260 """verify that files have expected EOLs"""
261 _checkhook(ui, repo, node, False)
261 _checkhook(ui, repo, node, False)
262
262
263 def checkheadshook(ui, repo, node, hooktype, **kwargs):
263 def checkheadshook(ui, repo, node, hooktype, **kwargs):
264 """verify that files have expected EOLs"""
264 """verify that files have expected EOLs"""
265 _checkhook(ui, repo, node, True)
265 _checkhook(ui, repo, node, True)
266
266
267 # "checkheadshook" used to be called "hook"
267 # "checkheadshook" used to be called "hook"
268 hook = checkheadshook
268 hook = checkheadshook
269
269
270 def preupdate(ui, repo, hooktype, parent1, parent2):
270 def preupdate(ui, repo, hooktype, parent1, parent2):
271 repo.loadeol([parent1])
271 repo.loadeol([parent1])
272 return False
272 return False
273
273
274 def uisetup(ui):
274 def uisetup(ui):
275 ui.setconfig('hooks', 'preupdate.eol', preupdate, 'eol')
275 ui.setconfig('hooks', 'preupdate.eol', preupdate, 'eol')
276
276
277 def extsetup(ui):
277 def extsetup(ui):
278 try:
278 try:
279 extensions.find('win32text')
279 extensions.find('win32text')
280 ui.warn(_("the eol extension is incompatible with the "
280 ui.warn(_("the eol extension is incompatible with the "
281 "win32text extension\n"))
281 "win32text extension\n"))
282 except KeyError:
282 except KeyError:
283 pass
283 pass
284
284
285
285
286 def reposetup(ui, repo):
286 def reposetup(ui, repo):
287 uisetup(repo.ui)
287 uisetup(repo.ui)
288
288
289 if not repo.local():
289 if not repo.local():
290 return
290 return
291 for name, fn in filters.iteritems():
291 for name, fn in filters.iteritems():
292 repo.adddatafilter(name, fn)
292 repo.adddatafilter(name, fn)
293
293
294 ui.setconfig('patch', 'eol', 'auto', 'eol')
294 ui.setconfig('patch', 'eol', 'auto', 'eol')
295
295
296 class eolrepo(repo.__class__):
296 class eolrepo(repo.__class__):
297
297
298 def loadeol(self, nodes):
298 def loadeol(self, nodes):
299 eol = parseeol(self.ui, self, nodes)
299 eol = parseeol(self.ui, self, nodes)
300 if eol is None:
300 if eol is None:
301 return None
301 return None
302 eol.copytoui(self.ui)
302 eol.copytoui(self.ui)
303 return eol.match
303 return eol.match
304
304
305 def _hgcleardirstate(self):
305 def _hgcleardirstate(self):
306 self._eolmatch = self.loadeol([None, 'tip'])
306 self._eolmatch = self.loadeol([None, 'tip'])
307 if not self._eolmatch:
307 if not self._eolmatch:
308 self._eolmatch = util.never
308 self._eolmatch = util.never
309 return
309 return
310
310
311 oldeol = None
311 oldeol = None
312 try:
312 try:
313 cachemtime = os.path.getmtime(self.vfs.join("eol.cache"))
313 cachemtime = os.path.getmtime(self.vfs.join("eol.cache"))
314 except OSError:
314 except OSError:
315 cachemtime = 0
315 cachemtime = 0
316 else:
316 else:
317 olddata = self.vfs.read("eol.cache")
317 olddata = self.vfs.read("eol.cache")
318 if olddata:
318 if olddata:
319 oldeol = eolfile(self.ui, self.root, olddata)
319 oldeol = eolfile(self.ui, self.root, olddata)
320
320
321 try:
321 try:
322 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
322 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
323 except OSError:
323 except OSError:
324 eolmtime = 0
324 eolmtime = 0
325
325
326 if eolmtime > cachemtime:
326 if eolmtime > cachemtime:
327 self.ui.debug("eol: detected change in .hgeol\n")
327 self.ui.debug("eol: detected change in .hgeol\n")
328
328
329 hgeoldata = self.wvfs.read('.hgeol')
329 hgeoldata = self.wvfs.read('.hgeol')
330 neweol = eolfile(self.ui, self.root, hgeoldata)
330 neweol = eolfile(self.ui, self.root, hgeoldata)
331
331
332 wlock = None
332 wlock = None
333 try:
333 try:
334 wlock = self.wlock()
334 wlock = self.wlock()
335 for f in self.dirstate:
335 for f in self.dirstate:
336 if self.dirstate[f] != 'n':
336 if self.dirstate[f] != 'n':
337 continue
337 continue
338 if oldeol is not None:
338 if oldeol is not None:
339 if not oldeol.match(f) and not neweol.match(f):
339 if not oldeol.match(f) and not neweol.match(f):
340 continue
340 continue
341 oldkey = None
341 oldkey = None
342 for pattern, key, m in oldeol.patterns:
342 for pattern, key, m in oldeol.patterns:
343 if m(f):
343 if m(f):
344 oldkey = key
344 oldkey = key
345 break
345 break
346 newkey = None
346 newkey = None
347 for pattern, key, m in neweol.patterns:
347 for pattern, key, m in neweol.patterns:
348 if m(f):
348 if m(f):
349 newkey = key
349 newkey = key
350 break
350 break
351 if oldkey == newkey:
351 if oldkey == newkey:
352 continue
352 continue
353 # all normal files need to be looked at again since
353 # all normal files need to be looked at again since
354 # the new .hgeol file specify a different filter
354 # the new .hgeol file specify a different filter
355 self.dirstate.normallookup(f)
355 self.dirstate.normallookup(f)
356 # Write the cache to update mtime and cache .hgeol
356 # Write the cache to update mtime and cache .hgeol
357 with self.vfs("eol.cache", "w") as f:
357 with self.vfs("eol.cache", "w") as f:
358 f.write(hgeoldata)
358 f.write(hgeoldata)
359 except error.LockUnavailable:
359 except errormod.LockUnavailable:
360 # If we cannot lock the repository and clear the
360 # If we cannot lock the repository and clear the
361 # dirstate, then a commit might not see all files
361 # dirstate, then a commit might not see all files
362 # as modified. But if we cannot lock the
362 # as modified. But if we cannot lock the
363 # repository, then we can also not make a commit,
363 # repository, then we can also not make a commit,
364 # so ignore the error.
364 # so ignore the error.
365 pass
365 pass
366 finally:
366 finally:
367 if wlock is not None:
367 if wlock is not None:
368 wlock.release()
368 wlock.release()
369
369
370 def commitctx(self, ctx, haserror=False):
370 def commitctx(self, ctx, haserror=False):
371 for f in sorted(ctx.added() + ctx.modified()):
371 for f in sorted(ctx.added() + ctx.modified()):
372 if not self._eolmatch(f):
372 if not self._eolmatch(f):
373 continue
373 continue
374 fctx = ctx[f]
374 fctx = ctx[f]
375 if fctx is None:
375 if fctx is None:
376 continue
376 continue
377 data = fctx.data()
377 data = fctx.data()
378 if util.binary(data):
378 if util.binary(data):
379 # We should not abort here, since the user should
379 # We should not abort here, since the user should
380 # be able to say "** = native" to automatically
380 # be able to say "** = native" to automatically
381 # have all non-binary files taken care of.
381 # have all non-binary files taken care of.
382 continue
382 continue
383 if inconsistenteol(data):
383 if inconsistenteol(data):
384 raise error.Abort(_("inconsistent newline style "
384 raise errormod.Abort(_("inconsistent newline style "
385 "in %s\n") % f)
385 "in %s\n") % f)
386 return super(eolrepo, self).commitctx(ctx, haserror)
386 return super(eolrepo, self).commitctx(ctx, haserror)
387 repo.__class__ = eolrepo
387 repo.__class__ = eolrepo
388 repo._hgcleardirstate()
388 repo._hgcleardirstate()
General Comments 0
You need to be logged in to leave comments. Login now