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