##// END OF EJS Templates
win32text: Add macencode/macdecode
OHASHI Hideya -
r6481:e837dded default
parent child Browse files
Show More
@@ -0,0 +1,115
1 #!/bin/sh
2
3 cat > unix2mac.py <<EOF
4 import sys
5
6 for path in sys.argv[1:]:
7 data = file(path, 'rb').read()
8 data = data.replace('\n', '\r')
9 file(path, 'wb').write(data)
10 EOF
11
12 cat > print.py <<EOF
13 import sys
14 print(sys.stdin.read().replace('\n', '<LF>').replace('\r', '<CR>').replace('\0', '<NUL>'))
15 EOF
16
17 hg init
18 echo '[hooks]' >> .hg/hgrc
19 echo 'pretxncommit.cr = python:hgext.win32text.forbidcr' >> .hg/hgrc
20 echo 'pretxnchangegroup.cr = python:hgext.win32text.forbidcr' >> .hg/hgrc
21 cat .hg/hgrc
22 echo
23
24 echo hello > f
25 hg add f
26 hg ci -m 1 -d'0 0'
27 echo
28
29 python unix2mac.py f
30 hg ci -m 2 -d'0 0'
31 hg revert -a
32 echo
33
34 mkdir d
35 echo hello > d/f2
36 python unix2mac.py d/f2
37 hg add d/f2
38 hg ci -m 3 -d'0 0'
39 hg revert -a
40 rm d/f2
41 echo
42
43 hg rem f
44 hg ci -m 4 -d'0 0'
45 echo
46
47 python -c 'file("bin", "wb").write("hello\x00\x0D")'
48 hg add bin
49 hg ci -m 5 -d'0 0'
50 hg log -v
51 echo
52
53 hg clone . dupe
54 echo
55 for x in a b c d; do echo content > dupe/$x; done
56 hg -R dupe add
57 python unix2mac.py dupe/b dupe/c dupe/d
58 hg -R dupe ci -m a -d'0 0' dupe/a
59 hg -R dupe ci -m b/c -d'0 0' dupe/[bc]
60 hg -R dupe ci -m d -d'0 0' dupe/d
61 hg -R dupe log -v
62 echo
63
64 hg pull dupe
65 echo
66
67 hg log -v
68 echo
69
70 rm .hg/hgrc
71 (echo some; echo text) > f3
72 python -c 'file("f4.bat", "wb").write("rem empty\x0D")'
73 hg add f3 f4.bat
74 hg ci -m 6 -d'0 0'
75
76 python print.py < bin
77 python print.py < f3
78 python print.py < f4.bat
79 echo
80
81 echo '[extensions]' >> .hg/hgrc
82 echo 'win32text = ' >> .hg/hgrc
83 echo '[decode]' >> .hg/hgrc
84 echo '** = macdecode:' >> .hg/hgrc
85 echo '[encode]' >> .hg/hgrc
86 echo '** = macencode:' >> .hg/hgrc
87 cat .hg/hgrc
88 echo
89
90 rm f3 f4.bat bin
91 hg co 2>&1 | python -c 'import sys, os; sys.stdout.write(sys.stdin.read().replace(os.getcwd(), "...."))'
92 python print.py < bin
93 python print.py < f3
94 python print.py < f4.bat
95 echo
96
97 python -c 'file("f5.sh", "wb").write("# empty\x0D")'
98 hg add f5.sh
99 hg ci -m 7 -d'0 0'
100 python print.py < f5.sh
101 hg cat f5.sh | python print.py
102
103 echo '% just linefeed' > linefeed
104 hg ci -qAm 8 linefeed
105 python print.py < linefeed
106 hg cat linefeed | python print.py
107 hg st -q
108 hg revert -a linefeed
109 python print.py < linefeed
110 hg st -q
111 echo modified >> linefeed
112 hg st -q
113 hg revert -a
114 hg st -q
115 python print.py < linefeed
@@ -0,0 +1,187
1 [hooks]
2 pretxncommit.cr = python:hgext.win32text.forbidcr
3 pretxnchangegroup.cr = python:hgext.win32text.forbidcr
4
5
6 Attempt to commit or push text file(s) using CR line endings
7 in dea860dc51ec: f
8 transaction abort!
9 rollback completed
10 abort: pretxncommit.cr hook failed
11 reverting f
12
13 Attempt to commit or push text file(s) using CR line endings
14 in 8aa1d87b4e2f: d/f2
15 transaction abort!
16 rollback completed
17 abort: pretxncommit.cr hook failed
18 forgetting d/f2
19
20
21 changeset: 2:d7599e43717c
22 tag: tip
23 user: test
24 date: Thu Jan 01 00:00:00 1970 +0000
25 files: bin
26 description:
27 5
28
29
30 changeset: 1:c72a7d1d0907
31 user: test
32 date: Thu Jan 01 00:00:00 1970 +0000
33 files: f
34 description:
35 4
36
37
38 changeset: 0:fcf06d5c4e1d
39 user: test
40 date: Thu Jan 01 00:00:00 1970 +0000
41 files: f
42 description:
43 1
44
45
46
47 updating working directory
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49
50 adding dupe/a
51 adding dupe/b
52 adding dupe/c
53 adding dupe/d
54 changeset: 5:ebbcbe52b20e
55 tag: tip
56 user: test
57 date: Thu Jan 01 00:00:00 1970 +0000
58 files: d
59 description:
60 d
61
62
63 changeset: 4:ceeb93d6508a
64 user: test
65 date: Thu Jan 01 00:00:00 1970 +0000
66 files: b c
67 description:
68 b/c
69
70
71 changeset: 3:c5404edbb872
72 user: test
73 date: Thu Jan 01 00:00:00 1970 +0000
74 files: a
75 description:
76 a
77
78
79 changeset: 2:d7599e43717c
80 user: test
81 date: Thu Jan 01 00:00:00 1970 +0000
82 files: bin
83 description:
84 5
85
86
87 changeset: 1:c72a7d1d0907
88 user: test
89 date: Thu Jan 01 00:00:00 1970 +0000
90 files: f
91 description:
92 4
93
94
95 changeset: 0:fcf06d5c4e1d
96 user: test
97 date: Thu Jan 01 00:00:00 1970 +0000
98 files: f
99 description:
100 1
101
102
103
104 pulling from dupe
105 searching for changes
106 adding changesets
107 adding manifests
108 adding file changes
109 added 3 changesets with 4 changes to 4 files
110 Attempt to commit or push text file(s) using CR line endings
111 in ceeb93d6508a: b
112 in ceeb93d6508a: c
113 in ebbcbe52b20e: d
114
115 To prevent this mistake in your local repository,
116 add to Mercurial.ini or .hg/hgrc:
117
118 [hooks]
119 pretxncommit.cr = python:hgext.win32text.forbidcr
120
121 and also consider adding:
122
123 [extensions]
124 hgext.win32text =
125 [encode]
126 ** = macencode:
127 [decode]
128 ** = macdecode:
129 transaction abort!
130 rollback completed
131 abort: pretxnchangegroup.cr hook failed
132
133 changeset: 2:d7599e43717c
134 tag: tip
135 user: test
136 date: Thu Jan 01 00:00:00 1970 +0000
137 files: bin
138 description:
139 5
140
141
142 changeset: 1:c72a7d1d0907
143 user: test
144 date: Thu Jan 01 00:00:00 1970 +0000
145 files: f
146 description:
147 4
148
149
150 changeset: 0:fcf06d5c4e1d
151 user: test
152 date: Thu Jan 01 00:00:00 1970 +0000
153 files: f
154 description:
155 1
156
157
158
159 hello<NUL><CR>
160 some<LF>text<LF>
161 rem empty<CR>
162
163 [extensions]
164 win32text =
165 [decode]
166 ** = macdecode:
167 [encode]
168 ** = macencode:
169
170 WARNING: f4.bat already has CR line endings
171 and does not need EOL conversion by the win32text plugin.
172 Before your next commit, please reconsider your encode/decode settings in
173 Mercurial.ini or ..../.hg/hgrc.
174 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 hello<NUL><CR>
176 some<CR>text<CR>
177 rem empty<CR>
178
179 # empty<CR>
180 # empty<LF>
181 % just linefeed<LF>
182 % just linefeed<LF>
183 no changes needed to linefeed
184 % just linefeed<LF>
185 M linefeed
186 reverting linefeed
187 % just linefeed<CR>
@@ -1,103 +1,144
1 # win32text.py - LF <-> CRLF translation utilities for Windows users
1 # win32text.py - LF <-> CRLF/CR translation utilities for Windows/Mac users
2 #
2 #
3 # This software may be used and distributed according to the terms
3 # This software may be used and distributed according to the terms
4 # of the GNU General Public License, incorporated herein by reference.
4 # of the GNU General Public License, incorporated herein by reference.
5 #
5 #
6 # To perform automatic newline conversion, use:
6 # To perform automatic newline conversion, use:
7 #
7 #
8 # [extensions]
8 # [extensions]
9 # hgext.win32text =
9 # hgext.win32text =
10 # [encode]
10 # [encode]
11 # ** = cleverencode:
11 # ** = cleverencode:
12 # # or ** = macencode:
12 # [decode]
13 # [decode]
13 # ** = cleverdecode:
14 # ** = cleverdecode:
15 # # or ** = macdecode:
14 #
16 #
15 # If not doing conversion, to make sure you do not commit CRLF by accident:
17 # If not doing conversion, to make sure you do not commit CRLF/CR by accident:
16 #
18 #
17 # [hooks]
19 # [hooks]
18 # pretxncommit.crlf = python:hgext.win32text.forbidcrlf
20 # pretxncommit.crlf = python:hgext.win32text.forbidcrlf
21 # # or pretxncommit.cr = python:hgext.win32text.forbidcr
19 #
22 #
20 # To do the same check on a server to prevent CRLF from being pushed or pulled:
23 # To do the same check on a server to prevent CRLF/CR from being pushed or
24 # pulled:
21 #
25 #
22 # [hooks]
26 # [hooks]
23 # pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf
27 # pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf
28 # # or pretxnchangegroup.cr = python:hgext.win32text.forbidcr
24
29
25 from mercurial import util
30 from mercurial import util
26 from mercurial.i18n import gettext as _
31 from mercurial.i18n import gettext as _
27 from mercurial.node import bin, short
32 from mercurial.node import bin, short
28 import re
33 import re
29
34
30 # regexp for single LF without CR preceding.
35 # regexp for single LF without CR preceding.
31 re_single_lf = re.compile('(^|[^\r])\n', re.MULTILINE)
36 re_single_lf = re.compile('(^|[^\r])\n', re.MULTILINE)
32
37
33 def dumbdecode(s, cmd, ui=None, repo=None, filename=None, **kwargs):
38 newlinestr = {'\r\n': 'CRLF', '\r': 'CR'}
34 # warn if already has CRLF in repository.
39 filterstr = {'\r\n': 'clever', '\r': 'mac'}
40
41 def checknewline(s, newline, ui=None, repo=None, filename=None):
42 # warn if already has 'newline' in repository.
35 # it might cause unexpected eol conversion.
43 # it might cause unexpected eol conversion.
36 # see issue 302:
44 # see issue 302:
37 # http://www.selenic.com/mercurial/bts/issue302
45 # http://www.selenic.com/mercurial/bts/issue302
38 if '\r\n' in s and ui and filename and repo:
46 if newline in s and ui and filename and repo:
39 ui.warn(_('WARNING: %s already has CRLF line endings\n'
47 ui.warn(_('WARNING: %s already has %s line endings\n'
40 'and does not need EOL conversion by the win32text plugin.\n'
48 'and does not need EOL conversion by the win32text plugin.\n'
41 'Before your next commit, please reconsider your '
49 'Before your next commit, please reconsider your '
42 'encode/decode settings in \nMercurial.ini or %s.\n') %
50 'encode/decode settings in \nMercurial.ini or %s.\n') %
43 (filename, repo.join('hgrc')))
51 (filename, newlinestr[newline], repo.join('hgrc')))
52
53 def dumbdecode(s, cmd, **kwargs):
54 checknewline(s, '\r\n', **kwargs)
44 # replace single LF to CRLF
55 # replace single LF to CRLF
45 return re_single_lf.sub('\\1\r\n', s)
56 return re_single_lf.sub('\\1\r\n', s)
46
57
47 def dumbencode(s, cmd):
58 def dumbencode(s, cmd):
48 return s.replace('\r\n', '\n')
59 return s.replace('\r\n', '\n')
49
60
61 def macdumbdecode(s, cmd, **kwargs):
62 checknewline(s, '\r', **kwargs)
63 return s.replace('\n', '\r')
64
65 def macdumbencode(s, cmd):
66 return s.replace('\r', '\n')
67
50 def cleverdecode(s, cmd, **kwargs):
68 def cleverdecode(s, cmd, **kwargs):
51 if util.binary(s):
69 if util.binary(s):
52 return s
70 return s
53 return dumbdecode(s, cmd, **kwargs)
71 return dumbdecode(s, cmd, **kwargs)
54
72
55 def cleverencode(s, cmd):
73 def cleverencode(s, cmd):
56 if util.binary(s):
74 if util.binary(s):
57 return s
75 return s
58 return dumbencode(s, cmd)
76 return dumbencode(s, cmd)
59
77
78 def macdecode(s, cmd, **kwargs):
79 if util.binary(s):
80 return s
81 return macdumbdecode(s, cmd, **kwargs)
82
83 def macencode(s, cmd):
84 if util.binary(s):
85 return s
86 return macdumbencode(s, cmd)
87
60 _filters = {
88 _filters = {
61 'dumbdecode:': dumbdecode,
89 'dumbdecode:': dumbdecode,
62 'dumbencode:': dumbencode,
90 'dumbencode:': dumbencode,
63 'cleverdecode:': cleverdecode,
91 'cleverdecode:': cleverdecode,
64 'cleverencode:': cleverencode,
92 'cleverencode:': cleverencode,
93 'macdumbdecode:': macdumbdecode,
94 'macdumbencode:': macdumbencode,
95 'macdecode:': macdecode,
96 'macencode:': macencode,
65 }
97 }
66
98
67 def forbidcrlf(ui, repo, hooktype, node, **kwargs):
99 def forbidcrlforcr(ui, repo, hooktype, node, newline, **kwargs):
68 halt = False
100 halt = False
69 for rev in xrange(repo.changelog.rev(bin(node)), repo.changelog.count()):
101 for rev in xrange(repo.changelog.rev(bin(node)), repo.changelog.count()):
70 c = repo.changectx(rev)
102 c = repo.changectx(rev)
71 for f in c.files():
103 for f in c.files():
72 if f not in c:
104 if f not in c:
73 continue
105 continue
74 data = c[f].data()
106 data = c[f].data()
75 if not util.binary(data) and '\r\n' in data:
107 if not util.binary(data) and newline in data:
76 if not halt:
108 if not halt:
77 ui.warn(_('Attempt to commit or push text file(s) '
109 ui.warn(_('Attempt to commit or push text file(s) '
78 'using CRLF line endings\n'))
110 'using %s line endings\n') %
111 newlinestr[newline])
79 ui.warn(_('in %s: %s\n') % (short(c.node()), f))
112 ui.warn(_('in %s: %s\n') % (short(c.node()), f))
80 halt = True
113 halt = True
81 if halt and hooktype == 'pretxnchangegroup':
114 if halt and hooktype == 'pretxnchangegroup':
115 crlf = newlinestr[newline].lower()
116 filter = filterstr[newline]
82 ui.warn(_('\nTo prevent this mistake in your local repository,\n'
117 ui.warn(_('\nTo prevent this mistake in your local repository,\n'
83 'add to Mercurial.ini or .hg/hgrc:\n'
118 'add to Mercurial.ini or .hg/hgrc:\n'
84 '\n'
119 '\n'
85 '[hooks]\n'
120 '[hooks]\n'
86 'pretxncommit.crlf = python:hgext.win32text.forbidcrlf\n'
121 'pretxncommit.%s = python:hgext.win32text.forbid%s\n'
87 '\n'
122 '\n'
88 'and also consider adding:\n'
123 'and also consider adding:\n'
89 '\n'
124 '\n'
90 '[extensions]\n'
125 '[extensions]\n'
91 'hgext.win32text =\n'
126 'hgext.win32text =\n'
92 '[encode]\n'
127 '[encode]\n'
93 '** = cleverencode:\n'
128 '** = %sencode:\n'
94 '[decode]\n'
129 '[decode]\n'
95 '** = cleverdecode:\n'))
130 '** = %sdecode:\n') % (crlf, crlf, filter, filter))
96 return halt
131 return halt
97
132
133 def forbidcrlf(ui, repo, hooktype, node, **kwargs):
134 return forbidcrlforcr(ui, repo, hooktype, node, '\r\n', **kwargs)
135
136 def forbidcr(ui, repo, hooktype, node, **kwargs):
137 return forbidcrlforcr(ui, repo, hooktype, node, '\r', **kwargs)
138
98 def reposetup(ui, repo):
139 def reposetup(ui, repo):
99 if not repo.local():
140 if not repo.local():
100 return
141 return
101 for name, fn in _filters.iteritems():
142 for name, fn in _filters.iteritems():
102 repo.adddatafilter(name, fn)
143 repo.adddatafilter(name, fn)
103
144
General Comments 0
You need to be logged in to leave comments. Login now