##// END OF EJS Templates
merge with crew
Patrick Mezard -
r13652:0652b2da merge default
parent child Browse files
Show More
@@ -1,325 +1,332 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 copy. The
9 configuration file found in the root of the working copy. 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 copy and the repository. The format is
15 converted between the working copy 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 behaviour; it is only needed if you need to override a later,
26 default behaviour; 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 The rules will first apply when files are touched in the working
52 The rules will first apply when files are touched in the working
53 copy, e.g. by updating to null and back to tip to touch all files.
53 copy, e.g. by updating to null and back to tip to touch all files.
54
54
55 The extension uses an optional ``[eol]`` section in your hgrc file
55 The extension uses an optional ``[eol]`` section in your hgrc file
56 (not the ``.hgeol`` file) for settings that control the overall
56 (not the ``.hgeol`` file) for settings that control the overall
57 behavior. There are two settings:
57 behavior. There are two settings:
58
58
59 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
59 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
60 ``CRLF`` to override the default interpretation of ``native`` for
60 ``CRLF`` to override the default interpretation of ``native`` for
61 checkout. This can be used with :hg:`archive` on Unix, say, to
61 checkout. This can be used with :hg:`archive` on Unix, say, to
62 generate an archive where files have line endings for Windows.
62 generate an archive where files have line endings for Windows.
63
63
64 - ``eol.only-consistent`` (default True) can be set to False to make
64 - ``eol.only-consistent`` (default True) can be set to False to make
65 the extension convert files with inconsistent EOLs. Inconsistent
65 the extension convert files with inconsistent EOLs. Inconsistent
66 means that there is both ``CRLF`` and ``LF`` present in the file.
66 means that there is both ``CRLF`` and ``LF`` present in the file.
67 Such files are normally not touched under the assumption that they
67 Such files are normally not touched under the assumption that they
68 have mixed EOLs on purpose.
68 have mixed EOLs on purpose.
69
69
70 The extension provides ``cleverencode:`` and ``cleverdecode:`` filters
70 The extension provides ``cleverencode:`` and ``cleverdecode:`` filters
71 like the deprecated win32text extension does. This means that you can
71 like the deprecated win32text extension does. This means that you can
72 disable win32text and enable eol and your filters will still work. You
72 disable win32text and enable eol and your filters will still work. You
73 only need to these filters until you have prepared a ``.hgeol`` file.
73 only need to these filters until you have prepared a ``.hgeol`` file.
74
74
75 The ``win32text.forbid*`` hooks provided by the win32text extension
75 The ``win32text.forbid*`` hooks provided by the win32text extension
76 have been unified into a single hook named ``eol.checkheadshook``. The
76 have been unified into a single hook named ``eol.checkheadshook``. The
77 hook will lookup the expected line endings from the ``.hgeol`` file,
77 hook will lookup the expected line endings from the ``.hgeol`` file,
78 which means you must migrate to a ``.hgeol`` file first before using
78 which means you must migrate to a ``.hgeol`` file first before using
79 the hook. ``eol.checkheadshook`` only checks heads, intermediate
79 the hook. ``eol.checkheadshook`` only checks heads, intermediate
80 invalid revisions will be pushed. To forbid them completely, use the
80 invalid revisions will be pushed. To forbid them completely, use the
81 ``eol.checkallhook`` hook. These hooks are best used as
81 ``eol.checkallhook`` hook. These hooks are best used as
82 ``pretxnchangegroup`` hooks.
82 ``pretxnchangegroup`` hooks.
83
83
84 See :hg:`help patterns` for more information about the glob patterns
84 See :hg:`help patterns` for more information about the glob patterns
85 used.
85 used.
86 """
86 """
87
87
88 from mercurial.i18n import _
88 from mercurial.i18n import _
89 from mercurial import util, config, extensions, match, error
89 from mercurial import util, config, extensions, match, error
90 import re, os
90 import re, os
91
91
92 # Matches a lone LF, i.e., one that is not part of CRLF.
92 # Matches a lone LF, i.e., one that is not part of CRLF.
93 singlelf = re.compile('(^|[^\r])\n')
93 singlelf = re.compile('(^|[^\r])\n')
94 # Matches a single EOL which can either be a CRLF where repeated CR
94 # Matches a single EOL which can either be a CRLF where repeated CR
95 # are removed or a LF. We do not care about old Machintosh files, so a
95 # are removed or a LF. We do not care about old Machintosh files, so a
96 # stray CR is an error.
96 # stray CR is an error.
97 eolre = re.compile('\r*\n')
97 eolre = re.compile('\r*\n')
98
98
99
99
100 def inconsistenteol(data):
100 def inconsistenteol(data):
101 return '\r\n' in data and singlelf.search(data)
101 return '\r\n' in data and singlelf.search(data)
102
102
103 def tolf(s, params, ui, **kwargs):
103 def tolf(s, params, ui, **kwargs):
104 """Filter to convert to LF EOLs."""
104 """Filter to convert to LF EOLs."""
105 if util.binary(s):
105 if util.binary(s):
106 return s
106 return s
107 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
107 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
108 return s
108 return s
109 return eolre.sub('\n', s)
109 return eolre.sub('\n', s)
110
110
111 def tocrlf(s, params, ui, **kwargs):
111 def tocrlf(s, params, ui, **kwargs):
112 """Filter to convert to CRLF EOLs."""
112 """Filter to convert to CRLF EOLs."""
113 if util.binary(s):
113 if util.binary(s):
114 return s
114 return s
115 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
115 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
116 return s
116 return s
117 return eolre.sub('\r\n', s)
117 return eolre.sub('\r\n', s)
118
118
119 def isbinary(s, params):
119 def isbinary(s, params):
120 """Filter to do nothing with the file."""
120 """Filter to do nothing with the file."""
121 return s
121 return s
122
122
123 filters = {
123 filters = {
124 'to-lf': tolf,
124 'to-lf': tolf,
125 'to-crlf': tocrlf,
125 'to-crlf': tocrlf,
126 'is-binary': isbinary,
126 'is-binary': isbinary,
127 # The following provide backwards compatibility with win32text
127 # The following provide backwards compatibility with win32text
128 'cleverencode:': tolf,
128 'cleverencode:': tolf,
129 'cleverdecode:': tocrlf
129 'cleverdecode:': tocrlf
130 }
130 }
131
131
132 class eolfile(object):
132 class eolfile(object):
133 def __init__(self, ui, root, data):
133 def __init__(self, ui, root, data):
134 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
134 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
135 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
135 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
136
136
137 self.cfg = config.config()
137 self.cfg = config.config()
138 # Our files should not be touched. The pattern must be
138 # Our files should not be touched. The pattern must be
139 # inserted first override a '** = native' pattern.
139 # inserted first override a '** = native' pattern.
140 self.cfg.set('patterns', '.hg*', 'BIN')
140 self.cfg.set('patterns', '.hg*', 'BIN')
141 # We can then parse the user's patterns.
141 # We can then parse the user's patterns.
142 self.cfg.parse('.hgeol', data)
142 self.cfg.parse('.hgeol', data)
143
143
144 isrepolf = self.cfg.get('repository', 'native') != 'CRLF'
144 isrepolf = self.cfg.get('repository', 'native') != 'CRLF'
145 self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf'
145 self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf'
146 iswdlf = ui.config('eol', 'native', os.linesep) in ('LF', '\n')
146 iswdlf = ui.config('eol', 'native', os.linesep) in ('LF', '\n')
147 self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf'
147 self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf'
148
148
149 include = []
149 include = []
150 exclude = []
150 exclude = []
151 for pattern, style in self.cfg.items('patterns'):
151 for pattern, style in self.cfg.items('patterns'):
152 key = style.upper()
152 key = style.upper()
153 if key == 'BIN':
153 if key == 'BIN':
154 exclude.append(pattern)
154 exclude.append(pattern)
155 else:
155 else:
156 include.append(pattern)
156 include.append(pattern)
157 # This will match the files for which we need to care
157 # This will match the files for which we need to care
158 # about inconsistent newlines.
158 # about inconsistent newlines.
159 self.match = match.match(root, '', [], include, exclude)
159 self.match = match.match(root, '', [], include, exclude)
160
160
161 def setfilters(self, ui):
161 def setfilters(self, ui):
162 for pattern, style in self.cfg.items('patterns'):
162 for pattern, style in self.cfg.items('patterns'):
163 key = style.upper()
163 key = style.upper()
164 try:
164 try:
165 ui.setconfig('decode', pattern, self._decode[key])
165 ui.setconfig('decode', pattern, self._decode[key])
166 ui.setconfig('encode', pattern, self._encode[key])
166 ui.setconfig('encode', pattern, self._encode[key])
167 except KeyError:
167 except KeyError:
168 ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
168 ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
169 % (style, self.cfg.source('patterns', pattern)))
169 % (style, self.cfg.source('patterns', pattern)))
170
170
171 def checkrev(self, repo, ctx, files):
171 def checkrev(self, repo, ctx, files):
172 for f in files:
172 failed = []
173 for f in (files or ctx.files()):
173 if f not in ctx:
174 if f not in ctx:
174 continue
175 continue
175 for pattern, style in self.cfg.items('patterns'):
176 for pattern, style in self.cfg.items('patterns'):
176 if not match.match(repo.root, '', [pattern])(f):
177 if not match.match(repo.root, '', [pattern])(f):
177 continue
178 continue
178 target = self._encode[style.upper()]
179 target = self._encode[style.upper()]
179 data = ctx[f].data()
180 data = ctx[f].data()
180 if target == "to-lf" and "\r\n" in data:
181 if (target == "to-lf" and "\r\n" in data
181 raise util.Abort(_("%s should not have CRLF line endings")
182 or target == "to-crlf" and singlelf.search(data)):
182 % f)
183 failed.append((str(ctx), target, f))
183 elif target == "to-crlf" and singlelf.search(data):
184 raise util.Abort(_("%s should not have LF line endings")
185 % f)
186 # Ignore other rules for this file
187 break
184 break
185 return failed
188
186
189 def parseeol(ui, repo, nodes):
187 def parseeol(ui, repo, nodes):
190 try:
188 try:
191 for node in nodes:
189 for node in nodes:
192 try:
190 try:
193 if node is None:
191 if node is None:
194 # Cannot use workingctx.data() since it would load
192 # Cannot use workingctx.data() since it would load
195 # and cache the filters before we configure them.
193 # and cache the filters before we configure them.
196 data = repo.wfile('.hgeol').read()
194 data = repo.wfile('.hgeol').read()
197 else:
195 else:
198 data = repo[node]['.hgeol'].data()
196 data = repo[node]['.hgeol'].data()
199 return eolfile(ui, repo.root, data)
197 return eolfile(ui, repo.root, data)
200 except (IOError, LookupError):
198 except (IOError, LookupError):
201 pass
199 pass
202 except error.ParseError, inst:
200 except error.ParseError, inst:
203 ui.warn(_("warning: ignoring .hgeol file due to parse error "
201 ui.warn(_("warning: ignoring .hgeol file due to parse error "
204 "at %s: %s\n") % (inst.args[1], inst.args[0]))
202 "at %s: %s\n") % (inst.args[1], inst.args[0]))
205 return None
203 return None
206
204
207 def _checkhook(ui, repo, node, headsonly):
205 def _checkhook(ui, repo, node, headsonly):
208 # Get revisions to check and touched files at the same time
206 # Get revisions to check and touched files at the same time
209 files = set()
207 files = set()
210 revs = set()
208 revs = set()
211 for rev in xrange(repo[node].rev(), len(repo)):
209 for rev in xrange(repo[node].rev(), len(repo)):
212 ctx = repo[rev]
213 files.update(ctx.files())
214 revs.add(rev)
210 revs.add(rev)
215 if headsonly:
211 if headsonly:
212 ctx = repo[rev]
213 files.update(ctx.files())
216 for pctx in ctx.parents():
214 for pctx in ctx.parents():
217 revs.discard(pctx.rev())
215 revs.discard(pctx.rev())
216 failed = []
218 for rev in revs:
217 for rev in revs:
219 ctx = repo[rev]
218 ctx = repo[rev]
220 eol = parseeol(ui, repo, [ctx.node()])
219 eol = parseeol(ui, repo, [ctx.node()])
221 if eol:
220 if eol:
222 eol.checkrev(repo, ctx, files)
221 failed.extend(eol.checkrev(repo, ctx, files))
222
223 if failed:
224 eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'}
225 msgs = []
226 for node, target, f in failed:
227 msgs.append(_(" %s in %s should not have %s line endings") %
228 (f, node, eols[target]))
229 raise util.Abort(_("end-of-line check failed:\n") + "\n".join(msgs))
223
230
224 def checkallhook(ui, repo, node, hooktype, **kwargs):
231 def checkallhook(ui, repo, node, hooktype, **kwargs):
225 """verify that files have expected EOLs"""
232 """verify that files have expected EOLs"""
226 _checkhook(ui, repo, node, False)
233 _checkhook(ui, repo, node, False)
227
234
228 def checkheadshook(ui, repo, node, hooktype, **kwargs):
235 def checkheadshook(ui, repo, node, hooktype, **kwargs):
229 """verify that files have expected EOLs"""
236 """verify that files have expected EOLs"""
230 _checkhook(ui, repo, node, True)
237 _checkhook(ui, repo, node, True)
231
238
232 # "checkheadshook" used to be called "hook"
239 # "checkheadshook" used to be called "hook"
233 hook = checkheadshook
240 hook = checkheadshook
234
241
235 def preupdate(ui, repo, hooktype, parent1, parent2):
242 def preupdate(ui, repo, hooktype, parent1, parent2):
236 #print "preupdate for %s: %s -> %s" % (repo.root, parent1, parent2)
243 #print "preupdate for %s: %s -> %s" % (repo.root, parent1, parent2)
237 repo.loadeol([parent1])
244 repo.loadeol([parent1])
238 return False
245 return False
239
246
240 def uisetup(ui):
247 def uisetup(ui):
241 ui.setconfig('hooks', 'preupdate.eol', preupdate)
248 ui.setconfig('hooks', 'preupdate.eol', preupdate)
242
249
243 def extsetup(ui):
250 def extsetup(ui):
244 try:
251 try:
245 extensions.find('win32text')
252 extensions.find('win32text')
246 ui.warn(_("the eol extension is incompatible with the "
253 ui.warn(_("the eol extension is incompatible with the "
247 "win32text extension\n"))
254 "win32text extension\n"))
248 except KeyError:
255 except KeyError:
249 pass
256 pass
250
257
251
258
252 def reposetup(ui, repo):
259 def reposetup(ui, repo):
253 uisetup(repo.ui)
260 uisetup(repo.ui)
254 #print "reposetup for", repo.root
261 #print "reposetup for", repo.root
255
262
256 if not repo.local():
263 if not repo.local():
257 return
264 return
258 for name, fn in filters.iteritems():
265 for name, fn in filters.iteritems():
259 repo.adddatafilter(name, fn)
266 repo.adddatafilter(name, fn)
260
267
261 ui.setconfig('patch', 'eol', 'auto')
268 ui.setconfig('patch', 'eol', 'auto')
262
269
263 class eolrepo(repo.__class__):
270 class eolrepo(repo.__class__):
264
271
265 def loadeol(self, nodes):
272 def loadeol(self, nodes):
266 eol = parseeol(self.ui, self, nodes)
273 eol = parseeol(self.ui, self, nodes)
267 if eol is None:
274 if eol is None:
268 return None
275 return None
269 eol.setfilters(self.ui)
276 eol.setfilters(self.ui)
270 return eol.match
277 return eol.match
271
278
272 def _hgcleardirstate(self):
279 def _hgcleardirstate(self):
273 self._eolfile = self.loadeol([None, 'tip'])
280 self._eolfile = self.loadeol([None, 'tip'])
274 if not self._eolfile:
281 if not self._eolfile:
275 self._eolfile = util.never
282 self._eolfile = util.never
276 return
283 return
277
284
278 try:
285 try:
279 cachemtime = os.path.getmtime(self.join("eol.cache"))
286 cachemtime = os.path.getmtime(self.join("eol.cache"))
280 except OSError:
287 except OSError:
281 cachemtime = 0
288 cachemtime = 0
282
289
283 try:
290 try:
284 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
291 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
285 except OSError:
292 except OSError:
286 eolmtime = 0
293 eolmtime = 0
287
294
288 if eolmtime > cachemtime:
295 if eolmtime > cachemtime:
289 ui.debug("eol: detected change in .hgeol\n")
296 ui.debug("eol: detected change in .hgeol\n")
290 wlock = None
297 wlock = None
291 try:
298 try:
292 wlock = self.wlock()
299 wlock = self.wlock()
293 for f in self.dirstate:
300 for f in self.dirstate:
294 if self.dirstate[f] == 'n':
301 if self.dirstate[f] == 'n':
295 # all normal files need to be looked at
302 # all normal files need to be looked at
296 # again since the new .hgeol file might no
303 # again since the new .hgeol file might no
297 # longer match a file it matched before
304 # longer match a file it matched before
298 self.dirstate.normallookup(f)
305 self.dirstate.normallookup(f)
299 # Touch the cache to update mtime.
306 # Touch the cache to update mtime.
300 self.opener("eol.cache", "w").close()
307 self.opener("eol.cache", "w").close()
301 wlock.release()
308 wlock.release()
302 except error.LockUnavailable:
309 except error.LockUnavailable:
303 # If we cannot lock the repository and clear the
310 # If we cannot lock the repository and clear the
304 # dirstate, then a commit might not see all files
311 # dirstate, then a commit might not see all files
305 # as modified. But if we cannot lock the
312 # as modified. But if we cannot lock the
306 # repository, then we can also not make a commit,
313 # repository, then we can also not make a commit,
307 # so ignore the error.
314 # so ignore the error.
308 pass
315 pass
309
316
310 def commitctx(self, ctx, error=False):
317 def commitctx(self, ctx, error=False):
311 for f in sorted(ctx.added() + ctx.modified()):
318 for f in sorted(ctx.added() + ctx.modified()):
312 if not self._eolfile(f):
319 if not self._eolfile(f):
313 continue
320 continue
314 data = ctx[f].data()
321 data = ctx[f].data()
315 if util.binary(data):
322 if util.binary(data):
316 # We should not abort here, since the user should
323 # We should not abort here, since the user should
317 # be able to say "** = native" to automatically
324 # be able to say "** = native" to automatically
318 # have all non-binary files taken care of.
325 # have all non-binary files taken care of.
319 continue
326 continue
320 if inconsistenteol(data):
327 if inconsistenteol(data):
321 raise util.Abort(_("inconsistent newline style "
328 raise util.Abort(_("inconsistent newline style "
322 "in %s\n" % f))
329 "in %s\n" % f))
323 return super(eolrepo, self).commitctx(ctx, error)
330 return super(eolrepo, self).commitctx(ctx, error)
324 repo.__class__ = eolrepo
331 repo.__class__ = eolrepo
325 repo._hgcleardirstate()
332 repo._hgcleardirstate()
@@ -1,184 +1,217 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: a.txt should not have CRLF line endings
43 error: pretxnchangegroup hook failed: end-of-line check failed:
44 a.txt in a8ee6548cd86 should not have CRLF line endings
44 transaction abort!
45 transaction abort!
45 rollback completed
46 rollback completed
46 abort: a.txt should not have CRLF line endings
47 abort: end-of-line check failed:
48 a.txt in a8ee6548cd86 should not have CRLF line endings
47 [255]
49 [255]
48
50
49 $ printf "first\nsecond\nthird\n" > a.txt
51 $ printf "first\nsecond\nthird\n" > a.txt
50 $ hg commit -m 'LF a.txt (fixed)'
52 $ hg commit -m 'LF a.txt (fixed)'
51 $ hg push ../main
53 $ hg push ../main
52 pushing to ../main
54 pushing to ../main
53 searching for changes
55 searching for changes
54 adding changesets
56 adding changesets
55 adding manifests
57 adding manifests
56 adding file changes
58 adding file changes
57 added 2 changesets with 2 changes to 1 files
59 added 2 changesets with 2 changes to 1 files
58
60
59 $ printf "first\nsecond\nthird\n" > crlf.txt
61 $ printf "first\nsecond\nthird\n" > crlf.txt
60 $ hg add crlf.txt
62 $ hg add crlf.txt
61 $ hg commit -m 'LF crlf.txt'
63 $ hg commit -m 'LF crlf.txt'
62 $ hg push ../main
64 $ hg push ../main
63 pushing to ../main
65 pushing to ../main
64 searching for changes
66 searching for changes
65 adding changesets
67 adding changesets
66 adding manifests
68 adding manifests
67 adding file changes
69 adding file changes
68 added 1 changesets with 1 changes to 1 files
70 added 1 changesets with 1 changes to 1 files
69 error: pretxnchangegroup hook failed: crlf.txt should not have LF line endings
71 error: pretxnchangegroup hook failed: end-of-line check failed:
72 crlf.txt in 004ba2132725 should not have LF line endings
70 transaction abort!
73 transaction abort!
71 rollback completed
74 rollback completed
72 abort: crlf.txt should not have LF line endings
75 abort: end-of-line check failed:
76 crlf.txt in 004ba2132725 should not have LF line endings
73 [255]
77 [255]
74
78
75 $ printf "first\r\nsecond\r\nthird\r\n" > crlf.txt
79 $ printf "first\r\nsecond\r\nthird\r\n" > crlf.txt
76 $ hg commit -m 'CRLF crlf.txt (fixed)'
80 $ hg commit -m 'CRLF crlf.txt (fixed)'
77 $ hg push ../main
81 $ hg push ../main
78 pushing to ../main
82 pushing to ../main
79 searching for changes
83 searching for changes
80 adding changesets
84 adding changesets
81 adding manifests
85 adding manifests
82 adding file changes
86 adding file changes
83 added 2 changesets with 2 changes to 1 files
87 added 2 changesets with 2 changes to 1 files
84
88
85 $ printf "first\r\nsecond" > b.txt
89 $ printf "first\r\nsecond" > b.txt
86 $ hg add b.txt
90 $ hg add b.txt
87 $ hg commit -m 'CRLF b.txt'
91 $ hg commit -m 'CRLF b.txt'
88 $ hg push ../main
92 $ hg push ../main
89 pushing to ../main
93 pushing to ../main
90 searching for changes
94 searching for changes
91 adding changesets
95 adding changesets
92 adding manifests
96 adding manifests
93 adding file changes
97 adding file changes
94 added 1 changesets with 1 changes to 1 files
98 added 1 changesets with 1 changes to 1 files
95 error: pretxnchangegroup hook failed: b.txt should not have CRLF line endings
99 error: pretxnchangegroup hook failed: end-of-line check failed:
100 b.txt in fbcf9b1025f5 should not have CRLF line endings
96 transaction abort!
101 transaction abort!
97 rollback completed
102 rollback completed
98 abort: b.txt should not have CRLF line endings
103 abort: end-of-line check failed:
104 b.txt in fbcf9b1025f5 should not have CRLF line endings
99 [255]
105 [255]
100
106
101 $ hg up -r -2
107 $ hg up -r -2
102 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
103 $ printf "some\nother\nfile" > c.txt
109 $ printf "some\nother\nfile" > c.txt
104 $ hg add c.txt
110 $ hg add c.txt
105 $ 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"
106 created new head
112 created new head
107 $ hg push -f ../main
113 $ hg push -f ../main
108 pushing to ../main
114 pushing to ../main
109 searching for changes
115 searching for changes
110 adding changesets
116 adding changesets
111 adding manifests
117 adding manifests
112 adding file changes
118 adding file changes
113 added 2 changesets with 2 changes to 2 files (+1 heads)
119 added 2 changesets with 2 changes to 2 files (+1 heads)
114 error: pretxnchangegroup hook failed: b.txt should not have CRLF line endings
120 error: pretxnchangegroup hook failed: end-of-line check failed:
121 b.txt in fbcf9b1025f5 should not have CRLF line endings
115 transaction abort!
122 transaction abort!
116 rollback completed
123 rollback completed
117 abort: b.txt should not have CRLF line endings
124 abort: end-of-line check failed:
125 b.txt in fbcf9b1025f5 should not have CRLF line endings
118 [255]
126 [255]
119
127
120 Test checkheadshook alias
128 Test checkheadshook alias
121
129
122 $ cat > ../main/.hg/hgrc <<EOF
130 $ cat > ../main/.hg/hgrc <<EOF
123 > [hooks]
131 > [hooks]
124 > pretxnchangegroup = python:hgext.eol.checkheadshook
132 > pretxnchangegroup = python:hgext.eol.checkheadshook
125 > EOF
133 > EOF
126 $ hg push -f ../main
134 $ hg push -f ../main
127 pushing to ../main
135 pushing to ../main
128 searching for changes
136 searching for changes
129 adding changesets
137 adding changesets
130 adding manifests
138 adding manifests
131 adding file changes
139 adding file changes
132 added 2 changesets with 2 changes to 2 files (+1 heads)
140 added 2 changesets with 2 changes to 2 files (+1 heads)
133 error: pretxnchangegroup hook failed: b.txt should not have CRLF line endings
141 error: pretxnchangegroup hook failed: end-of-line check failed:
142 b.txt in fbcf9b1025f5 should not have CRLF line endings
134 transaction abort!
143 transaction abort!
135 rollback completed
144 rollback completed
136 abort: b.txt should not have CRLF line endings
145 abort: end-of-line check failed:
146 b.txt in fbcf9b1025f5 should not have CRLF line endings
137 [255]
147 [255]
138
148
139 We can fix the head and push again
149 We can fix the head and push again
140
150
141 $ hg up 6
151 $ hg up 6
142 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
143 $ printf "first\nsecond" > b.txt
153 $ printf "first\nsecond" > b.txt
144 $ hg ci -m "remove CRLF from b.txt"
154 $ hg ci -m "remove CRLF from b.txt"
145 $ hg push -f ../main
155 $ hg push -f ../main
146 pushing to ../main
156 pushing to ../main
147 searching for changes
157 searching for changes
148 adding changesets
158 adding changesets
149 adding manifests
159 adding manifests
150 adding file changes
160 adding file changes
151 added 3 changesets with 3 changes to 2 files (+1 heads)
161 added 3 changesets with 3 changes to 2 files (+1 heads)
152 $ hg -R ../main rollback
162 $ hg -R ../main rollback
153 repository tip rolled back to revision 5 (undo push)
163 repository tip rolled back to revision 5 (undo push)
154 working directory now based on revision -1
164 working directory now based on revision -1
155
165
156 Test it still fails with checkallhook
166 Test it still fails with checkallhook
157
167
158 $ cat > ../main/.hg/hgrc <<EOF
168 $ cat > ../main/.hg/hgrc <<EOF
159 > [hooks]
169 > [hooks]
160 > pretxnchangegroup = python:hgext.eol.checkallhook
170 > pretxnchangegroup = python:hgext.eol.checkallhook
161 > EOF
171 > EOF
162 $ hg push -f ../main
172 $ hg push -f ../main
163 pushing to ../main
173 pushing to ../main
164 searching for changes
174 searching for changes
165 adding changesets
175 adding changesets
166 adding manifests
176 adding manifests
167 adding file changes
177 adding file changes
168 added 3 changesets with 3 changes to 2 files (+1 heads)
178 added 3 changesets with 3 changes to 2 files (+1 heads)
169 error: pretxnchangegroup hook failed: b.txt should not have CRLF line endings
179 error: pretxnchangegroup hook failed: end-of-line check failed:
180 b.txt in fbcf9b1025f5 should not have CRLF line endings
170 transaction abort!
181 transaction abort!
171 rollback completed
182 rollback completed
172 abort: b.txt should not have CRLF line endings
183 abort: end-of-line check failed:
184 b.txt in fbcf9b1025f5 should not have CRLF line endings
173 [255]
185 [255]
174
186
175 But we can push the clean head
187 But we can push the clean head
176
188
177 $ hg push -r7 -f ../main
189 $ hg push -r7 -f ../main
178 pushing to ../main
190 pushing to ../main
179 searching for changes
191 searching for changes
180 adding changesets
192 adding changesets
181 adding manifests
193 adding manifests
182 adding file changes
194 adding file changes
183 added 1 changesets with 1 changes to 1 files
195 added 1 changesets with 1 changes to 1 files
184
196
197 Test multiple files/revisions output
198
199 $ printf "another\r\nbad\r\none" > d.txt
200 $ hg add d.txt
201 $ hg ci -m "add d.txt"
202 $ hg push -f ../main
203 pushing to ../main
204 searching for changes
205 adding changesets
206 adding manifests
207 adding file changes
208 added 3 changesets with 3 changes to 2 files (+1 heads)
209 error: pretxnchangegroup hook failed: end-of-line check failed:
210 d.txt in a7040e68714f should not have CRLF line endings
211 b.txt in fbcf9b1025f5 should not have CRLF line endings
212 transaction abort!
213 rollback completed
214 abort: end-of-line check failed:
215 d.txt in a7040e68714f should not have CRLF line endings
216 b.txt in fbcf9b1025f5 should not have CRLF line endings
217 [255]
General Comments 0
You need to be logged in to leave comments. Login now