##// END OF EJS Templates
eol: make output stable...
Bryan O'Sullivan -
r27524:f5b6b4e5 default
parent child Browse files
Show More
@@ -1,354 +1,354 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 mercurial.i18n import _
94 from mercurial.i18n import _
95 from mercurial import util, config, extensions, match, error
95 from mercurial import util, config, extensions, match, error
96 import re, os
96 import re, os
97
97
98 # Note for extension authors: ONLY specify testedwith = 'internal' for
98 # Note for extension authors: ONLY specify testedwith = 'internal' for
99 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
99 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
100 # be specifying the version(s) of Mercurial they are tested with, or
100 # be specifying the version(s) of Mercurial they are tested with, or
101 # leave the attribute unspecified.
101 # leave the attribute unspecified.
102 testedwith = 'internal'
102 testedwith = 'internal'
103
103
104 # Matches a lone LF, i.e., one that is not part of CRLF.
104 # Matches a lone LF, i.e., one that is not part of CRLF.
105 singlelf = re.compile('(^|[^\r])\n')
105 singlelf = re.compile('(^|[^\r])\n')
106 # Matches a single EOL which can either be a CRLF where repeated CR
106 # Matches a single EOL which can either be a CRLF where repeated CR
107 # are removed or a LF. We do not care about old Macintosh files, so a
107 # are removed or a LF. We do not care about old Macintosh files, so a
108 # stray CR is an error.
108 # stray CR is an error.
109 eolre = re.compile('\r*\n')
109 eolre = re.compile('\r*\n')
110
110
111
111
112 def inconsistenteol(data):
112 def inconsistenteol(data):
113 return '\r\n' in data and singlelf.search(data)
113 return '\r\n' in data and singlelf.search(data)
114
114
115 def tolf(s, params, ui, **kwargs):
115 def tolf(s, params, ui, **kwargs):
116 """Filter to convert to LF EOLs."""
116 """Filter to convert to LF EOLs."""
117 if util.binary(s):
117 if util.binary(s):
118 return s
118 return s
119 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
119 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
120 return s
120 return s
121 if (ui.configbool('eol', 'fix-trailing-newline', False)
121 if (ui.configbool('eol', 'fix-trailing-newline', False)
122 and s and s[-1] != '\n'):
122 and s and s[-1] != '\n'):
123 s = s + '\n'
123 s = s + '\n'
124 return eolre.sub('\n', s)
124 return eolre.sub('\n', s)
125
125
126 def tocrlf(s, params, ui, **kwargs):
126 def tocrlf(s, params, ui, **kwargs):
127 """Filter to convert to CRLF EOLs."""
127 """Filter to convert to CRLF EOLs."""
128 if util.binary(s):
128 if util.binary(s):
129 return s
129 return s
130 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
130 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
131 return s
131 return s
132 if (ui.configbool('eol', 'fix-trailing-newline', False)
132 if (ui.configbool('eol', 'fix-trailing-newline', False)
133 and s and s[-1] != '\n'):
133 and s and s[-1] != '\n'):
134 s = s + '\n'
134 s = s + '\n'
135 return eolre.sub('\r\n', s)
135 return eolre.sub('\r\n', s)
136
136
137 def isbinary(s, params):
137 def isbinary(s, params):
138 """Filter to do nothing with the file."""
138 """Filter to do nothing with the file."""
139 return s
139 return s
140
140
141 filters = {
141 filters = {
142 'to-lf': tolf,
142 'to-lf': tolf,
143 'to-crlf': tocrlf,
143 'to-crlf': tocrlf,
144 'is-binary': isbinary,
144 'is-binary': isbinary,
145 # The following provide backwards compatibility with win32text
145 # The following provide backwards compatibility with win32text
146 'cleverencode:': tolf,
146 'cleverencode:': tolf,
147 'cleverdecode:': tocrlf
147 'cleverdecode:': tocrlf
148 }
148 }
149
149
150 class eolfile(object):
150 class eolfile(object):
151 def __init__(self, ui, root, data):
151 def __init__(self, ui, root, data):
152 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
152 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
153 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
153 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
154
154
155 self.cfg = config.config()
155 self.cfg = config.config()
156 # Our files should not be touched. The pattern must be
156 # Our files should not be touched. The pattern must be
157 # inserted first override a '** = native' pattern.
157 # inserted first override a '** = native' pattern.
158 self.cfg.set('patterns', '.hg*', 'BIN', 'eol')
158 self.cfg.set('patterns', '.hg*', 'BIN', 'eol')
159 # We can then parse the user's patterns.
159 # We can then parse the user's patterns.
160 self.cfg.parse('.hgeol', data)
160 self.cfg.parse('.hgeol', data)
161
161
162 isrepolf = self.cfg.get('repository', 'native') != 'CRLF'
162 isrepolf = self.cfg.get('repository', 'native') != 'CRLF'
163 self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf'
163 self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf'
164 iswdlf = ui.config('eol', 'native', os.linesep) in ('LF', '\n')
164 iswdlf = ui.config('eol', 'native', os.linesep) in ('LF', '\n')
165 self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf'
165 self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf'
166
166
167 include = []
167 include = []
168 exclude = []
168 exclude = []
169 for pattern, style in self.cfg.items('patterns'):
169 for pattern, style in self.cfg.items('patterns'):
170 key = style.upper()
170 key = style.upper()
171 if key == 'BIN':
171 if key == 'BIN':
172 exclude.append(pattern)
172 exclude.append(pattern)
173 else:
173 else:
174 include.append(pattern)
174 include.append(pattern)
175 # This will match the files for which we need to care
175 # This will match the files for which we need to care
176 # about inconsistent newlines.
176 # about inconsistent newlines.
177 self.match = match.match(root, '', [], include, exclude)
177 self.match = match.match(root, '', [], include, exclude)
178
178
179 def copytoui(self, ui):
179 def copytoui(self, ui):
180 for pattern, style in self.cfg.items('patterns'):
180 for pattern, style in self.cfg.items('patterns'):
181 key = style.upper()
181 key = style.upper()
182 try:
182 try:
183 ui.setconfig('decode', pattern, self._decode[key], 'eol')
183 ui.setconfig('decode', pattern, self._decode[key], 'eol')
184 ui.setconfig('encode', pattern, self._encode[key], 'eol')
184 ui.setconfig('encode', pattern, self._encode[key], 'eol')
185 except KeyError:
185 except KeyError:
186 ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
186 ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
187 % (style, self.cfg.source('patterns', pattern)))
187 % (style, self.cfg.source('patterns', pattern)))
188 # eol.only-consistent can be specified in ~/.hgrc or .hgeol
188 # eol.only-consistent can be specified in ~/.hgrc or .hgeol
189 for k, v in self.cfg.items('eol'):
189 for k, v in self.cfg.items('eol'):
190 ui.setconfig('eol', k, v, 'eol')
190 ui.setconfig('eol', k, v, 'eol')
191
191
192 def checkrev(self, repo, ctx, files):
192 def checkrev(self, repo, ctx, files):
193 failed = []
193 failed = []
194 for f in (files or ctx.files()):
194 for f in (files or ctx.files()):
195 if f not in ctx:
195 if f not in ctx:
196 continue
196 continue
197 for pattern, style in self.cfg.items('patterns'):
197 for pattern, style in self.cfg.items('patterns'):
198 if not match.match(repo.root, '', [pattern])(f):
198 if not match.match(repo.root, '', [pattern])(f):
199 continue
199 continue
200 target = self._encode[style.upper()]
200 target = self._encode[style.upper()]
201 data = ctx[f].data()
201 data = ctx[f].data()
202 if (target == "to-lf" and "\r\n" in data
202 if (target == "to-lf" and "\r\n" in data
203 or target == "to-crlf" and singlelf.search(data)):
203 or target == "to-crlf" and singlelf.search(data)):
204 failed.append((str(ctx), target, f))
204 failed.append((f, target, str(ctx)))
205 break
205 break
206 return failed
206 return failed
207
207
208 def parseeol(ui, repo, nodes):
208 def parseeol(ui, repo, nodes):
209 try:
209 try:
210 for node in nodes:
210 for node in nodes:
211 try:
211 try:
212 if node is None:
212 if node is None:
213 # Cannot use workingctx.data() since it would load
213 # Cannot use workingctx.data() since it would load
214 # and cache the filters before we configure them.
214 # and cache the filters before we configure them.
215 data = repo.wfile('.hgeol').read()
215 data = repo.wfile('.hgeol').read()
216 else:
216 else:
217 data = repo[node]['.hgeol'].data()
217 data = repo[node]['.hgeol'].data()
218 return eolfile(ui, repo.root, data)
218 return eolfile(ui, repo.root, data)
219 except (IOError, LookupError):
219 except (IOError, LookupError):
220 pass
220 pass
221 except error.ParseError as inst:
221 except error.ParseError as inst:
222 ui.warn(_("warning: ignoring .hgeol file due to parse error "
222 ui.warn(_("warning: ignoring .hgeol file due to parse error "
223 "at %s: %s\n") % (inst.args[1], inst.args[0]))
223 "at %s: %s\n") % (inst.args[1], inst.args[0]))
224 return None
224 return None
225
225
226 def _checkhook(ui, repo, node, headsonly):
226 def _checkhook(ui, repo, node, headsonly):
227 # Get revisions to check and touched files at the same time
227 # Get revisions to check and touched files at the same time
228 files = set()
228 files = set()
229 revs = set()
229 revs = set()
230 for rev in xrange(repo[node].rev(), len(repo)):
230 for rev in xrange(repo[node].rev(), len(repo)):
231 revs.add(rev)
231 revs.add(rev)
232 if headsonly:
232 if headsonly:
233 ctx = repo[rev]
233 ctx = repo[rev]
234 files.update(ctx.files())
234 files.update(ctx.files())
235 for pctx in ctx.parents():
235 for pctx in ctx.parents():
236 revs.discard(pctx.rev())
236 revs.discard(pctx.rev())
237 failed = []
237 failed = []
238 for rev in revs:
238 for rev in revs:
239 ctx = repo[rev]
239 ctx = repo[rev]
240 eol = parseeol(ui, repo, [ctx.node()])
240 eol = parseeol(ui, repo, [ctx.node()])
241 if eol:
241 if eol:
242 failed.extend(eol.checkrev(repo, ctx, files))
242 failed.extend(eol.checkrev(repo, ctx, files))
243
243
244 if failed:
244 if failed:
245 eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'}
245 eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'}
246 msgs = []
246 msgs = []
247 for node, target, f in failed:
247 for f, target, node in sorted(failed):
248 msgs.append(_(" %s in %s should not have %s line endings") %
248 msgs.append(_(" %s in %s should not have %s line endings") %
249 (f, node, eols[target]))
249 (f, node, eols[target]))
250 raise error.Abort(_("end-of-line check failed:\n") + "\n".join(msgs))
250 raise error.Abort(_("end-of-line check failed:\n") + "\n".join(msgs))
251
251
252 def checkallhook(ui, repo, node, hooktype, **kwargs):
252 def checkallhook(ui, repo, node, hooktype, **kwargs):
253 """verify that files have expected EOLs"""
253 """verify that files have expected EOLs"""
254 _checkhook(ui, repo, node, False)
254 _checkhook(ui, repo, node, False)
255
255
256 def checkheadshook(ui, repo, node, hooktype, **kwargs):
256 def checkheadshook(ui, repo, node, hooktype, **kwargs):
257 """verify that files have expected EOLs"""
257 """verify that files have expected EOLs"""
258 _checkhook(ui, repo, node, True)
258 _checkhook(ui, repo, node, True)
259
259
260 # "checkheadshook" used to be called "hook"
260 # "checkheadshook" used to be called "hook"
261 hook = checkheadshook
261 hook = checkheadshook
262
262
263 def preupdate(ui, repo, hooktype, parent1, parent2):
263 def preupdate(ui, repo, hooktype, parent1, parent2):
264 repo.loadeol([parent1])
264 repo.loadeol([parent1])
265 return False
265 return False
266
266
267 def uisetup(ui):
267 def uisetup(ui):
268 ui.setconfig('hooks', 'preupdate.eol', preupdate, 'eol')
268 ui.setconfig('hooks', 'preupdate.eol', preupdate, 'eol')
269
269
270 def extsetup(ui):
270 def extsetup(ui):
271 try:
271 try:
272 extensions.find('win32text')
272 extensions.find('win32text')
273 ui.warn(_("the eol extension is incompatible with the "
273 ui.warn(_("the eol extension is incompatible with the "
274 "win32text extension\n"))
274 "win32text extension\n"))
275 except KeyError:
275 except KeyError:
276 pass
276 pass
277
277
278
278
279 def reposetup(ui, repo):
279 def reposetup(ui, repo):
280 uisetup(repo.ui)
280 uisetup(repo.ui)
281
281
282 if not repo.local():
282 if not repo.local():
283 return
283 return
284 for name, fn in filters.iteritems():
284 for name, fn in filters.iteritems():
285 repo.adddatafilter(name, fn)
285 repo.adddatafilter(name, fn)
286
286
287 ui.setconfig('patch', 'eol', 'auto', 'eol')
287 ui.setconfig('patch', 'eol', 'auto', 'eol')
288
288
289 class eolrepo(repo.__class__):
289 class eolrepo(repo.__class__):
290
290
291 def loadeol(self, nodes):
291 def loadeol(self, nodes):
292 eol = parseeol(self.ui, self, nodes)
292 eol = parseeol(self.ui, self, nodes)
293 if eol is None:
293 if eol is None:
294 return None
294 return None
295 eol.copytoui(self.ui)
295 eol.copytoui(self.ui)
296 return eol.match
296 return eol.match
297
297
298 def _hgcleardirstate(self):
298 def _hgcleardirstate(self):
299 self._eolfile = self.loadeol([None, 'tip'])
299 self._eolfile = self.loadeol([None, 'tip'])
300 if not self._eolfile:
300 if not self._eolfile:
301 self._eolfile = util.never
301 self._eolfile = util.never
302 return
302 return
303
303
304 try:
304 try:
305 cachemtime = os.path.getmtime(self.join("eol.cache"))
305 cachemtime = os.path.getmtime(self.join("eol.cache"))
306 except OSError:
306 except OSError:
307 cachemtime = 0
307 cachemtime = 0
308
308
309 try:
309 try:
310 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
310 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
311 except OSError:
311 except OSError:
312 eolmtime = 0
312 eolmtime = 0
313
313
314 if eolmtime > cachemtime:
314 if eolmtime > cachemtime:
315 self.ui.debug("eol: detected change in .hgeol\n")
315 self.ui.debug("eol: detected change in .hgeol\n")
316 wlock = None
316 wlock = None
317 try:
317 try:
318 wlock = self.wlock()
318 wlock = self.wlock()
319 for f in self.dirstate:
319 for f in self.dirstate:
320 if self.dirstate[f] == 'n':
320 if self.dirstate[f] == 'n':
321 # all normal files need to be looked at
321 # all normal files need to be looked at
322 # again since the new .hgeol file might no
322 # again since the new .hgeol file might no
323 # longer match a file it matched before
323 # longer match a file it matched before
324 self.dirstate.normallookup(f)
324 self.dirstate.normallookup(f)
325 # Create or touch the cache to update mtime
325 # Create or touch the cache to update mtime
326 self.vfs("eol.cache", "w").close()
326 self.vfs("eol.cache", "w").close()
327 wlock.release()
327 wlock.release()
328 except error.LockUnavailable:
328 except error.LockUnavailable:
329 # If we cannot lock the repository and clear the
329 # If we cannot lock the repository and clear the
330 # dirstate, then a commit might not see all files
330 # dirstate, then a commit might not see all files
331 # as modified. But if we cannot lock the
331 # as modified. But if we cannot lock the
332 # repository, then we can also not make a commit,
332 # repository, then we can also not make a commit,
333 # so ignore the error.
333 # so ignore the error.
334 pass
334 pass
335
335
336 def commitctx(self, ctx, haserror=False):
336 def commitctx(self, ctx, haserror=False):
337 for f in sorted(ctx.added() + ctx.modified()):
337 for f in sorted(ctx.added() + ctx.modified()):
338 if not self._eolfile(f):
338 if not self._eolfile(f):
339 continue
339 continue
340 fctx = ctx[f]
340 fctx = ctx[f]
341 if fctx is None:
341 if fctx is None:
342 continue
342 continue
343 data = fctx.data()
343 data = fctx.data()
344 if util.binary(data):
344 if util.binary(data):
345 # We should not abort here, since the user should
345 # We should not abort here, since the user should
346 # be able to say "** = native" to automatically
346 # be able to say "** = native" to automatically
347 # have all non-binary files taken care of.
347 # have all non-binary files taken care of.
348 continue
348 continue
349 if inconsistenteol(data):
349 if inconsistenteol(data):
350 raise error.Abort(_("inconsistent newline style "
350 raise error.Abort(_("inconsistent newline style "
351 "in %s\n") % f)
351 "in %s\n") % f)
352 return super(eolrepo, self).commitctx(ctx, haserror)
352 return super(eolrepo, self).commitctx(ctx, haserror)
353 repo.__class__ = eolrepo
353 repo.__class__ = eolrepo
354 repo._hgcleardirstate()
354 repo._hgcleardirstate()
@@ -1,218 +1,218 b''
1 Test the EOL hook
1 Test the EOL hook
2
2
3 $ hg init main
3 $ hg init main
4 $ cat > main/.hg/hgrc <<EOF
4 $ cat > main/.hg/hgrc <<EOF
5 > [hooks]
5 > [hooks]
6 > pretxnchangegroup = python:hgext.eol.hook
6 > pretxnchangegroup = python:hgext.eol.hook
7 > EOF
7 > EOF
8 $ hg clone main fork
8 $ hg clone main fork
9 updating to branch default
9 updating to branch default
10 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
10 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 $ cd fork
11 $ cd fork
12
12
13 Create repo
13 Create repo
14 $ cat > .hgeol <<EOF
14 $ cat > .hgeol <<EOF
15 > [patterns]
15 > [patterns]
16 > mixed.txt = BIN
16 > mixed.txt = BIN
17 > crlf.txt = CRLF
17 > crlf.txt = CRLF
18 > **.txt = native
18 > **.txt = native
19 > EOF
19 > EOF
20 $ hg add .hgeol
20 $ hg add .hgeol
21 $ hg commit -m 'Commit .hgeol'
21 $ hg commit -m 'Commit .hgeol'
22
22
23 $ printf "first\nsecond\nthird\n" > a.txt
23 $ printf "first\nsecond\nthird\n" > a.txt
24 $ hg add a.txt
24 $ hg add a.txt
25 $ hg commit -m 'LF a.txt'
25 $ hg commit -m 'LF a.txt'
26 $ hg push ../main
26 $ hg push ../main
27 pushing to ../main
27 pushing to ../main
28 searching for changes
28 searching for changes
29 adding changesets
29 adding changesets
30 adding manifests
30 adding manifests
31 adding file changes
31 adding file changes
32 added 2 changesets with 2 changes to 2 files
32 added 2 changesets with 2 changes to 2 files
33
33
34 $ printf "first\r\nsecond\r\nthird\n" > a.txt
34 $ printf "first\r\nsecond\r\nthird\n" > a.txt
35 $ hg commit -m 'CRLF a.txt'
35 $ hg commit -m 'CRLF a.txt'
36 $ hg push ../main
36 $ hg push ../main
37 pushing to ../main
37 pushing to ../main
38 searching for changes
38 searching for changes
39 adding changesets
39 adding changesets
40 adding manifests
40 adding manifests
41 adding file changes
41 adding file changes
42 added 1 changesets with 1 changes to 1 files
42 added 1 changesets with 1 changes to 1 files
43 error: pretxnchangegroup hook failed: end-of-line check failed:
43 error: pretxnchangegroup hook failed: end-of-line check failed:
44 a.txt in a8ee6548cd86 should not have CRLF line endings
44 a.txt in a8ee6548cd86 should not have CRLF line endings
45 transaction abort!
45 transaction abort!
46 rollback completed
46 rollback completed
47 abort: end-of-line check failed:
47 abort: end-of-line check failed:
48 a.txt in a8ee6548cd86 should not have CRLF line endings
48 a.txt in a8ee6548cd86 should not have CRLF line endings
49 [255]
49 [255]
50
50
51 $ printf "first\nsecond\nthird\n" > a.txt
51 $ printf "first\nsecond\nthird\n" > a.txt
52 $ hg commit -m 'LF a.txt (fixed)'
52 $ hg commit -m 'LF a.txt (fixed)'
53 $ hg push ../main
53 $ hg push ../main
54 pushing to ../main
54 pushing to ../main
55 searching for changes
55 searching for changes
56 adding changesets
56 adding changesets
57 adding manifests
57 adding manifests
58 adding file changes
58 adding file changes
59 added 2 changesets with 2 changes to 1 files
59 added 2 changesets with 2 changes to 1 files
60
60
61 $ printf "first\nsecond\nthird\n" > crlf.txt
61 $ printf "first\nsecond\nthird\n" > crlf.txt
62 $ hg add crlf.txt
62 $ hg add crlf.txt
63 $ hg commit -m 'LF crlf.txt'
63 $ hg commit -m 'LF crlf.txt'
64 $ hg push ../main
64 $ hg push ../main
65 pushing to ../main
65 pushing to ../main
66 searching for changes
66 searching for changes
67 adding changesets
67 adding changesets
68 adding manifests
68 adding manifests
69 adding file changes
69 adding file changes
70 added 1 changesets with 1 changes to 1 files
70 added 1 changesets with 1 changes to 1 files
71 error: pretxnchangegroup hook failed: end-of-line check failed:
71 error: pretxnchangegroup hook failed: end-of-line check failed:
72 crlf.txt in 004ba2132725 should not have LF line endings
72 crlf.txt in 004ba2132725 should not have LF line endings
73 transaction abort!
73 transaction abort!
74 rollback completed
74 rollback completed
75 abort: end-of-line check failed:
75 abort: end-of-line check failed:
76 crlf.txt in 004ba2132725 should not have LF line endings
76 crlf.txt in 004ba2132725 should not have LF line endings
77 [255]
77 [255]
78
78
79 $ printf "first\r\nsecond\r\nthird\r\n" > crlf.txt
79 $ printf "first\r\nsecond\r\nthird\r\n" > crlf.txt
80 $ hg commit -m 'CRLF crlf.txt (fixed)'
80 $ hg commit -m 'CRLF crlf.txt (fixed)'
81 $ hg push ../main
81 $ hg push ../main
82 pushing to ../main
82 pushing to ../main
83 searching for changes
83 searching for changes
84 adding changesets
84 adding changesets
85 adding manifests
85 adding manifests
86 adding file changes
86 adding file changes
87 added 2 changesets with 2 changes to 1 files
87 added 2 changesets with 2 changes to 1 files
88
88
89 $ printf "first\r\nsecond" > b.txt
89 $ printf "first\r\nsecond" > b.txt
90 $ hg add b.txt
90 $ hg add b.txt
91 $ hg commit -m 'CRLF b.txt'
91 $ hg commit -m 'CRLF b.txt'
92 $ hg push ../main
92 $ hg push ../main
93 pushing to ../main
93 pushing to ../main
94 searching for changes
94 searching for changes
95 adding changesets
95 adding changesets
96 adding manifests
96 adding manifests
97 adding file changes
97 adding file changes
98 added 1 changesets with 1 changes to 1 files
98 added 1 changesets with 1 changes to 1 files
99 error: pretxnchangegroup hook failed: end-of-line check failed:
99 error: pretxnchangegroup hook failed: end-of-line check failed:
100 b.txt in fbcf9b1025f5 should not have CRLF line endings
100 b.txt in fbcf9b1025f5 should not have CRLF line endings
101 transaction abort!
101 transaction abort!
102 rollback completed
102 rollback completed
103 abort: end-of-line check failed:
103 abort: end-of-line check failed:
104 b.txt in fbcf9b1025f5 should not have CRLF line endings
104 b.txt in fbcf9b1025f5 should not have CRLF line endings
105 [255]
105 [255]
106
106
107 $ hg up -r -2
107 $ hg up -r -2
108 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
108 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
109 $ printf "some\nother\nfile" > c.txt
109 $ printf "some\nother\nfile" > c.txt
110 $ hg add c.txt
110 $ hg add c.txt
111 $ hg commit -m "LF c.txt, b.txt doesn't exist here"
111 $ hg commit -m "LF c.txt, b.txt doesn't exist here"
112 created new head
112 created new head
113 $ hg push -f ../main
113 $ hg push -f ../main
114 pushing to ../main
114 pushing to ../main
115 searching for changes
115 searching for changes
116 adding changesets
116 adding changesets
117 adding manifests
117 adding manifests
118 adding file changes
118 adding file changes
119 added 2 changesets with 2 changes to 2 files (+1 heads)
119 added 2 changesets with 2 changes to 2 files (+1 heads)
120 error: pretxnchangegroup hook failed: end-of-line check failed:
120 error: pretxnchangegroup hook failed: end-of-line check failed:
121 b.txt in fbcf9b1025f5 should not have CRLF line endings
121 b.txt in fbcf9b1025f5 should not have CRLF line endings
122 transaction abort!
122 transaction abort!
123 rollback completed
123 rollback completed
124 abort: end-of-line check failed:
124 abort: end-of-line check failed:
125 b.txt in fbcf9b1025f5 should not have CRLF line endings
125 b.txt in fbcf9b1025f5 should not have CRLF line endings
126 [255]
126 [255]
127
127
128 Test checkheadshook alias
128 Test checkheadshook alias
129
129
130 $ cat > ../main/.hg/hgrc <<EOF
130 $ cat > ../main/.hg/hgrc <<EOF
131 > [hooks]
131 > [hooks]
132 > pretxnchangegroup = python:hgext.eol.checkheadshook
132 > pretxnchangegroup = python:hgext.eol.checkheadshook
133 > EOF
133 > EOF
134 $ hg push -f ../main
134 $ hg push -f ../main
135 pushing to ../main
135 pushing to ../main
136 searching for changes
136 searching for changes
137 adding changesets
137 adding changesets
138 adding manifests
138 adding manifests
139 adding file changes
139 adding file changes
140 added 2 changesets with 2 changes to 2 files (+1 heads)
140 added 2 changesets with 2 changes to 2 files (+1 heads)
141 error: pretxnchangegroup hook failed: end-of-line check failed:
141 error: pretxnchangegroup hook failed: end-of-line check failed:
142 b.txt in fbcf9b1025f5 should not have CRLF line endings
142 b.txt in fbcf9b1025f5 should not have CRLF line endings
143 transaction abort!
143 transaction abort!
144 rollback completed
144 rollback completed
145 abort: end-of-line check failed:
145 abort: end-of-line check failed:
146 b.txt in fbcf9b1025f5 should not have CRLF line endings
146 b.txt in fbcf9b1025f5 should not have CRLF line endings
147 [255]
147 [255]
148
148
149 We can fix the head and push again
149 We can fix the head and push again
150
150
151 $ hg up 6
151 $ hg up 6
152 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
152 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
153 $ printf "first\nsecond" > b.txt
153 $ printf "first\nsecond" > b.txt
154 $ hg ci -m "remove CRLF from b.txt"
154 $ hg ci -m "remove CRLF from b.txt"
155 $ hg push -f ../main
155 $ hg push -f ../main
156 pushing to ../main
156 pushing to ../main
157 searching for changes
157 searching for changes
158 adding changesets
158 adding changesets
159 adding manifests
159 adding manifests
160 adding file changes
160 adding file changes
161 added 3 changesets with 3 changes to 2 files (+1 heads)
161 added 3 changesets with 3 changes to 2 files (+1 heads)
162 $ hg -R ../main rollback
162 $ hg -R ../main rollback
163 repository tip rolled back to revision 5 (undo push)
163 repository tip rolled back to revision 5 (undo push)
164
164
165 Test it still fails with checkallhook
165 Test it still fails with checkallhook
166
166
167 $ cat > ../main/.hg/hgrc <<EOF
167 $ cat > ../main/.hg/hgrc <<EOF
168 > [hooks]
168 > [hooks]
169 > pretxnchangegroup = python:hgext.eol.checkallhook
169 > pretxnchangegroup = python:hgext.eol.checkallhook
170 > EOF
170 > EOF
171 $ hg push -f ../main
171 $ hg push -f ../main
172 pushing to ../main
172 pushing to ../main
173 searching for changes
173 searching for changes
174 adding changesets
174 adding changesets
175 adding manifests
175 adding manifests
176 adding file changes
176 adding file changes
177 added 3 changesets with 3 changes to 2 files (+1 heads)
177 added 3 changesets with 3 changes to 2 files (+1 heads)
178 error: pretxnchangegroup hook failed: end-of-line check failed:
178 error: pretxnchangegroup hook failed: end-of-line check failed:
179 b.txt in fbcf9b1025f5 should not have CRLF line endings
179 b.txt in fbcf9b1025f5 should not have CRLF line endings
180 transaction abort!
180 transaction abort!
181 rollback completed
181 rollback completed
182 abort: end-of-line check failed:
182 abort: end-of-line check failed:
183 b.txt in fbcf9b1025f5 should not have CRLF line endings
183 b.txt in fbcf9b1025f5 should not have CRLF line endings
184 [255]
184 [255]
185
185
186 But we can push the clean head
186 But we can push the clean head
187
187
188 $ hg push -r7 -f ../main
188 $ hg push -r7 -f ../main
189 pushing to ../main
189 pushing to ../main
190 searching for changes
190 searching for changes
191 adding changesets
191 adding changesets
192 adding manifests
192 adding manifests
193 adding file changes
193 adding file changes
194 added 1 changesets with 1 changes to 1 files
194 added 1 changesets with 1 changes to 1 files
195
195
196 Test multiple files/revisions output
196 Test multiple files/revisions output
197
197
198 $ printf "another\r\nbad\r\none" > d.txt
198 $ printf "another\r\nbad\r\none" > d.txt
199 $ hg add d.txt
199 $ hg add d.txt
200 $ hg ci -m "add d.txt"
200 $ hg ci -m "add d.txt"
201 $ hg push -f ../main
201 $ hg push -f ../main
202 pushing to ../main
202 pushing to ../main
203 searching for changes
203 searching for changes
204 adding changesets
204 adding changesets
205 adding manifests
205 adding manifests
206 adding file changes
206 adding file changes
207 added 3 changesets with 3 changes to 2 files (+1 heads)
207 added 3 changesets with 3 changes to 2 files (+1 heads)
208 error: pretxnchangegroup hook failed: end-of-line check failed:
208 error: pretxnchangegroup hook failed: end-of-line check failed:
209 b.txt in fbcf9b1025f5 should not have CRLF line endings
209 d.txt in a7040e68714f should not have CRLF line endings
210 d.txt in a7040e68714f should not have CRLF line endings
210 b.txt in fbcf9b1025f5 should not have CRLF line endings
211 transaction abort!
211 transaction abort!
212 rollback completed
212 rollback completed
213 abort: end-of-line check failed:
213 abort: end-of-line check failed:
214 b.txt in fbcf9b1025f5 should not have CRLF line endings
214 d.txt in a7040e68714f should not have CRLF line endings
215 d.txt in a7040e68714f should not have CRLF line endings
215 b.txt in fbcf9b1025f5 should not have CRLF line endings
216 [255]
216 [255]
217
217
218 $ cd ..
218 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now