##// END OF EJS Templates
win32text: use 'tiprev' when appropriate...
Boris Feld -
r35693:01496e92 default
parent child Browse files
Show More
@@ -1,191 +1,191 b''
1 # win32text.py - LF <-> CRLF/CR translation utilities for Windows/Mac users
1 # win32text.py - LF <-> CRLF/CR translation utilities for Windows/Mac users
2 #
2 #
3 # Copyright 2005, 2007-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005, 2007-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''perform automatic newline conversion (DEPRECATED)
8 '''perform automatic newline conversion (DEPRECATED)
9
9
10 Deprecation: The win32text extension requires each user to configure
10 Deprecation: The win32text extension requires each user to configure
11 the extension again and again for each clone since the configuration
11 the extension again and again for each clone since the configuration
12 is not copied when cloning.
12 is not copied when cloning.
13
13
14 We have therefore made the ``eol`` as an alternative. The ``eol``
14 We have therefore made the ``eol`` as an alternative. The ``eol``
15 uses a version controlled file for its configuration and each clone
15 uses a version controlled file for its configuration and each clone
16 will therefore use the right settings from the start.
16 will therefore use the right settings from the start.
17
17
18 To perform automatic newline conversion, use::
18 To perform automatic newline conversion, use::
19
19
20 [extensions]
20 [extensions]
21 win32text =
21 win32text =
22 [encode]
22 [encode]
23 ** = cleverencode:
23 ** = cleverencode:
24 # or ** = macencode:
24 # or ** = macencode:
25
25
26 [decode]
26 [decode]
27 ** = cleverdecode:
27 ** = cleverdecode:
28 # or ** = macdecode:
28 # or ** = macdecode:
29
29
30 If not doing conversion, to make sure you do not commit CRLF/CR by accident::
30 If not doing conversion, to make sure you do not commit CRLF/CR by accident::
31
31
32 [hooks]
32 [hooks]
33 pretxncommit.crlf = python:hgext.win32text.forbidcrlf
33 pretxncommit.crlf = python:hgext.win32text.forbidcrlf
34 # or pretxncommit.cr = python:hgext.win32text.forbidcr
34 # or pretxncommit.cr = python:hgext.win32text.forbidcr
35
35
36 To do the same check on a server to prevent CRLF/CR from being
36 To do the same check on a server to prevent CRLF/CR from being
37 pushed or pulled::
37 pushed or pulled::
38
38
39 [hooks]
39 [hooks]
40 pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf
40 pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf
41 # or pretxnchangegroup.cr = python:hgext.win32text.forbidcr
41 # or pretxnchangegroup.cr = python:hgext.win32text.forbidcr
42 '''
42 '''
43
43
44 from __future__ import absolute_import
44 from __future__ import absolute_import
45
45
46 import re
46 import re
47 from mercurial.i18n import _
47 from mercurial.i18n import _
48 from mercurial.node import (
48 from mercurial.node import (
49 short,
49 short,
50 )
50 )
51 from mercurial import (
51 from mercurial import (
52 registrar,
52 registrar,
53 util,
53 util,
54 )
54 )
55
55
56 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
56 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
57 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
57 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
58 # be specifying the version(s) of Mercurial they are tested with, or
58 # be specifying the version(s) of Mercurial they are tested with, or
59 # leave the attribute unspecified.
59 # leave the attribute unspecified.
60 testedwith = 'ships-with-hg-core'
60 testedwith = 'ships-with-hg-core'
61
61
62 configtable = {}
62 configtable = {}
63 configitem = registrar.configitem(configtable)
63 configitem = registrar.configitem(configtable)
64
64
65 configitem('win32text', 'warn',
65 configitem('win32text', 'warn',
66 default=True,
66 default=True,
67 )
67 )
68
68
69 # regexp for single LF without CR preceding.
69 # regexp for single LF without CR preceding.
70 re_single_lf = re.compile('(^|[^\r])\n', re.MULTILINE)
70 re_single_lf = re.compile('(^|[^\r])\n', re.MULTILINE)
71
71
72 newlinestr = {'\r\n': 'CRLF', '\r': 'CR'}
72 newlinestr = {'\r\n': 'CRLF', '\r': 'CR'}
73 filterstr = {'\r\n': 'clever', '\r': 'mac'}
73 filterstr = {'\r\n': 'clever', '\r': 'mac'}
74
74
75 def checknewline(s, newline, ui=None, repo=None, filename=None):
75 def checknewline(s, newline, ui=None, repo=None, filename=None):
76 # warn if already has 'newline' in repository.
76 # warn if already has 'newline' in repository.
77 # it might cause unexpected eol conversion.
77 # it might cause unexpected eol conversion.
78 # see issue 302:
78 # see issue 302:
79 # https://bz.mercurial-scm.org/302
79 # https://bz.mercurial-scm.org/302
80 if newline in s and ui and filename and repo:
80 if newline in s and ui and filename and repo:
81 ui.warn(_('WARNING: %s already has %s line endings\n'
81 ui.warn(_('WARNING: %s already has %s line endings\n'
82 'and does not need EOL conversion by the win32text plugin.\n'
82 'and does not need EOL conversion by the win32text plugin.\n'
83 'Before your next commit, please reconsider your '
83 'Before your next commit, please reconsider your '
84 'encode/decode settings in \nMercurial.ini or %s.\n') %
84 'encode/decode settings in \nMercurial.ini or %s.\n') %
85 (filename, newlinestr[newline], repo.vfs.join('hgrc')))
85 (filename, newlinestr[newline], repo.vfs.join('hgrc')))
86
86
87 def dumbdecode(s, cmd, **kwargs):
87 def dumbdecode(s, cmd, **kwargs):
88 checknewline(s, '\r\n', **kwargs)
88 checknewline(s, '\r\n', **kwargs)
89 # replace single LF to CRLF
89 # replace single LF to CRLF
90 return re_single_lf.sub('\\1\r\n', s)
90 return re_single_lf.sub('\\1\r\n', s)
91
91
92 def dumbencode(s, cmd):
92 def dumbencode(s, cmd):
93 return s.replace('\r\n', '\n')
93 return s.replace('\r\n', '\n')
94
94
95 def macdumbdecode(s, cmd, **kwargs):
95 def macdumbdecode(s, cmd, **kwargs):
96 checknewline(s, '\r', **kwargs)
96 checknewline(s, '\r', **kwargs)
97 return s.replace('\n', '\r')
97 return s.replace('\n', '\r')
98
98
99 def macdumbencode(s, cmd):
99 def macdumbencode(s, cmd):
100 return s.replace('\r', '\n')
100 return s.replace('\r', '\n')
101
101
102 def cleverdecode(s, cmd, **kwargs):
102 def cleverdecode(s, cmd, **kwargs):
103 if not util.binary(s):
103 if not util.binary(s):
104 return dumbdecode(s, cmd, **kwargs)
104 return dumbdecode(s, cmd, **kwargs)
105 return s
105 return s
106
106
107 def cleverencode(s, cmd):
107 def cleverencode(s, cmd):
108 if not util.binary(s):
108 if not util.binary(s):
109 return dumbencode(s, cmd)
109 return dumbencode(s, cmd)
110 return s
110 return s
111
111
112 def macdecode(s, cmd, **kwargs):
112 def macdecode(s, cmd, **kwargs):
113 if not util.binary(s):
113 if not util.binary(s):
114 return macdumbdecode(s, cmd, **kwargs)
114 return macdumbdecode(s, cmd, **kwargs)
115 return s
115 return s
116
116
117 def macencode(s, cmd):
117 def macencode(s, cmd):
118 if not util.binary(s):
118 if not util.binary(s):
119 return macdumbencode(s, cmd)
119 return macdumbencode(s, cmd)
120 return s
120 return s
121
121
122 _filters = {
122 _filters = {
123 'dumbdecode:': dumbdecode,
123 'dumbdecode:': dumbdecode,
124 'dumbencode:': dumbencode,
124 'dumbencode:': dumbencode,
125 'cleverdecode:': cleverdecode,
125 'cleverdecode:': cleverdecode,
126 'cleverencode:': cleverencode,
126 'cleverencode:': cleverencode,
127 'macdumbdecode:': macdumbdecode,
127 'macdumbdecode:': macdumbdecode,
128 'macdumbencode:': macdumbencode,
128 'macdumbencode:': macdumbencode,
129 'macdecode:': macdecode,
129 'macdecode:': macdecode,
130 'macencode:': macencode,
130 'macencode:': macencode,
131 }
131 }
132
132
133 def forbidnewline(ui, repo, hooktype, node, newline, **kwargs):
133 def forbidnewline(ui, repo, hooktype, node, newline, **kwargs):
134 halt = False
134 halt = False
135 seen = set()
135 seen = set()
136 # we try to walk changesets in reverse order from newest to
136 # we try to walk changesets in reverse order from newest to
137 # oldest, so that if we see a file multiple times, we take the
137 # oldest, so that if we see a file multiple times, we take the
138 # newest version as canonical. this prevents us from blocking a
138 # newest version as canonical. this prevents us from blocking a
139 # changegroup that contains an unacceptable commit followed later
139 # changegroup that contains an unacceptable commit followed later
140 # by a commit that fixes the problem.
140 # by a commit that fixes the problem.
141 tip = repo['tip']
141 tip = repo['tip']
142 for rev in xrange(len(repo) - 1, repo[node].rev() - 1, -1):
142 for rev in xrange(repo.changelog.tiprev(), repo[node].rev() - 1, -1):
143 c = repo[rev]
143 c = repo[rev]
144 for f in c.files():
144 for f in c.files():
145 if f in seen or f not in tip or f not in c:
145 if f in seen or f not in tip or f not in c:
146 continue
146 continue
147 seen.add(f)
147 seen.add(f)
148 data = c[f].data()
148 data = c[f].data()
149 if not util.binary(data) and newline in data:
149 if not util.binary(data) and newline in data:
150 if not halt:
150 if not halt:
151 ui.warn(_('attempt to commit or push text file(s) '
151 ui.warn(_('attempt to commit or push text file(s) '
152 'using %s line endings\n') %
152 'using %s line endings\n') %
153 newlinestr[newline])
153 newlinestr[newline])
154 ui.warn(_('in %s: %s\n') % (short(c.node()), f))
154 ui.warn(_('in %s: %s\n') % (short(c.node()), f))
155 halt = True
155 halt = True
156 if halt and hooktype == 'pretxnchangegroup':
156 if halt and hooktype == 'pretxnchangegroup':
157 crlf = newlinestr[newline].lower()
157 crlf = newlinestr[newline].lower()
158 filter = filterstr[newline]
158 filter = filterstr[newline]
159 ui.warn(_('\nTo prevent this mistake in your local repository,\n'
159 ui.warn(_('\nTo prevent this mistake in your local repository,\n'
160 'add to Mercurial.ini or .hg/hgrc:\n'
160 'add to Mercurial.ini or .hg/hgrc:\n'
161 '\n'
161 '\n'
162 '[hooks]\n'
162 '[hooks]\n'
163 'pretxncommit.%s = python:hgext.win32text.forbid%s\n'
163 'pretxncommit.%s = python:hgext.win32text.forbid%s\n'
164 '\n'
164 '\n'
165 'and also consider adding:\n'
165 'and also consider adding:\n'
166 '\n'
166 '\n'
167 '[extensions]\n'
167 '[extensions]\n'
168 'win32text =\n'
168 'win32text =\n'
169 '[encode]\n'
169 '[encode]\n'
170 '** = %sencode:\n'
170 '** = %sencode:\n'
171 '[decode]\n'
171 '[decode]\n'
172 '** = %sdecode:\n') % (crlf, crlf, filter, filter))
172 '** = %sdecode:\n') % (crlf, crlf, filter, filter))
173 return halt
173 return halt
174
174
175 def forbidcrlf(ui, repo, hooktype, node, **kwargs):
175 def forbidcrlf(ui, repo, hooktype, node, **kwargs):
176 return forbidnewline(ui, repo, hooktype, node, '\r\n', **kwargs)
176 return forbidnewline(ui, repo, hooktype, node, '\r\n', **kwargs)
177
177
178 def forbidcr(ui, repo, hooktype, node, **kwargs):
178 def forbidcr(ui, repo, hooktype, node, **kwargs):
179 return forbidnewline(ui, repo, hooktype, node, '\r', **kwargs)
179 return forbidnewline(ui, repo, hooktype, node, '\r', **kwargs)
180
180
181 def reposetup(ui, repo):
181 def reposetup(ui, repo):
182 if not repo.local():
182 if not repo.local():
183 return
183 return
184 for name, fn in _filters.iteritems():
184 for name, fn in _filters.iteritems():
185 repo.adddatafilter(name, fn)
185 repo.adddatafilter(name, fn)
186
186
187 def extsetup(ui):
187 def extsetup(ui):
188 # deprecated config: win32text.warn
188 # deprecated config: win32text.warn
189 if ui.configbool('win32text', 'warn'):
189 if ui.configbool('win32text', 'warn'):
190 ui.warn(_("win32text is deprecated: "
190 ui.warn(_("win32text is deprecated: "
191 "https://mercurial-scm.org/wiki/Win32TextExtension\n"))
191 "https://mercurial-scm.org/wiki/Win32TextExtension\n"))
General Comments 0
You need to be logged in to leave comments. Login now