##// END OF EJS Templates
eol: fix win32text encode/decode filter names
Martin Geisler -
r12979:733345a1 default
parent child Browse files
Show More
@@ -1,264 +1,269 b''
1 1 """automatically manage newlines in repository files
2 2
3 3 This extension allows you to manage the type of line endings (CRLF or
4 4 LF) that are used in the repository and in the local working
5 5 directory. That way you can get CRLF line endings on Windows and LF on
6 6 Unix/Mac, thereby letting everybody use their OS native line endings.
7 7
8 8 The extension reads its configuration from a versioned ``.hgeol``
9 9 configuration file every time you run an ``hg`` command. The
10 10 ``.hgeol`` file use the same syntax as all other Mercurial
11 11 configuration files. It uses two sections, ``[patterns]`` and
12 12 ``[repository]``.
13 13
14 14 The ``[patterns]`` section specifies the line endings used in the
15 15 working directory. The format is specified by a file pattern. The
16 16 first match is used, so put more specific patterns first. The
17 17 available line endings are ``LF``, ``CRLF``, and ``BIN``.
18 18
19 19 Files with the declared format of ``CRLF`` or ``LF`` are always
20 20 checked out in that format and files declared to be binary (``BIN``)
21 21 are left unchanged. Additionally, ``native`` is an alias for the
22 22 platform's default line ending: ``LF`` on Unix (including Mac OS X)
23 23 and ``CRLF`` on Windows. Note that ``BIN`` (do nothing to line
24 24 endings) is Mercurial's default behaviour; it is only needed if you
25 25 need to override a later, more general pattern.
26 26
27 27 The optional ``[repository]`` section specifies the line endings to
28 28 use for files stored in the repository. It has a single setting,
29 29 ``native``, which determines the storage line endings for files
30 30 declared as ``native`` in the ``[patterns]`` section. It can be set to
31 31 ``LF`` or ``CRLF``. The default is ``LF``. For example, this means
32 32 that on Windows, files configured as ``native`` (``CRLF`` by default)
33 33 will be converted to ``LF`` when stored in the repository. Files
34 34 declared as ``LF``, ``CRLF``, or ``BIN`` in the ``[patterns]`` section
35 35 are always stored as-is in the repository.
36 36
37 37 Example versioned ``.hgeol`` file::
38 38
39 39 [patterns]
40 40 **.py = native
41 41 **.vcproj = CRLF
42 42 **.txt = native
43 43 Makefile = LF
44 44 **.jpg = BIN
45 45
46 46 [repository]
47 47 native = LF
48 48
49 49 The extension uses an optional ``[eol]`` section in your hgrc file
50 50 (not the ``.hgeol`` file) for settings that control the overall
51 51 behavior. There are two settings:
52 52
53 53 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
54 54 ``CRLF`` to override the default interpretation of ``native`` for
55 55 checkout. This can be used with :hg:`archive` on Unix, say, to
56 56 generate an archive where files have line endings for Windows.
57 57
58 58 - ``eol.only-consistent`` (default True) can be set to False to make
59 59 the extension convert files with inconsistent EOLs. Inconsistent
60 60 means that there is both ``CRLF`` and ``LF`` present in the file.
61 61 Such files are normally not touched under the assumption that they
62 62 have mixed EOLs on purpose.
63 63
64 The extension provides ``cleverencode:`` and ``cleverdecode:`` filters
65 like the deprecated win32text extension does. This means that you can
66 disable win32text and enable eol and your filters will still work. You
67 only need to these filters until you have prepared a ``.hgeol`` file.
68
64 69 See :hg:`help patterns` for more information about the glob patterns
65 70 used.
66 71 """
67 72
68 73 from mercurial.i18n import _
69 74 from mercurial import util, config, extensions, match
70 75 import re, os
71 76
72 77 # Matches a lone LF, i.e., one that is not part of CRLF.
73 78 singlelf = re.compile('(^|[^\r])\n')
74 79 # Matches a single EOL which can either be a CRLF where repeated CR
75 80 # are removed or a LF. We do not care about old Machintosh files, so a
76 81 # stray CR is an error.
77 82 eolre = re.compile('\r*\n')
78 83
79 84
80 85 def inconsistenteol(data):
81 86 return '\r\n' in data and singlelf.search(data)
82 87
83 88 def tolf(s, params, ui, **kwargs):
84 89 """Filter to convert to LF EOLs."""
85 90 if util.binary(s):
86 91 return s
87 92 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
88 93 return s
89 94 return eolre.sub('\n', s)
90 95
91 96 def tocrlf(s, params, ui, **kwargs):
92 97 """Filter to convert to CRLF EOLs."""
93 98 if util.binary(s):
94 99 return s
95 100 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
96 101 return s
97 102 return eolre.sub('\r\n', s)
98 103
99 104 def isbinary(s, params):
100 105 """Filter to do nothing with the file."""
101 106 return s
102 107
103 108 filters = {
104 109 'to-lf': tolf,
105 110 'to-crlf': tocrlf,
106 111 'is-binary': isbinary,
107 112 # The following provide backwards compatibility with win32text
108 'cleverencode': tolf,
109 'cleverdecode': tocrlf
113 'cleverencode:': tolf,
114 'cleverdecode:': tocrlf
110 115 }
111 116
112 117
113 118 def hook(ui, repo, node, hooktype, **kwargs):
114 119 """verify that files have expected EOLs"""
115 120 files = set()
116 121 for rev in xrange(repo[node].rev(), len(repo)):
117 122 files.update(repo[rev].files())
118 123 tip = repo['tip']
119 124 for f in files:
120 125 if f not in tip:
121 126 continue
122 127 for pattern, target in ui.configitems('encode'):
123 128 if match.match(repo.root, '', [pattern])(f):
124 129 data = tip[f].data()
125 130 if target == "to-lf" and "\r\n" in data:
126 131 raise util.Abort(_("%s should not have CRLF line endings")
127 132 % f)
128 133 elif target == "to-crlf" and singlelf.search(data):
129 134 raise util.Abort(_("%s should not have LF line endings")
130 135 % f)
131 136
132 137
133 138 def preupdate(ui, repo, hooktype, parent1, parent2):
134 139 #print "preupdate for %s: %s -> %s" % (repo.root, parent1, parent2)
135 140 repo.readhgeol(parent1)
136 141 return False
137 142
138 143 def uisetup(ui):
139 144 ui.setconfig('hooks', 'preupdate.eol', preupdate)
140 145
141 146 def extsetup(ui):
142 147 try:
143 148 extensions.find('win32text')
144 149 raise util.Abort(_("the eol extension is incompatible with the "
145 150 "win32text extension"))
146 151 except KeyError:
147 152 pass
148 153
149 154
150 155 def reposetup(ui, repo):
151 156 uisetup(repo.ui)
152 157 #print "reposetup for", repo.root
153 158
154 159 if not repo.local():
155 160 return
156 161 for name, fn in filters.iteritems():
157 162 repo.adddatafilter(name, fn)
158 163
159 164 ui.setconfig('patch', 'eol', 'auto')
160 165
161 166 class eolrepo(repo.__class__):
162 167
163 168 _decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
164 169 _encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
165 170
166 171 def readhgeol(self, node=None, data=None):
167 172 if data is None:
168 173 try:
169 174 if node is None:
170 175 data = self.wfile('.hgeol').read()
171 176 else:
172 177 data = self[node]['.hgeol'].data()
173 178 except (IOError, LookupError):
174 179 return None
175 180
176 181 if self.ui.config('eol', 'native', os.linesep) in ('LF', '\n'):
177 182 self._decode['NATIVE'] = 'to-lf'
178 183 else:
179 184 self._decode['NATIVE'] = 'to-crlf'
180 185
181 186 eol = config.config()
182 187 # Our files should not be touched. The pattern must be
183 188 # inserted first override a '** = native' pattern.
184 189 eol.set('patterns', '.hg*', 'BIN')
185 190 # We can then parse the user's patterns.
186 191 eol.parse('.hgeol', data)
187 192
188 193 if eol.get('repository', 'native') == 'CRLF':
189 194 self._encode['NATIVE'] = 'to-crlf'
190 195 else:
191 196 self._encode['NATIVE'] = 'to-lf'
192 197
193 198 for pattern, style in eol.items('patterns'):
194 199 key = style.upper()
195 200 try:
196 201 self.ui.setconfig('decode', pattern, self._decode[key])
197 202 self.ui.setconfig('encode', pattern, self._encode[key])
198 203 except KeyError:
199 204 self.ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
200 205 % (style, eol.source('patterns', pattern)))
201 206
202 207 include = []
203 208 exclude = []
204 209 for pattern, style in eol.items('patterns'):
205 210 key = style.upper()
206 211 if key == 'BIN':
207 212 exclude.append(pattern)
208 213 else:
209 214 include.append(pattern)
210 215
211 216 # This will match the files for which we need to care
212 217 # about inconsistent newlines.
213 218 return match.match(self.root, '', [], include, exclude)
214 219
215 220 def _hgcleardirstate(self):
216 221 self._eolfile = self.readhgeol() or self.readhgeol('tip')
217 222
218 223 if not self._eolfile:
219 224 self._eolfile = util.never
220 225 return
221 226
222 227 try:
223 228 cachemtime = os.path.getmtime(self.join("eol.cache"))
224 229 except OSError:
225 230 cachemtime = 0
226 231
227 232 try:
228 233 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
229 234 except OSError:
230 235 eolmtime = 0
231 236
232 237 if eolmtime > cachemtime:
233 238 ui.debug("eol: detected change in .hgeol\n")
234 239 # TODO: we could introduce a method for this in dirstate.
235 240 wlock = None
236 241 try:
237 242 wlock = self.wlock()
238 243 for f, e in self.dirstate._map.iteritems():
239 244 self.dirstate._map[f] = (e[0], e[1], -1, 0)
240 245 self.dirstate._dirty = True
241 246 # Touch the cache to update mtime. TODO: are we sure this
242 247 # always enought to update the mtime, or should we write a
243 248 # bit to the file?
244 249 self.opener("eol.cache", "w").close()
245 250 finally:
246 251 if wlock is not None:
247 252 wlock.release()
248 253
249 254 def commitctx(self, ctx, error=False):
250 255 for f in sorted(ctx.added() + ctx.modified()):
251 256 if not self._eolfile(f):
252 257 continue
253 258 data = ctx[f].data()
254 259 if util.binary(data):
255 260 # We should not abort here, since the user should
256 261 # be able to say "** = native" to automatically
257 262 # have all non-binary files taken care of.
258 263 continue
259 264 if inconsistenteol(data):
260 265 raise util.Abort(_("inconsistent newline style "
261 266 "in %s\n" % f))
262 267 return super(eolrepo, self).commitctx(ctx, error)
263 268 repo.__class__ = eolrepo
264 269 repo._hgcleardirstate()
General Comments 0
You need to be logged in to leave comments. Login now