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