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 short |
49 short, |
|
50 ) |
|
51 from mercurial import ( |
49 from mercurial import ( |
52 pycompat, |
50 pycompat, |
53 registrar, |
51 registrar, |
54 ) |
52 ) |
55 from mercurial.utils import ( |
53 from mercurial.utils import stringutil |
56 stringutil, |
|
57 ) |
|
58 |
54 |
59 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
55 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
60 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
56 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
61 # be specifying the version(s) of Mercurial they are tested with, or |
57 # be specifying the version(s) of Mercurial they are tested with, or |
62 # leave the attribute unspecified. |
58 # leave the attribute unspecified. |
63 testedwith = 'ships-with-hg-core' |
59 testedwith = 'ships-with-hg-core' |
64 |
60 |
65 configtable = {} |
61 configtable = {} |
66 configitem = registrar.configitem(configtable) |
62 configitem = registrar.configitem(configtable) |
67 |
63 |
68 configitem('win32text', 'warn', |
64 configitem( |
69 default=True, |
65 'win32text', 'warn', default=True, |
70 ) |
66 ) |
71 |
67 |
72 # regexp for single LF without CR preceding. |
68 # regexp for single LF without CR preceding. |
73 re_single_lf = re.compile('(^|[^\r])\n', re.MULTILINE) |
69 re_single_lf = re.compile('(^|[^\r])\n', re.MULTILINE) |
74 |
70 |
75 newlinestr = {'\r\n': 'CRLF', '\r': 'CR'} |
71 newlinestr = {'\r\n': 'CRLF', '\r': 'CR'} |
76 filterstr = {'\r\n': 'clever', '\r': 'mac'} |
72 filterstr = {'\r\n': 'clever', '\r': 'mac'} |
|
73 |
77 |
74 |
78 def checknewline(s, newline, ui=None, repo=None, filename=None): |
75 def checknewline(s, newline, ui=None, repo=None, filename=None): |
79 # warn if already has 'newline' in repository. |
76 # warn if already has 'newline' in repository. |
80 # it might cause unexpected eol conversion. |
77 # it might cause unexpected eol conversion. |
81 # see issue 302: |
78 # see issue 302: |
82 # https://bz.mercurial-scm.org/302 |
79 # https://bz.mercurial-scm.org/302 |
83 if newline in s and ui and filename and repo: |
80 if newline in s and ui and filename and repo: |
84 ui.warn(_('WARNING: %s already has %s line endings\n' |
81 ui.warn( |
85 'and does not need EOL conversion by the win32text plugin.\n' |
82 _( |
86 'Before your next commit, please reconsider your ' |
83 'WARNING: %s already has %s line endings\n' |
87 'encode/decode settings in \nMercurial.ini or %s.\n') % |
84 'and does not need EOL conversion by the win32text plugin.\n' |
88 (filename, newlinestr[newline], repo.vfs.join('hgrc'))) |
85 'Before your next commit, please reconsider your ' |
|
86 'encode/decode settings in \nMercurial.ini or %s.\n' |
|
87 ) |
|
88 % (filename, newlinestr[newline], repo.vfs.join('hgrc')) |
|
89 ) |
|
90 |
89 |
91 |
90 def dumbdecode(s, cmd, **kwargs): |
92 def dumbdecode(s, cmd, **kwargs): |
91 checknewline(s, '\r\n', **kwargs) |
93 checknewline(s, '\r\n', **kwargs) |
92 # replace single LF to CRLF |
94 # replace single LF to CRLF |
93 return re_single_lf.sub('\\1\r\n', s) |
95 return re_single_lf.sub('\\1\r\n', s) |
94 |
96 |
|
97 |
95 def dumbencode(s, cmd): |
98 def dumbencode(s, cmd): |
96 return s.replace('\r\n', '\n') |
99 return s.replace('\r\n', '\n') |
|
100 |
97 |
101 |
98 def macdumbdecode(s, cmd, **kwargs): |
102 def macdumbdecode(s, cmd, **kwargs): |
99 checknewline(s, '\r', **kwargs) |
103 checknewline(s, '\r', **kwargs) |
100 return s.replace('\n', '\r') |
104 return s.replace('\n', '\r') |
101 |
105 |
|
106 |
102 def macdumbencode(s, cmd): |
107 def macdumbencode(s, cmd): |
103 return s.replace('\r', '\n') |
108 return s.replace('\r', '\n') |
104 |
109 |
|
110 |
105 def cleverdecode(s, cmd, **kwargs): |
111 def cleverdecode(s, cmd, **kwargs): |
106 if not stringutil.binary(s): |
112 if not stringutil.binary(s): |
107 return dumbdecode(s, cmd, **kwargs) |
113 return dumbdecode(s, cmd, **kwargs) |
108 return s |
114 return s |
109 |
115 |
|
116 |
110 def cleverencode(s, cmd): |
117 def cleverencode(s, cmd): |
111 if not stringutil.binary(s): |
118 if not stringutil.binary(s): |
112 return dumbencode(s, cmd) |
119 return dumbencode(s, cmd) |
113 return s |
120 return s |
114 |
121 |
|
122 |
115 def macdecode(s, cmd, **kwargs): |
123 def macdecode(s, cmd, **kwargs): |
116 if not stringutil.binary(s): |
124 if not stringutil.binary(s): |
117 return macdumbdecode(s, cmd, **kwargs) |
125 return macdumbdecode(s, cmd, **kwargs) |
118 return s |
126 return s |
119 |
127 |
|
128 |
120 def macencode(s, cmd): |
129 def macencode(s, cmd): |
121 if not stringutil.binary(s): |
130 if not stringutil.binary(s): |
122 return macdumbencode(s, cmd) |
131 return macdumbencode(s, cmd) |
123 return s |
132 return s |
|
133 |
124 |
134 |
125 _filters = { |
135 _filters = { |
126 'dumbdecode:': dumbdecode, |
136 'dumbdecode:': dumbdecode, |
127 'dumbencode:': dumbencode, |
137 'dumbencode:': dumbencode, |
128 'cleverdecode:': cleverdecode, |
138 'cleverdecode:': cleverdecode, |
129 'cleverencode:': cleverencode, |
139 'cleverencode:': cleverencode, |
130 'macdumbdecode:': macdumbdecode, |
140 'macdumbdecode:': macdumbdecode, |
131 'macdumbencode:': macdumbencode, |
141 'macdumbencode:': macdumbencode, |
132 'macdecode:': macdecode, |
142 'macdecode:': macdecode, |
133 'macencode:': macencode, |
143 'macencode:': macencode, |
134 } |
144 } |
|
145 |
135 |
146 |
136 def forbidnewline(ui, repo, hooktype, node, newline, **kwargs): |
147 def forbidnewline(ui, repo, hooktype, node, newline, **kwargs): |
137 halt = False |
148 halt = False |
138 seen = set() |
149 seen = set() |
139 # we try to walk changesets in reverse order from newest to |
150 # we try to walk changesets in reverse order from newest to |
140 # oldest, so that if we see a file multiple times, we take the |
151 # oldest, so that if we see a file multiple times, we take the |
141 # newest version as canonical. this prevents us from blocking a |
152 # newest version as canonical. this prevents us from blocking a |
142 # changegroup that contains an unacceptable commit followed later |
153 # changegroup that contains an unacceptable commit followed later |
143 # by a commit that fixes the problem. |
154 # by a commit that fixes the problem. |
144 tip = repo['tip'] |
155 tip = repo['tip'] |
145 for rev in pycompat.xrange(repo.changelog.tiprev(), |
156 for rev in pycompat.xrange( |
146 repo[node].rev() - 1, -1): |
157 repo.changelog.tiprev(), repo[node].rev() - 1, -1 |
|
158 ): |
147 c = repo[rev] |
159 c = repo[rev] |
148 for f in c.files(): |
160 for f in c.files(): |
149 if f in seen or f not in tip or f not in c: |
161 if f in seen or f not in tip or f not in c: |
150 continue |
162 continue |
151 seen.add(f) |
163 seen.add(f) |
152 data = c[f].data() |
164 data = c[f].data() |
153 if not stringutil.binary(data) and newline in data: |
165 if not stringutil.binary(data) and newline in data: |
154 if not halt: |
166 if not halt: |
155 ui.warn(_('attempt to commit or push text file(s) ' |
167 ui.warn( |
156 'using %s line endings\n') % |
168 _( |
157 newlinestr[newline]) |
169 'attempt to commit or push text file(s) ' |
|
170 'using %s line endings\n' |
|
171 ) |
|
172 % newlinestr[newline] |
|
173 ) |
158 ui.warn(_('in %s: %s\n') % (short(c.node()), f)) |
174 ui.warn(_('in %s: %s\n') % (short(c.node()), f)) |
159 halt = True |
175 halt = True |
160 if halt and hooktype == 'pretxnchangegroup': |
176 if halt and hooktype == 'pretxnchangegroup': |
161 crlf = newlinestr[newline].lower() |
177 crlf = newlinestr[newline].lower() |
162 filter = filterstr[newline] |
178 filter = filterstr[newline] |
163 ui.warn(_('\nTo prevent this mistake in your local repository,\n' |
179 ui.warn( |
164 'add to Mercurial.ini or .hg/hgrc:\n' |
180 _( |
165 '\n' |
181 '\nTo prevent this mistake in your local repository,\n' |
166 '[hooks]\n' |
182 'add to Mercurial.ini or .hg/hgrc:\n' |
167 'pretxncommit.%s = python:hgext.win32text.forbid%s\n' |
183 '\n' |
168 '\n' |
184 '[hooks]\n' |
169 'and also consider adding:\n' |
185 'pretxncommit.%s = python:hgext.win32text.forbid%s\n' |
170 '\n' |
186 '\n' |
171 '[extensions]\n' |
187 'and also consider adding:\n' |
172 'win32text =\n' |
188 '\n' |
173 '[encode]\n' |
189 '[extensions]\n' |
174 '** = %sencode:\n' |
190 'win32text =\n' |
175 '[decode]\n' |
191 '[encode]\n' |
176 '** = %sdecode:\n') % (crlf, crlf, filter, filter)) |
192 '** = %sencode:\n' |
|
193 '[decode]\n' |
|
194 '** = %sdecode:\n' |
|
195 ) |
|
196 % (crlf, crlf, filter, filter) |
|
197 ) |
177 return halt |
198 return halt |
|
199 |
178 |
200 |
179 def forbidcrlf(ui, repo, hooktype, node, **kwargs): |
201 def forbidcrlf(ui, repo, hooktype, node, **kwargs): |
180 return forbidnewline(ui, repo, hooktype, node, '\r\n', **kwargs) |
202 return forbidnewline(ui, repo, hooktype, node, '\r\n', **kwargs) |
181 |
203 |
|
204 |
182 def forbidcr(ui, repo, hooktype, node, **kwargs): |
205 def forbidcr(ui, repo, hooktype, node, **kwargs): |
183 return forbidnewline(ui, repo, hooktype, node, '\r', **kwargs) |
206 return forbidnewline(ui, repo, hooktype, node, '\r', **kwargs) |
|
207 |
184 |
208 |
185 def reposetup(ui, repo): |
209 def reposetup(ui, repo): |
186 if not repo.local(): |
210 if not repo.local(): |
187 return |
211 return |
188 for name, fn in _filters.iteritems(): |
212 for name, fn in _filters.iteritems(): |
189 repo.adddatafilter(name, fn) |
213 repo.adddatafilter(name, fn) |
190 |
214 |
|
215 |
191 def extsetup(ui): |
216 def extsetup(ui): |
192 # deprecated config: win32text.warn |
217 # deprecated config: win32text.warn |
193 if ui.configbool('win32text', 'warn'): |
218 if ui.configbool('win32text', 'warn'): |
194 ui.warn(_("win32text is deprecated: " |
219 ui.warn( |
195 "https://mercurial-scm.org/wiki/Win32TextExtension\n")) |
220 _( |
|
221 "win32text is deprecated: " |
|
222 "https://mercurial-scm.org/wiki/Win32TextExtension\n" |
|
223 ) |
|
224 ) |