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