##// END OF EJS Templates
merge with stable
Martin von Zweigbergk -
r43741:93f74a7d merge default
parent child Browse files
Show More
@@ -0,0 +1,15 b''
1 FROM centos:centos8
2
3 RUN groupadd -g %GID% build && \
4 useradd -u %UID% -g %GID% -s /bin/bash -d /build -m build
5
6 RUN yum install -y \
7 gcc \
8 gettext \
9 make \
10 python3-devel \
11 python3-docutils \
12 rpm-build
13
14 # For creating repo meta data
15 RUN yum install -y createrepo
@@ -0,0 +1,6 b''
1 from __future__ import absolute_import, print_function
2
3 import re
4 import sys
5
6 print(re.sub(r"(?<=Message-Id:) \n ", " ", sys.stdin.read()), end="")
@@ -185,3 +185,5 b' e386b5f4f8360dbb43a576dd9b1368e386fefa5b'
185 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAl1DD/sQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91bvmD/4/QDZZGVe+WiMUxbT+grfFjwjX4nkg7Vt+6vQbjN68NC5XpSiCzW8uu0LRemX0KJKoOfQxqHk3YKkZZHIk10Fe6RSLWt8dqlfa2J9B2U8DwMEBykCOuxcLlDe7DGaaMXlXXRhNXebRheNPLeNe+r7beMAAjwchTIIJD5xcFnPRFR0nN7Vj7eRUdWIQ9H/s7TolPz1Mf7IWqapLjPtofiwSgtRoXfIAkuuabnE4eMVJ8rsLwcuMhxWP2zjEfEg68YkiGBAFmlnRk+3lJpiB9kVapB3cWcsWv2OBhz0D3NgGp82eWkjJCZZhZ+zHHrQ6L9zbiArzW9NVvPEAKLbl3XUhFUzFTUD+S38wsYLYL5RkzhlCI2/K1LJLOtj7r0Seen0v8X842p0cXmxTg/o1Vg3JOm04l9AwzCsnqwIqV7Ru//KPqH91MFFH6T6tbfjtLHRmjxRjMZmVt7ZQjS84opVCZwgUTZZJB2kd1goROjdowQVK6qsEonlzGjWb9zc3el5L9uzDeim3e5t2GNRVt8veQaLc+U2hHWniVsDJMvqp2Hr9IWUKp+bu/35B1nElvooS40gj2WhkfkCbbXSg9qnVLwGxxcGdF28Z0nhQcfKiJAc+8l9l19GNhdKxOi4zUXlp90opPWfT7wGQmysvTjQeFL2zX9ziuHUZZwlW1YbeMQ==
185 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAl1DD/sQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91bvmD/4/QDZZGVe+WiMUxbT+grfFjwjX4nkg7Vt+6vQbjN68NC5XpSiCzW8uu0LRemX0KJKoOfQxqHk3YKkZZHIk10Fe6RSLWt8dqlfa2J9B2U8DwMEBykCOuxcLlDe7DGaaMXlXXRhNXebRheNPLeNe+r7beMAAjwchTIIJD5xcFnPRFR0nN7Vj7eRUdWIQ9H/s7TolPz1Mf7IWqapLjPtofiwSgtRoXfIAkuuabnE4eMVJ8rsLwcuMhxWP2zjEfEg68YkiGBAFmlnRk+3lJpiB9kVapB3cWcsWv2OBhz0D3NgGp82eWkjJCZZhZ+zHHrQ6L9zbiArzW9NVvPEAKLbl3XUhFUzFTUD+S38wsYLYL5RkzhlCI2/K1LJLOtj7r0Seen0v8X842p0cXmxTg/o1Vg3JOm04l9AwzCsnqwIqV7Ru//KPqH91MFFH6T6tbfjtLHRmjxRjMZmVt7ZQjS84opVCZwgUTZZJB2kd1goROjdowQVK6qsEonlzGjWb9zc3el5L9uzDeim3e5t2GNRVt8veQaLc+U2hHWniVsDJMvqp2Hr9IWUKp+bu/35B1nElvooS40gj2WhkfkCbbXSg9qnVLwGxxcGdF28Z0nhQcfKiJAc+8l9l19GNhdKxOi4zUXlp90opPWfT7wGQmysvTjQeFL2zX9ziuHUZZwlW1YbeMQ==
186 a4e32fd539ab41489a51b2aa88bda9a73b839562 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAl1xTxUQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91ZQgD/96mViQ6fEh84l4XyAlY6Dq3SgMqEXttsUpk/GPoW4ykDFKN6VoiOaPoyNODO/46V3yeAjYjy3vX7Ua4/MY1NlnNoliQcTYtRV3SlDdoueTPOLfO6YSV27LG+dX/HYvPc/htCVmIVItU1JL+KEpXnv+bT50Bk+m6OgzfJMDzdHQ5ICImT8gW7UXlH/mlNtWMOrJDk3cArGhGs/pTFVrfgRTfDfDGSA9xW0/QvsNI5iwZHgMYaqoPFDnw6d/NXWRlk77KNiXkBEOKHf6UEWecMKmiSCm8RePSiX9ezqdcBAHygOg4KUeiR2kPNl4QJtskyG4CwWxlmGlfgKx07s7rGafE+DWLEYC9Wa8qK6/LPiowm17m/UlAYxdFXaBCiN0wgEw7oNmjcx/791ez+CL1+h6pd0+iSVI4bO9/YZ8LPROYef18MFm+IFIDIOgZU4eUbpBrzBb3IM1a519xgnmWXAjtRtGWEZMuHaSoLJf2pDXvaUPX6YpJeqCBFO3q/swbiJsQsy6xRW0Dwtn7umU1PGdmMoTnskTRKy9Kgzv7lf/nsUuRbzzM4ut9m1TOo27AulObMrmQB4YvLi/LEnYaRNx18yaqOceMxb/mS0tHLgcZToy9rTV+vtC21vgwfzGia2neLLe50tnIsBPP/AdTOw9ZDMRfXMCajWM22hPxvnGcw==
186 a4e32fd539ab41489a51b2aa88bda9a73b839562 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAl1xTxUQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91ZQgD/96mViQ6fEh84l4XyAlY6Dq3SgMqEXttsUpk/GPoW4ykDFKN6VoiOaPoyNODO/46V3yeAjYjy3vX7Ua4/MY1NlnNoliQcTYtRV3SlDdoueTPOLfO6YSV27LG+dX/HYvPc/htCVmIVItU1JL+KEpXnv+bT50Bk+m6OgzfJMDzdHQ5ICImT8gW7UXlH/mlNtWMOrJDk3cArGhGs/pTFVrfgRTfDfDGSA9xW0/QvsNI5iwZHgMYaqoPFDnw6d/NXWRlk77KNiXkBEOKHf6UEWecMKmiSCm8RePSiX9ezqdcBAHygOg4KUeiR2kPNl4QJtskyG4CwWxlmGlfgKx07s7rGafE+DWLEYC9Wa8qK6/LPiowm17m/UlAYxdFXaBCiN0wgEw7oNmjcx/791ez+CL1+h6pd0+iSVI4bO9/YZ8LPROYef18MFm+IFIDIOgZU4eUbpBrzBb3IM1a519xgnmWXAjtRtGWEZMuHaSoLJf2pDXvaUPX6YpJeqCBFO3q/swbiJsQsy6xRW0Dwtn7umU1PGdmMoTnskTRKy9Kgzv7lf/nsUuRbzzM4ut9m1TOo27AulObMrmQB4YvLi/LEnYaRNx18yaqOceMxb/mS0tHLgcZToy9rTV+vtC21vgwfzGia2neLLe50tnIsBPP/AdTOw9ZDMRfXMCajWM22hPxvnGcw==
187 181e52f2b62f4768aa0d988936c929dc7c4a41a0 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAl2UzlMQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91SDzD/0YZqtN+LK5AusJjWaTa61DRIPhJQoZD+HKg4kAzjL8zw8SxBGLxMZkGmve9QFMNzqIr5kkPk6yEKrEWYqyPtpwrv5Xh5D4d8AKfphdzwSr+BvMk4fBEvwnBhrUJtKDEiuYQdbh4+OQfQs1c3xhtinjXn30160uzFvLQY6/h4hxai2XWj4trgoNXqPHDHlQKc6kRfPpmNO2UZhG+2Xfsava2JpcP4xA2R0XkI10be5MDoGU4AFCMUcXZzIto0DYT+HOezowoNpdC1EWVHfa+bdrlzHHO7WPaTLzEPy44/IhXmNhbwFKOk5RZ/qBADQvs9BDfmIDczOoZKTC5+ESZM0PR2np5t7+JFMUeeRcINqBdSc4Aszw3iHjgNbJJ3viU72JZvGGGd9MglP590tA0proVGxQgvXDq3mtq3Se5yOLAjmRnktW5Tnt8/Z3ycuZz+QsTEMXR5uIZvgz63ibfsCGTXFYUz9h7McGgmhfKWvQw9+MH6kRbE9U8qaUumgf4zi4HNzmf8AyaMJo07DIMwWVgjlVUdWUlN/Eg61fU3wC79mV8mLVsi5/TZ986obz4csoYSYXyyez5ScRji+znSw8vUx0YhoiOQbDms/y2QZR/toyon554tHkDZsya2lhpwXs8T0IFZhERXsmz/XmT3fWnhSzyrUe6VjBMep1zn6lvQ==
187 181e52f2b62f4768aa0d988936c929dc7c4a41a0 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAl2UzlMQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91SDzD/0YZqtN+LK5AusJjWaTa61DRIPhJQoZD+HKg4kAzjL8zw8SxBGLxMZkGmve9QFMNzqIr5kkPk6yEKrEWYqyPtpwrv5Xh5D4d8AKfphdzwSr+BvMk4fBEvwnBhrUJtKDEiuYQdbh4+OQfQs1c3xhtinjXn30160uzFvLQY6/h4hxai2XWj4trgoNXqPHDHlQKc6kRfPpmNO2UZhG+2Xfsava2JpcP4xA2R0XkI10be5MDoGU4AFCMUcXZzIto0DYT+HOezowoNpdC1EWVHfa+bdrlzHHO7WPaTLzEPy44/IhXmNhbwFKOk5RZ/qBADQvs9BDfmIDczOoZKTC5+ESZM0PR2np5t7+JFMUeeRcINqBdSc4Aszw3iHjgNbJJ3viU72JZvGGGd9MglP590tA0proVGxQgvXDq3mtq3Se5yOLAjmRnktW5Tnt8/Z3ycuZz+QsTEMXR5uIZvgz63ibfsCGTXFYUz9h7McGgmhfKWvQw9+MH6kRbE9U8qaUumgf4zi4HNzmf8AyaMJo07DIMwWVgjlVUdWUlN/Eg61fU3wC79mV8mLVsi5/TZ986obz4csoYSYXyyez5ScRji+znSw8vUx0YhoiOQbDms/y2QZR/toyon554tHkDZsya2lhpwXs8T0IFZhERXsmz/XmT3fWnhSzyrUe6VjBMep1zn6lvQ==
188 59338f9561099de77c684c00f76507f11e46ebe8 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAl2ty1MQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91XBUD/wJqwW0cuMCUvuUODLIfWa7ZxNl1mV9eW3tFQEuLGry97s12KDwBe0Erdjj7DASl4/6Xpc4PYxelZwSw4xT1UQg7wd/C3daCq/cDXrAkl7ZNTAHu6iAnHh25mOpIBfhMbh4j3YD0A2OoI17QGScU6S7Uv0Gz1CY20lJmEqsMzuuDPm2zrdPnTWffRUuPgskAg3czaw45Na7nUBeaxN1On0O5WqMYZsCGyi14g5S0Z0LHMKRJzc/s48JUTDjTbbzJ6HBxrxWTW2v8gN2J6QDYykcLBB9kV6laal9jhWs9n/w0yWwHfBfJ+E4EiMXeRdZgGA55OCOuDxnmmONs1/Z0WwPo+vQlowEnjDMT0jPrPePZ5P4BDXZD3tGsmdXDHM7j+VfDyPh1FBFpcaej44t84X1OWtAnLZ3VMPLwobz9MOzz4wr9UuHq23hus0Fen+FJYOAlTx9qPAqBrCTpGl+h1DMKD62D7lF8Z1CxTlqg9PPBB7IZNCXoN7FZ4Wfhv1AarMVNNUgBx6m0r6OScCXrluuFklYDSIZrfgiwosXxsHW27RjxktrV4O+J1GT/chLBJFViTZg/gX/9UC3eLkzp1t6gC6T9SQ+lq0/I+1/rHQkxNaywLycBPOG1yb/59mibEwB9+Mu9anRYKFNHEktNoEmyw5G9UoZhD+1tHt4tkJCwA==
189 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAl3BrQ4QHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91ZXjEACfBdZczf0a4bmeaaxRwxXAniSS4rVkF790g22fsvSZFvQEpmwqNtsvbTt3N1V2QSDSZyhBa+/qfpuZ689VXMlR3rcJOVjo/7193QLXHOPfRn7sDeeCxjsbtXXLbLa8UT56gtT5gUa4i0LC2kHBEi+UhV9EGgSaDTBxWUFJ9RY2sosy1XFiOUlkUoHUbqUF28J3/CxEXzULWkqTOPwh94JYsgXSSS69WNZEfsuEBSPCzn8Gd7z7lWudZ/VTZBTpTji7HQxpFtSZxNzpwmcmVOH9HlEKoA1K4JoR+1TMHqSytQXlz3FMF6c6Z1G+OPpwTGCjGTkB9ZAusP3gU8KIZTTEXthiEluRtnRq1yu4K2LTyY172JPJvANAWpVEvBvn4k5c9tDOEt9RCAPqCrgNGzDTrw02+gZyyNkjcS6hPn+cDJ6OQ1j2eCQtHlqfHLSc7FsRjUSTiKSEUTdWvHbNfOYe6Yth/tnQ7TnpnS9S0eiugFzZs2f8P85Gfa3uTFQIDm67Ud+8Yu1uOxa6bhECLaXEACnLofzz8sioLsJMiOoG2HmwhyPyfZUHXlb2zdsSP3LC+gKN39VvzSxhhjrIUJoM4ulP0GP1/lkMVzOady66iLaEwDvEn4FLmu395SubHwbre1Jx83hiCQpZfPkI0PhKnh4yVm+BRGUpX97rMTGjzw==
@@ -198,3 +198,5 b' e386b5f4f8360dbb43a576dd9b1368e386fefa5b'
198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
@@ -183,16 +183,15 b' packaging_targets := \\'
183 centos5 \
183 centos5 \
184 centos6 \
184 centos6 \
185 centos7 \
185 centos7 \
186 centos8 \
186 deb \
187 deb \
187 docker-centos5 \
188 docker-centos5 \
188 docker-centos6 \
189 docker-centos6 \
189 docker-centos7 \
190 docker-centos7 \
191 docker-centos8 \
190 docker-debian-jessie \
192 docker-debian-jessie \
191 docker-debian-stretch \
193 docker-debian-stretch \
192 docker-fedora20 \
194 docker-fedora \
193 docker-fedora21 \
194 docker-fedora28 \
195 docker-fedora29 \
196 docker-ubuntu-trusty \
195 docker-ubuntu-trusty \
197 docker-ubuntu-trusty-ppa \
196 docker-ubuntu-trusty-ppa \
198 docker-ubuntu-xenial \
197 docker-ubuntu-xenial \
@@ -201,10 +200,7 b' packaging_targets := \\'
201 docker-ubuntu-artful-ppa \
200 docker-ubuntu-artful-ppa \
202 docker-ubuntu-bionic \
201 docker-ubuntu-bionic \
203 docker-ubuntu-bionic-ppa \
202 docker-ubuntu-bionic-ppa \
204 fedora20 \
203 fedora \
205 fedora21 \
206 fedora28 \
207 fedora29 \
208 linux-wheels \
204 linux-wheels \
209 linux-wheels-x86_64 \
205 linux-wheels-x86_64 \
210 linux-wheels-i686 \
206 linux-wheels-i686 \
@@ -9,9 +9,7 b' build/'
9 | \.mypy_cache/
9 | \.mypy_cache/
10 | \.venv/
10 | \.venv/
11 | mercurial/thirdparty/
11 | mercurial/thirdparty/
12 | hgext/fsmonitor/pywatchman/
13 | contrib/python-zstandard/
12 | contrib/python-zstandard/
14 | contrib/grey.py
15 '''
13 '''
16 skip-string-normalization = true
14 skip-string-normalization = true
17 quiet = true
15 quiet = true
@@ -191,6 +191,10 b" winrm set winrm/config/client/auth '@{Ba"
191 $Setting = 'LocalAccountTokenFilterPolicy'
191 $Setting = 'LocalAccountTokenFilterPolicy'
192 Set-ItemProperty -Path $Key -Name $Setting -Value 1 -Force
192 Set-ItemProperty -Path $Key -Name $Setting -Value 1 -Force
193
193
194 # Avoid long usernames in the temp directory path because the '~' causes extra quoting in ssh output
195 [System.Environment]::SetEnvironmentVariable('TMP', 'C:\Temp', [System.EnvironmentVariableTarget]::User)
196 [System.Environment]::SetEnvironmentVariable('TEMP', 'C:\Temp', [System.EnvironmentVariableTarget]::User)
197
194 # Configure and restart the WinRM Service; Enable the required firewall exception
198 # Configure and restart the WinRM Service; Enable the required firewall exception
195 Stop-Service -Name WinRM
199 Stop-Service -Name WinRM
196 Set-Service -Name WinRM -StartupType Automatic
200 Set-Service -Name WinRM -StartupType Automatic
@@ -25,12 +25,12 b' DISTROS = {'
25 }
25 }
26
26
27 INSTALL_PYTHONS = r'''
27 INSTALL_PYTHONS = r'''
28 PYENV2_VERSIONS="2.7.16 pypy2.7-7.1.1"
28 PYENV2_VERSIONS="2.7.17 pypy2.7-7.2.0"
29 PYENV3_VERSIONS="3.5.7 3.6.9 3.7.4 3.8.0 pypy3.5-7.0.0 pypy3.6-7.1.1"
29 PYENV3_VERSIONS="3.5.7 3.6.9 3.7.5 3.8.0 pypy3.5-7.0.0 pypy3.6-7.2.0"
30
30
31 git clone https://github.com/pyenv/pyenv.git /hgdev/pyenv
31 git clone https://github.com/pyenv/pyenv.git /hgdev/pyenv
32 pushd /hgdev/pyenv
32 pushd /hgdev/pyenv
33 git checkout d6d6bc8bb08bcdcbf4eb79509aa7061011ade1c4
33 git checkout 0e7cfc3b3d4eca46ad83d632e1505f5932cd179b
34 popd
34 popd
35
35
36 export PYENV_ROOT="/hgdev/pyenv"
36 export PYENV_ROOT="/hgdev/pyenv"
@@ -266,6 +266,7 b' PACKAGES="\\'
266 python3-fuzzywuzzy \
266 python3-fuzzywuzzy \
267 python3-pygments \
267 python3-pygments \
268 python3-vcr \
268 python3-vcr \
269 python3-venv \
269 rsync \
270 rsync \
270 sqlite3 \
271 sqlite3 \
271 subversion \
272 subversion \
@@ -4,10 +4,25 b''
4 #
4 #
5 # pip-compile --generate-hashes --output-file=contrib/automation/linux-requirements-py3.txt contrib/automation/linux-requirements.txt.in
5 # pip-compile --generate-hashes --output-file=contrib/automation/linux-requirements-py3.txt contrib/automation/linux-requirements.txt.in
6 #
6 #
7 appdirs==1.4.3 \
8 --hash=sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92 \
9 --hash=sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e \
10 # via black
7 astroid==2.2.5 \
11 astroid==2.2.5 \
8 --hash=sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4 \
12 --hash=sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4 \
9 --hash=sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4 \
13 --hash=sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4 \
10 # via pylint
14 # via pylint
15 attrs==19.3.0 \
16 --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \
17 --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 \
18 # via black
19 black==19.10b0 ; python_version >= "3.6" and platform_python_implementation != "PyPy" \
20 --hash=sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b \
21 --hash=sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539
22 click==7.0 \
23 --hash=sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13 \
24 --hash=sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7 \
25 # via black
11 docutils==0.15.2 \
26 docutils==0.15.2 \
12 --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \
27 --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \
13 --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \
28 --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \
@@ -78,6 +93,9 b' multidict==4.5.2 \\'
78 --hash=sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7 \
93 --hash=sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7 \
79 --hash=sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b \
94 --hash=sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b \
80 # via yarl
95 # via yarl
96 pathspec==0.6.0 \
97 --hash=sha256:e285ccc8b0785beadd4c18e5708b12bb8fcf529a1e61215b3feff1d1e559ea5c \
98 # via black
81 pyflakes==2.1.1 \
99 pyflakes==2.1.1 \
82 --hash=sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0 \
100 --hash=sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0 \
83 --hash=sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2
101 --hash=sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2
@@ -104,10 +122,27 b' pyyaml==5.1.2 \\'
104 --hash=sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41 \
122 --hash=sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41 \
105 --hash=sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8 \
123 --hash=sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8 \
106 # via vcrpy
124 # via vcrpy
125 regex==2019.11.1 \
126 --hash=sha256:15454b37c5a278f46f7aa2d9339bda450c300617ca2fca6558d05d870245edc7 \
127 --hash=sha256:1ad40708c255943a227e778b022c6497c129ad614bb7a2a2f916e12e8a359ee7 \
128 --hash=sha256:5e00f65cc507d13ab4dfa92c1232d004fa202c1d43a32a13940ab8a5afe2fb96 \
129 --hash=sha256:604dc563a02a74d70ae1f55208ddc9bfb6d9f470f6d1a5054c4bd5ae58744ab1 \
130 --hash=sha256:720e34a539a76a1fedcebe4397290604cc2bdf6f81eca44adb9fb2ea071c0c69 \
131 --hash=sha256:7caf47e4a9ac6ef08cabd3442cc4ca3386db141fb3c8b2a7e202d0470028e910 \
132 --hash=sha256:c31eaf28c6fe75ea329add0022efeed249e37861c19681960f99bbc7db981fb2 \
133 --hash=sha256:c7393597191fc2043c744db021643549061e12abe0b3ff5c429d806de7b93b66 \
134 --hash=sha256:d2b302f8cdd82c8f48e9de749d1d17f85ce9a0f082880b9a4859f66b07037dc6 \
135 --hash=sha256:e3d8dd0ec0ea280cf89026b0898971f5750a7bd92cb62c51af5a52abd020054a \
136 --hash=sha256:ec032cbfed59bd5a4b8eab943c310acfaaa81394e14f44454ad5c9eba4f24a74 \
137 # via black
107 six==1.12.0 \
138 six==1.12.0 \
108 --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
139 --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
109 --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 \
140 --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 \
110 # via astroid, vcrpy
141 # via astroid, vcrpy
142 toml==0.10.0 \
143 --hash=sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c \
144 --hash=sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e \
145 # via black
111 typed-ast==1.4.0 ; python_version >= "3.0" and platform_python_implementation != "PyPy" \
146 typed-ast==1.4.0 ; python_version >= "3.0" and platform_python_implementation != "PyPy" \
112 --hash=sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e \
147 --hash=sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e \
113 --hash=sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e \
148 --hash=sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e \
@@ -146,4 +181,4 b' yarl==1.3.0 \\'
146
181
147 # WARNING: The following packages were not pinned, but pip requires them to be
182 # WARNING: The following packages were not pinned, but pip requires them to be
148 # pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag.
183 # pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag.
149 # setuptools==41.0.1 # via python-levenshtein
184 # setuptools==41.6.0 # via python-levenshtein
@@ -1,3 +1,5 b''
1 # black pulls in typed-ast, which doesn't install on PyPy.
2 black ; python_version >= '3.6' and platform_python_implementation != 'PyPy'
1 # Bazaar doesn't work with Python 3 nor PyPy.
3 # Bazaar doesn't work with Python 3 nor PyPy.
2 bzr ; python_version <= '2.7' and platform_python_implementation == 'CPython'
4 bzr ; python_version <= '2.7' and platform_python_implementation == 'CPython'
3 docutils
5 docutils
@@ -339,7 +339,7 b' def main():'
339
339
340
340
341 if __name__ == '__main__':
341 if __name__ == '__main__':
342 if sys.version_info.major < 3:
342 if sys.version_info[0:2] < (3, 7):
343 print('This script must be run under Python 3.')
343 print('This script must be run under Python 3.7+')
344 sys.exit(3)
344 sys.exit(3)
345 main()
345 main()
@@ -5,11 +5,5 b' clang-format:pattern = (**.c or **.cc or'
5 rustfmt:command = rustfmt {rootpath}
5 rustfmt:command = rustfmt {rootpath}
6 rustfmt:pattern = set:**.rs
6 rustfmt:pattern = set:**.rs
7
7
8 # We use black, but currently with
8 black:command = black --config=black.toml -
9 # https://github.com/psf/black/pull/826 applied. For now
9 black:pattern = set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"
10 # contrib/grey.py is our fork of black. You need to pip install
11 # git+https://github.com/python/black/@d9e71a75ccfefa3d9156a64c03313a0d4ad981e5
12 # to have the dependencies for grey.
13 #
14 # black:command = python3.7 contrib/grey.py --config=black.toml -
15 # black:pattern = set:**.py - hgext/fsmonitor/pywatchman/** - mercurial/thirdparty/** - "contrib/python-zstandard/** - contrib/grey.py"
@@ -4,6 +4,7 b' from __future__ import absolute_import, '
4
4
5 import ast
5 import ast
6 import collections
6 import collections
7 import io
7 import os
8 import os
8 import sys
9 import sys
9
10
@@ -754,7 +755,11 b' def sources(f, modname):'
754 yield src.read(), modname, f, 0
755 yield src.read(), modname, f, 0
755 py = True
756 py = True
756 if py or f.endswith('.t'):
757 if py or f.endswith('.t'):
757 with open(f, 'r') as src:
758 # Strictly speaking we should sniff for the magic header that denotes
759 # Python source file encoding. But in reality we don't use anything
760 # other than ASCII (mainly) and UTF-8 (in a few exceptions), so
761 # simplicity is fine.
762 with io.open(f, 'r', encoding='utf-8') as src:
758 for script, modname, t, line in embedded(f, modname, src):
763 for script, modname, t, line in embedded(f, modname, src):
759 yield script, modname.encode('utf8'), t, line
764 yield script, modname.encode('utf8'), t, line
760
765
@@ -22,10 +22,10 b''
22 $VC9_PYTHON_URL = "https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi"
22 $VC9_PYTHON_URL = "https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi"
23 $VC9_PYTHON_SHA256 = "070474db76a2e625513a5835df4595df9324d820f9cc97eab2a596dcbc2f5cbf"
23 $VC9_PYTHON_SHA256 = "070474db76a2e625513a5835df4595df9324d820f9cc97eab2a596dcbc2f5cbf"
24
24
25 $PYTHON27_x64_URL = "https://www.python.org/ftp/python/2.7.16/python-2.7.16.amd64.msi"
25 $PYTHON27_x64_URL = "https://www.python.org/ftp/python/2.7.17/python-2.7.17.amd64.msi"
26 $PYTHON27_x64_SHA256 = "7c0f45993019152d46041a7db4b947b919558fdb7a8f67bcd0535bc98d42b603"
26 $PYTHON27_x64_SHA256 = "3b934447e3620e51d2daf5b2f258c9b617bcc686ca2f777a49aa3b47893abf1b"
27 $PYTHON27_X86_URL = "https://www.python.org/ftp/python/2.7.16/python-2.7.16.msi"
27 $PYTHON27_X86_URL = "https://www.python.org/ftp/python/2.7.17/python-2.7.17.msi"
28 $PYTHON27_X86_SHA256 = "d57dc3e1ba490aee856c28b4915d09e3f49442461e46e481bc6b2d18207831d7"
28 $PYTHON27_X86_SHA256 = "a4e3a321517c6b0c2693d6f712a0d18c82600b3d0c759c299b3d14384a17f863"
29
29
30 $PYTHON35_x86_URL = "https://www.python.org/ftp/python/3.5.4/python-3.5.4.exe"
30 $PYTHON35_x86_URL = "https://www.python.org/ftp/python/3.5.4/python-3.5.4.exe"
31 $PYTHON35_x86_SHA256 = "F27C2D67FD9688E4970F3BFF799BB9D722A0D6C2C13B04848E1F7D620B524B0E"
31 $PYTHON35_x86_SHA256 = "F27C2D67FD9688E4970F3BFF799BB9D722A0D6C2C13B04848E1F7D620B524B0E"
@@ -37,10 +37,10 b''
37 $PYTHON36_x64_URL = "https://www.python.org/ftp/python/3.6.8/python-3.6.8-amd64.exe"
37 $PYTHON36_x64_URL = "https://www.python.org/ftp/python/3.6.8/python-3.6.8-amd64.exe"
38 $PYTHON36_x64_SHA256 = "96088A58B7C43BC83B84E6B67F15E8706C614023DD64F9A5A14E81FF824ADADC"
38 $PYTHON36_x64_SHA256 = "96088A58B7C43BC83B84E6B67F15E8706C614023DD64F9A5A14E81FF824ADADC"
39
39
40 $PYTHON37_x86_URL = "https://www.python.org/ftp/python/3.7.4/python-3.7.4.exe"
40 $PYTHON37_x86_URL = "https://www.python.org/ftp/python/3.7.5/python-3.7.5.exe"
41 $PYTHON37_x86_SHA256 = "9a30ab5568ba37bfbcae5cdee19e9dc30765c42cf066f605221563ff8b20ee34"
41 $PYTHON37_x86_SHA256 = "3c2ae8f72b48e6e0c2b482206e322bf5d0344ff91abc3b3c200cec9e275c7168"
42 $PYTHON37_X64_URL = "https://www.python.org/ftp/python/3.7.4/python-3.7.4-amd64.exe"
42 $PYTHON37_X64_URL = "https://www.python.org/ftp/python/3.7.5/python-3.7.5-amd64.exe"
43 $PYTHON37_x64_SHA256 = "bab92f987320975c7826171a072bfd64f8f0941aaf2cdeba6924b7025c9968a3"
43 $PYTHON37_x64_SHA256 = "f3d60c127e7a92ed547efa3321bf70cd96b75c53bf4b903147015257c1314981"
44
44
45 $PYTHON38_x86_URL = "https://www.python.org/ftp/python/3.8.0/python-3.8.0.exe"
45 $PYTHON38_x86_URL = "https://www.python.org/ftp/python/3.8.0/python-3.8.0.exe"
46 $PYTHON38_x86_SHA256 = "b471908de5e10d8fb5c3351a5affb1172da7790c533e0c9ffbaeec9c11611b15"
46 $PYTHON38_x86_SHA256 = "b471908de5e10d8fb5c3351a5affb1172da7790c533e0c9ffbaeec9c11611b15"
@@ -11,19 +11,17 b' UBUNTU_CODENAMES := \\'
11 cosmic \
11 cosmic \
12 disco
12 disco
13
13
14 FEDORA_RELEASES := \
14 FEDORA_RELEASE := 31
15 20 \
16 21 \
17 28 \
18 29
19
15
20 CENTOS_RELEASES := \
16 CENTOS_RELEASES := \
21 5 \
17 5 \
22 6 \
18 6 \
23 7
19 7 \
20 8
24
21
25 # Build a Python for these CentOS releases.
22 # Build a Python for these CentOS releases.
26 CENTOS_WITH_PYTHON_RELEASES := 5 6
23 CENTOS_WITH_PYTHON_RELEASES := 5 6
24 CENTOS_WITH_NONVERSIONED_PYTHON := 5 6 7
27
25
28 help:
26 help:
29 @echo 'Packaging Make Targets'
27 @echo 'Packaging Make Targets'
@@ -34,8 +32,8 b' help:'
34 @echo 'docker-debian-{$(strip $(DEBIAN_CODENAMES))}'
32 @echo 'docker-debian-{$(strip $(DEBIAN_CODENAMES))}'
35 @echo ' Build Debian packages specific to a Debian distro using Docker.'
33 @echo ' Build Debian packages specific to a Debian distro using Docker.'
36 @echo ''
34 @echo ''
37 @echo 'docker-fedora{$(strip $(FEDORA_RELEASES))}'
35 @echo 'docker-fedora'
38 @echo ' Build an RPM for a specific Fedora version using Docker.'
36 @echo ' Build an RPM for a Fedora $(FEDORA_RELEASE) using Docker.'
39 @echo ''
37 @echo ''
40 @echo 'docker-ubuntu-{$(strip $(UBUNTU_CODENAMES))}'
38 @echo 'docker-ubuntu-{$(strip $(UBUNTU_CODENAMES))}'
41 @echo ' Build Debian package specific to an Ubuntu distro using Docker.'
39 @echo ' Build Debian package specific to an Ubuntu distro using Docker.'
@@ -59,8 +57,8 b' help:'
59 @echo 'centos{$(strip $(CENTOS_RELEASES))}'
57 @echo 'centos{$(strip $(CENTOS_RELEASES))}'
60 @echo ' Build an RPM for a specific CentOS version locally'
58 @echo ' Build an RPM for a specific CentOS version locally'
61 @echo ''
59 @echo ''
62 @echo 'fedora{$(strip $(FEDORA_RELEASES))}'
60 @echo 'fedora'
63 @echo ' Build an RPM for a specific Fedora version locally'
61 @echo ' Build an RPM for Fedora $(FEDORA_RELEASE) locally'
64
62
65 .PHONY: help
63 .PHONY: help
66
64
@@ -97,37 +95,30 b' endef'
97 $(foreach codename,$(UBUNTU_CODENAMES),$(eval $(call ubuntu_targets,$(codename))))
95 $(foreach codename,$(UBUNTU_CODENAMES),$(eval $(call ubuntu_targets,$(codename))))
98
96
99 # Fedora targets.
97 # Fedora targets.
100 define fedora_targets
98 .PHONY: fedora
101 .PHONY: fedora$(1)
99 fedora:
102 fedora$(1):
100 mkdir -p $(HGROOT)/packages/fedora$(FEDORA_RELEASE)
103 mkdir -p $$(HGROOT)/packages/fedora$(1)
104 ./buildrpm
101 ./buildrpm
105 cp $$(HGROOT)/contrib/packaging/rpmbuild/RPMS/*/* $$(HGROOT)/packages/fedora$(1)
102 cp $(HGROOT)/contrib/packaging/rpmbuild/RPMS/*/* $(HGROOT)/packages/fedora$(FEDORA_RELEASE)
106 cp $$(HGROOT)/contrib/packaging/rpmbuild/SRPMS/* $$(HGROOT)/packages/fedora$(1)
103 cp $(HGROOT)/contrib/packaging/rpmbuild/SRPMS/* $(HGROOT)/packages/fedora$(FEDORA_RELEASE)
107 rm -rf $(HGROOT)/rpmbuild
104 rm -rf $(HGROOT)/rpmbuild
108
105
109 .PHONY: docker-fedora$(1)
106 .PHONY: docker-fedora
110 docker-fedora$(1):
107 docker-fedora:
111 mkdir -p $$(HGROOT)/packages/fedora$(1)
108 ./dockerrpm fedora$(FEDORA_RELEASE)
112 ./dockerrpm fedora$(1)
113
114 endef
115
116 $(foreach release,$(FEDORA_RELEASES),$(eval $(call fedora_targets,$(release))))
117
109
118 # CentOS targets.
110 # CentOS targets.
119 define centos_targets
111 define centos_targets
120 .PHONY: centos$(1)
112 .PHONY: centos$(1)
121 centos$(1):
113 centos$(1):
122 mkdir -p $$(HGROOT)/packages/centos$(1)
114 mkdir -p $$(HGROOT)/packages/centos$(1)
123 ./buildrpm $$(if $$(filter $(1),$$(CENTOS_WITH_PYTHON_RELEASES)),--withpython)
115 ./buildrpm $$(if $$(filter $(1),$$(CENTOS_WITH_PYTHON_RELEASES)),--withpython,$$(if $$(filter $(1),$$(CENTOS_WITH_NONVERSIONED_PYTHON)),--python python,))
124 cp $$(HGROOT)/contrib/packaging/rpmbuild/RPMS/*/* $$(HGROOT)/packages/centos$(1)
116 cp $$(HGROOT)/contrib/packaging/rpmbuild/RPMS/*/* $$(HGROOT)/packages/centos$(1)
125 cp $$(HGROOT)/contrib/packaging/rpmbuild/SRPMS/* $$(HGROOT)/packages/centos$(1)
117 cp $$(HGROOT)/contrib/packaging/rpmbuild/SRPMS/* $$(HGROOT)/packages/centos$(1)
126
118
127 .PHONY: docker-centos$(1)
119 .PHONY: docker-centos$(1)
128 docker-centos$(1):
120 docker-centos$(1):
129 mkdir -p $$(HGROOT)/packages/centos$(1)
121 ./dockerrpm centos$(1) $$(if $$(filter $(1),$$(CENTOS_WITH_PYTHON_RELEASES)),--withpython,$$(if $$(filter $(1),$$(CENTOS_WITH_NONVERSIONED_PYTHON)),--python python,))
130 ./dockerrpm centos$(1) $$(if $$(filter $(1),$$(CENTOS_WITH_PYTHON_RELEASES)),--withpython)
131
122
132 endef
123 endef
133
124
@@ -106,10 +106,10 b' if [ "$CLEANUP" ] ; then'
106 echo
106 echo
107 OUTPUTDIR=${OUTPUTDIR:=packages/$DISTID-$CODENAME}
107 OUTPUTDIR=${OUTPUTDIR:=packages/$DISTID-$CODENAME}
108 mkdir -p "$OUTPUTDIR"
108 mkdir -p "$OUTPUTDIR"
109 find ../mercurial*.deb ../mercurial_*.build ../mercurial_*.changes \
109 find ../mercurial*.deb ../mercurial_*.build* ../mercurial_*.changes \
110 ../mercurial*.dsc ../mercurial*.gz \
110 ../mercurial*.dsc ../mercurial*.gz \
111 -type f -newer $control -print0 2>/dev/null | \
111 -type f -newer $control -print0 2>/dev/null | \
112 xargs -Inarf -0 mv narf "$OUTPUTDIR"
112 xargs -Inarf -0 mv narf "$OUTPUTDIR"
113 echo "Built packages for $debver:"
113 echo "Built packages for $debver:"
114 find "$PWD"/"$OUTPUTDIR" -type f -newer $control -name '*.deb'
114 find "$OUTPUTDIR" -type f -newer $control -name '*.deb'
115 fi
115 fi
@@ -1,16 +1,12 b''
1 #!/bin/bash -e
1 #!/bin/bash -e
2 #
2 #
3 # Build a Mercurial RPM from the current repo
3 # Build a Mercurial RPM from the current repo, mainly for Fedora/CentOS/RHEL
4 #
5 # Tested on
6 # - Fedora 20
7 # - CentOS 5
8 # - centOS 6
9
4
10 . $(dirname $0)/packagelib.sh
5 . $(dirname $0)/packagelib.sh
11
6
12 BUILD=1
7 BUILD=1
13 RPMBUILDDIR="$PWD/rpmbuild"
8 RPMBUILDDIR="$PWD/rpmbuild"
9 PYTHONEXE=python3
14
10
15 while [ "$1" ]; do
11 while [ "$1" ]; do
16 case "$1" in
12 case "$1" in
@@ -18,10 +14,16 b' while [ "$1" ]; do'
18 shift
14 shift
19 BUILD=
15 BUILD=
20 ;;
16 ;;
17 --python)
18 shift
19 PYTHONEXE=$1
20 shift
21 ;;
21 --withpython | --with-python)
22 --withpython | --with-python)
22 shift
23 shift
23 PYTHONVER=2.7.16
24 PYTHONVER=2.7.16
24 PYTHONMD5=f1a2ace631068444831d01485466ece0
25 PYTHONMD5=f1a2ace631068444831d01485466ece0
26 PYTHONEXE=python
25 ;;
27 ;;
26 --rpmbuilddir )
28 --rpmbuilddir )
27 shift
29 shift
@@ -51,7 +53,7 b' fi'
51 gethgversion
53 gethgversion
52
54
53 if [ -z "$type" ] ; then
55 if [ -z "$type" ] ; then
54 release=1
56 release=1
55 else
57 else
56 release=0.9_$type
58 release=0.9_$type
57 fi
59 fi
@@ -96,6 +98,7 b' rpmspec=$RPMBUILDDIR/SPECS/mercurial.spe'
96
98
97 sed -e "s,^Version:.*,Version: $version," \
99 sed -e "s,^Version:.*,Version: $version," \
98 -e "s,^Release:.*,Release: $release," \
100 -e "s,^Release:.*,Release: $release," \
101 -e "s/^%global pythonexe .*/%global pythonexe $PYTHONEXE/" \
99 $specfile > $rpmspec
102 $specfile > $rpmspec
100
103
101 echo >> $rpmspec
104 echo >> $rpmspec
@@ -121,8 +124,8 b' for l in sorted(changelog, reverse=True)'
121 if prevtitle != title:
124 if prevtitle != title:
122 prevtitle = title
125 prevtitle = title
123 print
126 print
124 print title
127 print(title)
125 print "- %s" % l[3].strip()
128 print("- %s" % l[3].strip())
126 ' >> $rpmspec
129 ' >> $rpmspec
127
130
128 else
131 else
@@ -138,7 +141,7 b' def datestr(date, format):'
138 for l in sys.stdin.readlines():
141 for l in sys.stdin.readlines():
139 tok = l.split("\t")
142 tok = l.split("\t")
140 hgdate = tuple(int(v) for v in tok[0].split())
143 hgdate = tuple(int(v) for v in tok[0].split())
141 print "* %s %s\n- %s" % (datestr(hgdate, "%a %b %d %Y"), tok[1], tok[2])
144 print("* %s %s\n- %s" % (datestr(hgdate, "%a %b %d %Y"), tok[1], tok[2]))
142 ' >> $rpmspec
145 ' >> $rpmspec
143
146
144 fi
147 fi
@@ -7,21 +7,24 b' Build-Depends:'
7 dh-python,
7 dh-python,
8 less,
8 less,
9 netbase,
9 netbase,
10 python-all,
10 python3-all,
11 python-all-dev,
11 python3-all-dev,
12 python-docutils,
12 python3-docutils,
13 unzip,
13 unzip,
14 zip
14 zip
15 Standards-Version: 3.9.4
15 Standards-Version: 3.9.4
16 X-Python-Version: >= 2.7
16 X-Python3-Version: >= 3.5
17
17
18 Package: mercurial
18 Package: mercurial
19 Depends:
19 Depends:
20 python,
20 sensible-utils,
21 ${shlibs:Depends},
21 ${shlibs:Depends},
22 ${misc:Depends},
22 ${misc:Depends},
23 ${python:Depends},
23 ${python3:Depends},
24 mercurial-common (= ${source:Version})
24 Recommends: ca-certificates
25 Suggests: wish
26 Replaces: mercurial-common
27 Breaks: mercurial-common
25 Architecture: any
28 Architecture: any
26 Description: fast, easy to use, distributed revision control tool.
29 Description: fast, easy to use, distributed revision control tool.
27 Mercurial is a fast, lightweight Source Control Management system designed
30 Mercurial is a fast, lightweight Source Control Management system designed
@@ -36,19 +39,3 b' Description: fast, easy to use, distribu'
36 * Easy-to-use command-line interface
39 * Easy-to-use command-line interface
37 * Integrated stand-alone web interface
40 * Integrated stand-alone web interface
38 * Small Python codebase
41 * Small Python codebase
39
40 Package: mercurial-common
41 Architecture: all
42 Depends:
43 ${misc:Depends},
44 ${python:Depends},
45 Recommends: mercurial (= ${source:Version}), ca-certificates
46 Suggests: wish
47 Breaks: mercurial (<< ${source:Version})
48 Replaces: mercurial (<< 2.6.3)
49 Description: easy-to-use, scalable distributed version control system (common files)
50 Mercurial is a fast, lightweight Source Control Management system designed
51 for efficient handling of very large distributed projects.
52 .
53 This package contains the architecture independent components of Mercurial,
54 and is generally useless without the mercurial package.
@@ -4,41 +4,41 b''
4
4
5 CPUS=$(shell cat /proc/cpuinfo | grep -E ^processor | wc -l)
5 CPUS=$(shell cat /proc/cpuinfo | grep -E ^processor | wc -l)
6
6
7 export HGPYTHON3=1
8 export PYTHON=python3
9
7 %:
10 %:
8 dh $@ --with python2
11 dh $@ --with python3
9
12
10 override_dh_auto_test:
13 override_dh_auto_test:
11 http_proxy='' dh_auto_test -- TESTFLAGS="-j$(CPUS)"
14 http_proxy='' dh_auto_test -- TESTFLAGS="-j$(CPUS)"
12
15
13 override_dh_python2:
16 override_dh_python3:
14 dh_python2
17 dh_python3 --shebang=/usr/bin/python3
15 find debian/mercurial/usr/share -type d -empty -delete
18
19 override_dh_auto_clean:
20 $(MAKE) cleanbutpackages
21 $(MAKE) -C contrib/chg clean
16
22
17 override_dh_install:
23 override_dh_auto_build:
18 python$(PYVERS) setup.py install --root "$(CURDIR)"/debian/mercurial --install-layout=deb
24 $(MAKE) all
25 $(MAKE) -C contrib/chg all
26
27 override_dh_auto_install:
28 python3 setup.py install --root "$(CURDIR)"/debian/mercurial --install-layout=deb
19 # chg
29 # chg
20 make -C contrib/chg \
30 make -C contrib/chg \
21 DESTDIR="$(CURDIR)"/debian/mercurial \
31 DESTDIR="$(CURDIR)"/debian/mercurial \
22 PREFIX=/usr \
32 PREFIX=/usr \
23 clean install
33 install
24 # remove arch-independent python stuff
34 make install-doc PREFIX="$(CURDIR)"/debian/mercurial/usr
25 find "$(CURDIR)"/debian/mercurial/usr/lib \
35 cp contrib/hg-ssh "$(CURDIR)"/debian/mercurial/usr/bin
26 ! -name '*.so' ! -type d -delete , \
36 mkdir -p "$(CURDIR)"/debian/mercurial/usr/share/mercurial
27 -type d -empty -delete
37 cp contrib/hgk "$(CURDIR)"/debian/mercurial/usr/share/mercurial
28 python$(PYVERS) setup.py install --root "$(CURDIR)/debian/mercurial-common" --install-layout=deb
38 mkdir -p "$(CURDIR)"/debian/mercurial/etc/mercurial/hgrc.d/
29 make install-doc PREFIX="$(CURDIR)"/debian/mercurial-common/usr
39 cp contrib/packaging/debian/*.rc "$(CURDIR)"/debian/mercurial/etc/mercurial/hgrc.d/
30 # remove arch-dependent python stuff
31 find "$(CURDIR)"/debian/mercurial-common/usr/lib \
32 -name '*.so' ! -type d -delete , \
33 -type d -empty -delete
34 cp contrib/hg-ssh "$(CURDIR)"/debian/mercurial-common/usr/bin
35 mkdir -p "$(CURDIR)"/debian/mercurial-common/usr/share/mercurial
36 cp contrib/hgk "$(CURDIR)"/debian/mercurial-common/usr/share/mercurial
37 mkdir -p "$(CURDIR)"/debian/mercurial-common/etc/mercurial/hgrc.d/
38 cp contrib/packaging/debian/*.rc "$(CURDIR)"/debian/mercurial-common/etc/mercurial/hgrc.d/
39 # completions
40 # completions
40 mkdir -p "$(CURDIR)"/debian/mercurial-common/usr/share/bash-completion/completions
41 mkdir -p "$(CURDIR)"/debian/mercurial/usr/share/bash-completion/completions
41 cp contrib/bash_completion "$(CURDIR)"/debian/mercurial-common/usr/share/bash-completion/completions/hg
42 cp contrib/bash_completion "$(CURDIR)"/debian/mercurial/usr/share/bash-completion/completions/hg
42 mkdir -p "$(CURDIR)"/debian/mercurial-common/usr/share/zsh/vendor-completions
43 mkdir -p "$(CURDIR)"/debian/mercurial/usr/share/zsh/vendor-completions
43 cp contrib/zsh_completion "$(CURDIR)"/debian/mercurial-common/usr/share/zsh/vendor-completions/_hg
44 cp contrib/zsh_completion "$(CURDIR)"/debian/mercurial/usr/share/zsh/vendor-completions/_hg
44 rm "$(CURDIR)"/debian/mercurial-common/usr/bin/hg
@@ -1,4 +1,4 b''
1 FROM fedora:29
1 FROM fedora:%OS_RELEASE%
2
2
3 RUN groupadd -g 1000 build && \
3 RUN groupadd -g 1000 build && \
4 useradd -u 1000 -g 1000 -s /bin/bash -d /build -m build
4 useradd -u 1000 -g 1000 -s /bin/bash -d /build -m build
@@ -7,8 +7,8 b' RUN dnf install -y \\'
7 gcc \
7 gcc \
8 gettext \
8 gettext \
9 make \
9 make \
10 python-devel \
10 python3-devel \
11 python-docutils \
11 python3-docutils \
12 rpm-build
12 rpm-build
13
13
14 # For creating repo meta data
14 # For creating repo meta data
@@ -6,6 +6,14 b' export ROOTDIR=$(cd $BUILDDIR/../..; pwd'
6 PLATFORM="$1"
6 PLATFORM="$1"
7 shift # extra params are passed to buildrpm
7 shift # extra params are passed to buildrpm
8
8
9 DOCKERFILE="$PLATFORM"
10 OS_RELEASE="${PLATFORM//[a-z]/}"
11 case "$PLATFORM" in
12 fedora*)
13 DOCKERFILE="${PLATFORM//[0-9]/}.template"
14 ;;
15 esac
16
9 DOCKER=$($BUILDDIR/hg-docker docker-path)
17 DOCKER=$($BUILDDIR/hg-docker docker-path)
10
18
11 CONTAINER=hg-docker-$PLATFORM
19 CONTAINER=hg-docker-$PLATFORM
@@ -18,9 +26,14 b' else'
18 DOCKERGID=$(id -g)
26 DOCKERGID=$(id -g)
19 fi
27 fi
20
28
21 $BUILDDIR/hg-docker build --build-arg UID=$DOCKERUID --build-arg GID=$DOCKERGID $BUILDDIR/docker/$PLATFORM $CONTAINER
29 $BUILDDIR/hg-docker build \
30 --build-arg UID=$DOCKERUID \
31 --build-arg GID=$DOCKERGID \
32 --build-arg OS_RELEASE=${OS_RELEASE:-latest} \
33 $BUILDDIR/docker/$DOCKERFILE $CONTAINER
22
34
23 RPMBUILDDIR=$ROOTDIR/packages/$PLATFORM
35 RPMBUILDDIR=$ROOTDIR/packages/$PLATFORM
36 mkdir -p $RPMBUILDDIR
24 $ROOTDIR/contrib/packaging/buildrpm --rpmbuilddir $RPMBUILDDIR --prepare $*
37 $ROOTDIR/contrib/packaging/buildrpm --rpmbuilddir $RPMBUILDDIR --prepare $*
25
38
26 DSHARED=/mnt/shared
39 DSHARED=/mnt/shared
@@ -2,37 +2,119 b''
2 # This file is autogenerated by pip-compile
2 # This file is autogenerated by pip-compile
3 # To update, run:
3 # To update, run:
4 #
4 #
5 # pip-compile --generate-hashes contrib/packaging/inno/requirements.txt.in -o contrib/packaging/inno/requirements.txt
5 # pip-compile --generate-hashes --output-file=contrib/packaging/inno/requirements.txt contrib/packaging/inno/requirements.txt.in
6 #
6 #
7 certifi==2018.11.29 \
7 certifi==2019.9.11 \
8 --hash=sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7 \
8 --hash=sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50 \
9 --hash=sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033 \
9 --hash=sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef \
10 # via dulwich
10 # via dulwich
11 configparser==3.7.3 \
11 cffi==1.13.1 \
12 --hash=sha256:27594cf4fc279f321974061ac69164aaebd2749af962ac8686b20503ac0bcf2d \
12 --hash=sha256:00d890313797d9fe4420506613384b43099ad7d2b905c0752dbcc3a6f14d80fa \
13 --hash=sha256:9d51fe0a382f05b6b117c5e601fc219fede4a8c71703324af3f7d883aef476a3 \
13 --hash=sha256:0cf9e550ac6c5e57b713437e2f4ac2d7fd0cd10336525a27224f5fc1ec2ee59a \
14 --hash=sha256:0ea23c9c0cdd6778146a50d867d6405693ac3b80a68829966c98dd5e1bbae400 \
15 --hash=sha256:193697c2918ecdb3865acf6557cddf5076bb39f1f654975e087b67efdff83365 \
16 --hash=sha256:1ae14b542bf3b35e5229439c35653d2ef7d8316c1fffb980f9b7647e544baa98 \
17 --hash=sha256:1e389e069450609c6ffa37f21f40cce36f9be7643bbe5051ab1de99d5a779526 \
18 --hash=sha256:263242b6ace7f9cd4ea401428d2d45066b49a700852334fd55311bde36dcda14 \
19 --hash=sha256:33142ae9807665fa6511cfa9857132b2c3ee6ddffb012b3f0933fc11e1e830d5 \
20 --hash=sha256:364f8404034ae1b232335d8c7f7b57deac566f148f7222cef78cf8ae28ef764e \
21 --hash=sha256:47368f69fe6529f8f49a5d146ddee713fc9057e31d61e8b6dc86a6a5e38cecc1 \
22 --hash=sha256:4895640844f17bec32943995dc8c96989226974dfeb9dd121cc45d36e0d0c434 \
23 --hash=sha256:558b3afef987cf4b17abd849e7bedf64ee12b28175d564d05b628a0f9355599b \
24 --hash=sha256:5ba86e1d80d458b338bda676fd9f9d68cb4e7a03819632969cf6d46b01a26730 \
25 --hash=sha256:63424daa6955e6b4c70dc2755897f5be1d719eabe71b2625948b222775ed5c43 \
26 --hash=sha256:6381a7d8b1ebd0bc27c3bc85bc1bfadbb6e6f756b4d4db0aa1425c3719ba26b4 \
27 --hash=sha256:6381ab708158c4e1639da1f2a7679a9bbe3e5a776fc6d1fd808076f0e3145331 \
28 --hash=sha256:6fd58366747debfa5e6163ada468a90788411f10c92597d3b0a912d07e580c36 \
29 --hash=sha256:728ec653964655d65408949b07f9b2219df78badd601d6c49e28d604efe40599 \
30 --hash=sha256:7cfcfda59ef1f95b9f729c56fe8a4041899f96b72685d36ef16a3440a0f85da8 \
31 --hash=sha256:819f8d5197c2684524637f940445c06e003c4a541f9983fd30d6deaa2a5487d8 \
32 --hash=sha256:825ecffd9574557590e3225560a8a9d751f6ffe4a49e3c40918c9969b93395fa \
33 --hash=sha256:9009e917d8f5ef780c2626e29b6bc126f4cb2a4d43ca67aa2b40f2a5d6385e78 \
34 --hash=sha256:9c77564a51d4d914ed5af096cd9843d90c45b784b511723bd46a8a9d09cf16fc \
35 --hash=sha256:a19089fa74ed19c4fe96502a291cfdb89223a9705b1d73b3005df4256976142e \
36 --hash=sha256:a40ed527bffa2b7ebe07acc5a3f782da072e262ca994b4f2085100b5a444bbb2 \
37 --hash=sha256:bb75ba21d5716abc41af16eac1145ab2e471deedde1f22c6f99bd9f995504df0 \
38 --hash=sha256:e22a00c0c81ffcecaf07c2bfb3672fa372c50e2bd1024ffee0da191c1b27fc71 \
39 --hash=sha256:e55b5a746fb77f10c83e8af081979351722f6ea48facea79d470b3731c7b2891 \
40 --hash=sha256:ec2fa3ee81707a5232bf2dfbd6623fdb278e070d596effc7e2d788f2ada71a05 \
41 --hash=sha256:fd82eb4694be712fcae03c717ca2e0fc720657ac226b80bbb597e971fc6928c2 \
42 # via cryptography
43 configparser==4.0.2 \
44 --hash=sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c \
45 --hash=sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df \
14 # via entrypoints
46 # via entrypoints
15 docutils==0.14 \
47 cryptography==2.8 \
16 --hash=sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6 \
48 --hash=sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c \
17 --hash=sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274 \
49 --hash=sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595 \
18 --hash=sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6
50 --hash=sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad \
19 dulwich==0.19.11 \
51 --hash=sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651 \
20 --hash=sha256:afbe070f6899357e33f63f3f3696e601731fef66c64a489dea1bc9f539f4a725
52 --hash=sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2 \
53 --hash=sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff \
54 --hash=sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d \
55 --hash=sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42 \
56 --hash=sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d \
57 --hash=sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e \
58 --hash=sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912 \
59 --hash=sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793 \
60 --hash=sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13 \
61 --hash=sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7 \
62 --hash=sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0 \
63 --hash=sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879 \
64 --hash=sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f \
65 --hash=sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9 \
66 --hash=sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2 \
67 --hash=sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf \
68 --hash=sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8 \
69 # via secretstorage
70 docutils==0.15.2 \
71 --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \
72 --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \
73 --hash=sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99
74 dulwich==0.19.13 \
75 --hash=sha256:0e442f6f96e6d97270a7cca4e75306b6b0228627bdf57dde3759e0e345a6b523 \
76 --hash=sha256:667f49536ccba09d3b90bac80d44048e45566f84b98a5e139cc8c70757a6ae60 \
77 --hash=sha256:82792a9d49b112fa2151fa0fb29b01667855a843ff99325b1c1578a4aec11b57 \
78 --hash=sha256:aa628449c5f594a9a282f4d9e5993fef65481ef5e3b9b6c52ff31200f8f5dc95 \
79 --hash=sha256:ab4668bc4e1996d12eb1910e123a09edcff8e166e7ec46db5aafb5c7e250b99f \
80 --hash=sha256:c35ed2cd5b263ce0d67758ffba590c0466ff13b048457ff060b7d2e6cb55a40e \
81 --hash=sha256:c8b48079a14850cbeb788b38e1061ae6db75061431c1c0f91382460be4c84bbe \
82 --hash=sha256:dfcd9943c69f963dd61a027f480d16f548ea5905c2485be8f4b8f130df2c32de \
83 --hash=sha256:e3693c3238c1a5fc1e4427281c4455d78549f4797f2a7107a5f4443b21efafb4
21 entrypoints==0.3 \
84 entrypoints==0.3 \
22 --hash=sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19 \
85 --hash=sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19 \
23 --hash=sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451 \
86 --hash=sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451 \
24 # via keyring
87 # via keyring
88 enum34==1.1.6 \
89 --hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
90 --hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
91 --hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
92 --hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1 \
93 # via cryptography
94 ipaddress==1.0.23 \
95 --hash=sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc \
96 --hash=sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2 \
97 # via cryptography
25 keyring==18.0.1 \
98 keyring==18.0.1 \
26 --hash=sha256:67d6cc0132bd77922725fae9f18366bb314fd8f95ff4d323a4df41890a96a838 \
99 --hash=sha256:67d6cc0132bd77922725fae9f18366bb314fd8f95ff4d323a4df41890a96a838 \
27 --hash=sha256:7b29ebfcf8678c4da531b2478a912eea01e80007e5ddca9ee0c7038cb3489ec6
100 --hash=sha256:7b29ebfcf8678c4da531b2478a912eea01e80007e5ddca9ee0c7038cb3489ec6
28 pygments==2.3.1 \
101 pycparser==2.19 \
29 --hash=sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a \
102 --hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3 \
30 --hash=sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d
103 # via cffi
104 pygments==2.4.2 \
105 --hash=sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127 \
106 --hash=sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297
31 pywin32-ctypes==0.2.0 \
107 pywin32-ctypes==0.2.0 \
32 --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
108 --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
33 --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 \
109 --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98
110 secretstorage==2.3.1 \
111 --hash=sha256:3af65c87765323e6f64c83575b05393f9e003431959c9395d1791d51497f29b6 \
34 # via keyring
112 # via keyring
35 urllib3==1.24.1 \
113 six==1.12.0 \
36 --hash=sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39 \
114 --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
37 --hash=sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22 \
115 --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 \
116 # via cryptography
117 urllib3==1.25.6 \
118 --hash=sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398 \
119 --hash=sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86 \
38 # via dulwich
120 # via dulwich
@@ -2,3 +2,6 b' docutils'
2 dulwich
2 dulwich
3 keyring
3 keyring
4 pygments
4 pygments
5 # Need to list explicitly so dependency gets pulled in when
6 # not running on Windows.
7 pywin32-ctypes
@@ -2,6 +2,8 b''
2
2
3 %define withpython %{nil}
3 %define withpython %{nil}
4
4
5 %global pythonexe python3
6
5 %if "%{?withpython}"
7 %if "%{?withpython}"
6
8
7 %global pythonver %{withpython}
9 %global pythonver %{withpython}
@@ -15,7 +17,7 b''
15
17
16 %else
18 %else
17
19
18 %global pythonver %(python -c 'import sys;print ".".join(map(str, sys.version_info[:2]))')
20 %global pythonver %(%{pythonexe} -c 'import sys;print(".".join(map(str, sys.version_info[:2])))')
19
21
20 %endif
22 %endif
21
23
@@ -37,8 +39,8 b' BuildRequires: make, gcc, gettext'
37 %if "%{?withpython}"
39 %if "%{?withpython}"
38 BuildRequires: readline-devel, openssl-devel, ncurses-devel, zlib-devel, bzip2-devel
40 BuildRequires: readline-devel, openssl-devel, ncurses-devel, zlib-devel, bzip2-devel
39 %else
41 %else
40 BuildRequires: python >= 2.7, python-devel, python-docutils >= 0.5
42 BuildRequires: %{pythonexe} >= %{pythonver}, %{pythonexe}-devel, %{pythonexe}-docutils >= 0.5
41 Requires: python >= 2.7
43 Requires: %{pythonexe} >= %{pythonver}
42 %endif
44 %endif
43 # The hgk extension uses the wish tcl interpreter, but we don't enforce it
45 # The hgk extension uses the wish tcl interpreter, but we don't enforce it
44 #Requires: tk
46 #Requires: tk
@@ -52,13 +54,15 b' for efficient handling of very large dis'
52 %if "%{?withpython}"
54 %if "%{?withpython}"
53 %setup -q -n mercurial-%{version}-%{release} -a1 -a2
55 %setup -q -n mercurial-%{version}-%{release} -a1 -a2
54 # despite the comments in cgi.py, we do this to prevent rpmdeps from picking /usr/local/bin/python up
56 # despite the comments in cgi.py, we do this to prevent rpmdeps from picking /usr/local/bin/python up
55 sed -i '1c#! /usr/bin/env python' %{pythonname}/Lib/cgi.py
57 sed -i '1c#! /usr/bin/env %{pythonexe}' %{pythonname}/Lib/cgi.py
56 %else
58 %else
57 %setup -q -n mercurial-%{version}-%{release}
59 %setup -q -n mercurial-%{version}-%{release}
58 %endif
60 %endif
59
61
60 %build
62 %build
61
63
64 export HGPYTHON3=1
65
62 %if "%{?withpython}"
66 %if "%{?withpython}"
63
67
64 PYPATH=$PWD/%{pythonname}
68 PYPATH=$PWD/%{pythonname}
@@ -82,12 +86,16 b' export PYTHONPATH=$PWD/%{docutilsname}'
82
86
83 %endif
87 %endif
84
88
85 make all
89 make all PYTHON=%{pythonexe}
86 make -C contrib/chg
90 make -C contrib/chg
87
91
92 sed -i -e '1s|#!/usr/bin/env python$|#!/usr/bin/env %{pythonexe}|' contrib/hg-ssh
93
88 %install
94 %install
89 rm -rf $RPM_BUILD_ROOT
95 rm -rf $RPM_BUILD_ROOT
90
96
97 export HGPYTHON3=1
98
91 %if "%{?withpython}"
99 %if "%{?withpython}"
92
100
93 PYPATH=$PWD/%{pythonname}
101 PYPATH=$PWD/%{pythonname}
@@ -101,14 +109,14 b' cd %{docutilsname}'
101 LD_LIBRARY_PATH=$PYPATH $PYPATH/python setup.py install --root="$RPM_BUILD_ROOT"
109 LD_LIBRARY_PATH=$PYPATH $PYPATH/python setup.py install --root="$RPM_BUILD_ROOT"
102 cd -
110 cd -
103
111
104 PATH=$PYPATH:$PATH LD_LIBRARY_PATH=$PYPATH make install DESTDIR=$RPM_BUILD_ROOT PREFIX=%{hgpyprefix} MANDIR=%{_mandir}
112 PATH=$PYPATH:$PATH LD_LIBRARY_PATH=$PYPATH make install PYTHON=%{pythonexe} DESTDIR=$RPM_BUILD_ROOT PREFIX=%{hgpyprefix} MANDIR=%{_mandir}
105 mkdir -p $RPM_BUILD_ROOT%{_bindir}
113 mkdir -p $RPM_BUILD_ROOT%{_bindir}
106 ( cd $RPM_BUILD_ROOT%{_bindir}/ && ln -s ../..%{hgpyprefix}/bin/hg . )
114 ( cd $RPM_BUILD_ROOT%{_bindir}/ && ln -s ../..%{hgpyprefix}/bin/hg . )
107 ( cd $RPM_BUILD_ROOT%{_bindir}/ && ln -s ../..%{hgpyprefix}/bin/python2.? %{pythonhg} )
115 ( cd $RPM_BUILD_ROOT%{_bindir}/ && ln -s ../..%{hgpyprefix}/bin/python2.? %{pythonhg} )
108
116
109 %else
117 %else
110
118
111 make install DESTDIR=$RPM_BUILD_ROOT PREFIX=%{_prefix} MANDIR=%{_mandir}
119 make install PYTHON=%{pythonexe} DESTDIR=$RPM_BUILD_ROOT PREFIX=%{_prefix} MANDIR=%{_mandir}
112
120
113 %endif
121 %endif
114
122
@@ -135,7 +143,7 b' rm -rf $RPM_BUILD_ROOT'
135
143
136 %files
144 %files
137 %defattr(-,root,root,-)
145 %defattr(-,root,root,-)
138 %doc CONTRIBUTORS COPYING doc/README doc/hg*.txt doc/hg*.html *.cgi contrib/*.fcgi
146 %doc CONTRIBUTORS COPYING doc/README doc/hg*.txt doc/hg*.html *.cgi contrib/*.fcgi contrib/*.wsgi
139 %doc %attr(644,root,root) %{_mandir}/man?/hg*
147 %doc %attr(644,root,root) %{_mandir}/man?/hg*
140 %doc %attr(644,root,root) contrib/*.svg
148 %doc %attr(644,root,root) contrib/*.svg
141 %dir %{_datadir}/zsh/
149 %dir %{_datadir}/zsh/
@@ -2,12 +2,12 b''
2 # This file is autogenerated by pip-compile
2 # This file is autogenerated by pip-compile
3 # To update, run:
3 # To update, run:
4 #
4 #
5 # pip-compile --generate-hashes contrib/packaging/wix/requirements.txt.in -o contrib/packaging/wix/requirements.txt
5 # pip-compile --generate-hashes --output-file=contrib/packaging/wix/requirements.txt contrib/packaging/wix/requirements.txt.in
6 #
6 #
7 docutils==0.14 \
7 docutils==0.15.2 \
8 --hash=sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6 \
8 --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \
9 --hash=sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274 \
9 --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \
10 --hash=sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6
10 --hash=sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99
11 pygments==2.3.1 \
11 pygments==2.4.2 \
12 --hash=sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a \
12 --hash=sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127 \
13 --hash=sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d
13 --hash=sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297
@@ -18,6 +18,7 b' from mercurial import ('
18 )
18 )
19 from mercurial.utils import (
19 from mercurial.utils import (
20 procutil,
20 procutil,
21 stringutil
21 )
22 )
22
23
23 options = [(b'L', b'label', [], _(b'labels to use on conflict markers')),
24 options = [(b'L', b'label', [], _(b'labels to use on conflict markers')),
@@ -75,8 +76,7 b' try:'
75 context.arbitraryfilectx(other),
76 context.arbitraryfilectx(other),
76 **pycompat.strkwargs(opts)))
77 **pycompat.strkwargs(opts)))
77 except ParseError as e:
78 except ParseError as e:
78 if pycompat.ispy3:
79 e = stringutil.forcebytestr(e)
79 e = str(e).encode('utf8')
80 pycompat.stdout.write(b"%s: %s\n" % (sys.argv[0].encode('utf8'), e))
80 pycompat.stdout.write(b"%s: %s\n" % (sys.argv[0].encode('utf8'), e))
81 showhelp()
81 showhelp()
82 sys.exit(1)
82 sys.exit(1)
@@ -53,9 +53,13 b' class _lazyloaderex(importlib.util.LazyL'
53
53
54 # This is 3.6+ because with Python 3.5 it isn't possible to lazily load
54 # This is 3.6+ because with Python 3.5 it isn't possible to lazily load
55 # extensions. See the discussion in https://bugs.python.org/issue26186 for more.
55 # extensions. See the discussion in https://bugs.python.org/issue26186 for more.
56 _extensions_loader = _lazyloaderex.factory(
56 if sys.version_info[0:2] >= (3, 6):
57 importlib.machinery.ExtensionFileLoader
57 _extensions_loader = _lazyloaderex.factory(
58 )
58 importlib.machinery.ExtensionFileLoader
59 )
60 else:
61 _extensions_loader = importlib.machinery.ExtensionFileLoader
62
59 _bytecode_loader = _lazyloaderex.factory(
63 _bytecode_loader = _lazyloaderex.factory(
60 importlib.machinery.SourcelessFileLoader
64 importlib.machinery.SourcelessFileLoader
61 )
65 )
@@ -955,7 +955,7 b' class bzrestapi(bzaccess):'
955 def _fetch(self, burl):
955 def _fetch(self, burl):
956 try:
956 try:
957 resp = url.open(self.ui, burl)
957 resp = url.open(self.ui, burl)
958 return json.loads(resp.read())
958 return pycompat.json_loads(resp.read())
959 except util.urlerr.httperror as inst:
959 except util.urlerr.httperror as inst:
960 if inst.code == 401:
960 if inst.code == 401:
961 raise error.Abort(_(b'authorization failed'))
961 raise error.Abort(_(b'authorization failed'))
@@ -978,7 +978,7 b' class bzrestapi(bzaccess):'
978 req = request_type(burl, data, {b'Content-Type': b'application/json'})
978 req = request_type(burl, data, {b'Content-Type': b'application/json'})
979 try:
979 try:
980 resp = url.opener(self.ui).open(req)
980 resp = url.opener(self.ui).open(req)
981 return json.loads(resp.read())
981 return pycompat.json_loads(resp.read())
982 except util.urlerr.httperror as inst:
982 except util.urlerr.httperror as inst:
983 if inst.code == 401:
983 if inst.code == 401:
984 raise error.Abort(_(b'authorization failed'))
984 raise error.Abort(_(b'authorization failed'))
@@ -7,7 +7,6 b''
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import email.parser as emailparser
11 import os
10 import os
12 import shutil
11 import shutil
13 import stat
12 import stat
@@ -17,6 +16,7 b' from mercurial.i18n import _'
17 from mercurial import (
16 from mercurial import (
18 encoding,
17 encoding,
19 error,
18 error,
19 mail,
20 pycompat,
20 pycompat,
21 util,
21 util,
22 )
22 )
@@ -69,7 +69,6 b' class gnuarch_source(common.converter_so'
69 self.changes = {}
69 self.changes = {}
70 self.parents = {}
70 self.parents = {}
71 self.tags = {}
71 self.tags = {}
72 self.catlogparser = emailparser.Parser()
73 self.encoding = encoding.encoding
72 self.encoding = encoding.encoding
74 self.archives = []
73 self.archives = []
75
74
@@ -299,26 +298,29 b' class gnuarch_source(common.converter_so'
299
298
300 def _parsecatlog(self, data, rev):
299 def _parsecatlog(self, data, rev):
301 try:
300 try:
302 catlog = self.catlogparser.parsestr(data)
301 catlog = mail.parsebytes(data)
303
302
304 # Commit date
303 # Commit date
305 self.changes[rev].date = dateutil.datestr(
304 self.changes[rev].date = dateutil.datestr(
306 dateutil.strdate(catlog[b'Standard-date'], b'%Y-%m-%d %H:%M:%S')
305 dateutil.strdate(catlog[r'Standard-date'], b'%Y-%m-%d %H:%M:%S')
307 )
306 )
308
307
309 # Commit author
308 # Commit author
310 self.changes[rev].author = self.recode(catlog[b'Creator'])
309 self.changes[rev].author = self.recode(catlog[r'Creator'])
311
310
312 # Commit description
311 # Commit description
313 self.changes[rev].summary = b'\n\n'.join(
312 self.changes[rev].summary = b'\n\n'.join(
314 (catlog[b'Summary'], catlog.get_payload())
313 (
314 self.recode(catlog[r'Summary']),
315 self.recode(catlog.get_payload()),
316 )
315 )
317 )
316 self.changes[rev].summary = self.recode(self.changes[rev].summary)
318 self.changes[rev].summary = self.recode(self.changes[rev].summary)
317
319
318 # Commit revision origin when dealing with a branch or tag
320 # Commit revision origin when dealing with a branch or tag
319 if b'Continuation-of' in catlog:
321 if r'Continuation-of' in catlog:
320 self.changes[rev].continuationof = self.recode(
322 self.changes[rev].continuationof = self.recode(
321 catlog[b'Continuation-of']
323 catlog[r'Continuation-of']
322 )
324 )
323 except Exception:
325 except Exception:
324 raise error.Abort(_(b'could not parse cat-log of %s') % rev)
326 raise error.Abort(_(b'could not parse cat-log of %s') % rev)
@@ -126,7 +126,6 b' from __future__ import absolute_import'
126
126
127 import collections
127 import collections
128 import itertools
128 import itertools
129 import json
130 import os
129 import os
131 import re
130 import re
132 import subprocess
131 import subprocess
@@ -642,7 +641,7 b' def fixfile(ui, repo, opts, fixers, fixc'
642 if fixer.shouldoutputmetadata():
641 if fixer.shouldoutputmetadata():
643 try:
642 try:
644 metadatajson, newerdata = stdout.split(b'\0', 1)
643 metadatajson, newerdata = stdout.split(b'\0', 1)
645 metadata[fixername] = json.loads(metadatajson)
644 metadata[fixername] = pycompat.json_loads(metadatajson)
646 except ValueError:
645 except ValueError:
647 ui.warn(
646 ui.warn(
648 _(b'ignored invalid output from fixer tool: %s\n')
647 _(b'ignored invalid output from fixer tool: %s\n')
@@ -132,6 +132,7 b' from mercurial import ('
132 util,
132 util,
133 )
133 )
134 from mercurial import match as matchmod
134 from mercurial import match as matchmod
135 from mercurial.utils import stringutil
135
136
136 from . import (
137 from . import (
137 pywatchman,
138 pywatchman,
@@ -189,10 +190,10 b' def debuginstall(ui, fm):'
189 fm.write(
190 fm.write(
190 b"fsmonitor-watchman-version",
191 b"fsmonitor-watchman-version",
191 _(b" watchman binary version %s\n"),
192 _(b" watchman binary version %s\n"),
192 v[b"version"],
193 pycompat.bytestr(v["version"]),
193 )
194 )
194 except watchmanclient.Unavailable as e:
195 except watchmanclient.Unavailable as e:
195 err = str(e)
196 err = stringutil.forcebytestr(e)
196 fm.condwrite(
197 fm.condwrite(
197 err,
198 err,
198 b"fsmonitor-watchman-error",
199 b"fsmonitor-watchman-error",
@@ -207,15 +208,23 b' def _handleunavailable(ui, state, ex):'
207 if isinstance(ex, watchmanclient.Unavailable):
208 if isinstance(ex, watchmanclient.Unavailable):
208 # experimental config: fsmonitor.verbose
209 # experimental config: fsmonitor.verbose
209 if ex.warn and ui.configbool(b'fsmonitor', b'verbose'):
210 if ex.warn and ui.configbool(b'fsmonitor', b'verbose'):
210 if b'illegal_fstypes' not in str(ex):
211 if b'illegal_fstypes' not in stringutil.forcebytestr(ex):
211 ui.warn(str(ex) + b'\n')
212 ui.warn(stringutil.forcebytestr(ex) + b'\n')
212 if ex.invalidate:
213 if ex.invalidate:
213 state.invalidate()
214 state.invalidate()
214 # experimental config: fsmonitor.verbose
215 # experimental config: fsmonitor.verbose
215 if ui.configbool(b'fsmonitor', b'verbose'):
216 if ui.configbool(b'fsmonitor', b'verbose'):
216 ui.log(b'fsmonitor', b'Watchman unavailable: %s\n', ex.msg)
217 ui.log(
218 b'fsmonitor',
219 b'Watchman unavailable: %s\n',
220 stringutil.forcebytestr(ex.msg),
221 )
217 else:
222 else:
218 ui.log(b'fsmonitor', b'Watchman exception: %s\n', ex)
223 ui.log(
224 b'fsmonitor',
225 b'Watchman exception: %s\n',
226 stringutil.forcebytestr(ex),
227 )
219
228
220
229
221 def _hashignore(ignore):
230 def _hashignore(ignore):
@@ -227,8 +236,8 b' def _hashignore(ignore):'
227
236
228 """
237 """
229 sha1 = hashlib.sha1()
238 sha1 = hashlib.sha1()
230 sha1.update(repr(ignore))
239 sha1.update(pycompat.byterepr(ignore))
231 return sha1.hexdigest()
240 return pycompat.sysbytes(sha1.hexdigest())
232
241
233
242
234 _watchmanencoding = pywatchman.encoding.get_local_encoding()
243 _watchmanencoding = pywatchman.encoding.get_local_encoding()
@@ -245,12 +254,14 b' def _watchmantofsencoding(path):'
245 try:
254 try:
246 decoded = path.decode(_watchmanencoding)
255 decoded = path.decode(_watchmanencoding)
247 except UnicodeDecodeError as e:
256 except UnicodeDecodeError as e:
248 raise error.Abort(str(e), hint=b'watchman encoding error')
257 raise error.Abort(
258 stringutil.forcebytestr(e), hint=b'watchman encoding error'
259 )
249
260
250 try:
261 try:
251 encoded = decoded.encode(_fsencoding, 'strict')
262 encoded = decoded.encode(_fsencoding, 'strict')
252 except UnicodeEncodeError as e:
263 except UnicodeEncodeError as e:
253 raise error.Abort(str(e))
264 raise error.Abort(stringutil.forcebytestr(e))
254
265
255 return encoded
266 return encoded
256
267
@@ -372,7 +383,7 b' def overridewalk(orig, self, match, subr'
372 else:
383 else:
373 # We need to propagate the last observed clock up so that we
384 # We need to propagate the last observed clock up so that we
374 # can use it for our next query
385 # can use it for our next query
375 state.setlastclock(result[b'clock'])
386 state.setlastclock(pycompat.sysbytes(result[b'clock']))
376 if result[b'is_fresh_instance']:
387 if result[b'is_fresh_instance']:
377 if state.walk_on_invalidate:
388 if state.walk_on_invalidate:
378 state.invalidate()
389 state.invalidate()
@@ -396,8 +407,15 b' def overridewalk(orig, self, match, subr'
396 # for name case changes.
407 # for name case changes.
397 for entry in result[b'files']:
408 for entry in result[b'files']:
398 fname = entry[b'name']
409 fname = entry[b'name']
410
411 # Watchman always give us a str. Normalize to bytes on Python 3
412 # using Watchman's encoding, if needed.
413 if not isinstance(fname, bytes):
414 fname = fname.encode(_watchmanencoding)
415
399 if _fixencoding:
416 if _fixencoding:
400 fname = _watchmantofsencoding(fname)
417 fname = _watchmantofsencoding(fname)
418
401 if switch_slashes:
419 if switch_slashes:
402 fname = fname.replace(b'\\', b'/')
420 fname = fname.replace(b'\\', b'/')
403 if normalize:
421 if normalize:
@@ -486,9 +504,9 b' def overridewalk(orig, self, match, subr'
486 for f in auditfail:
504 for f in auditfail:
487 results[f] = None
505 results[f] = None
488
506
489 nf = iter(auditpass).next
507 nf = iter(auditpass)
490 for st in util.statfiles([join(f) for f in auditpass]):
508 for st in util.statfiles([join(f) for f in auditpass]):
491 f = nf()
509 f = next(nf)
492 if st or f in dmap:
510 if st or f in dmap:
493 results[f] = st
511 results[f] = st
494
512
@@ -916,7 +934,7 b' def reposetup(ui, repo):'
916 return
934 return
917
935
918 try:
936 try:
919 client = watchmanclient.client(repo.ui, repo._root)
937 client = watchmanclient.client(repo.ui, repo.root)
920 except Exception as ex:
938 except Exception as ex:
921 _handleunavailable(ui, fsmonitorstate, ex)
939 _handleunavailable(ui, fsmonitorstate, ex)
922 return
940 return
This diff has been collapsed as it changes many lines, (604 lines changed) Show them Hide them
@@ -26,10 +26,8 b''
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
29 from __future__ import absolute_import
30 from __future__ import division
31 from __future__ import print_function
32 # no unicode literals
29 # no unicode literals
30 from __future__ import absolute_import, division, print_function
33
31
34 import inspect
32 import inspect
35 import math
33 import math
@@ -38,33 +36,22 b' import socket'
38 import subprocess
36 import subprocess
39 import time
37 import time
40
38
39 from . import capabilities, compat, encoding, load
40
41
41 # Sometimes it's really hard to get Python extensions to compile,
42 # Sometimes it's really hard to get Python extensions to compile,
42 # so fall back to a pure Python implementation.
43 # so fall back to a pure Python implementation.
43 try:
44 try:
44 from . import bser
45 from . import bser
46
45 # Demandimport causes modules to be loaded lazily. Force the load now
47 # Demandimport causes modules to be loaded lazily. Force the load now
46 # so that we can fall back on pybser if bser doesn't exist
48 # so that we can fall back on pybser if bser doesn't exist
47 bser.pdu_info
49 bser.pdu_info
48 except ImportError:
50 except ImportError:
49 from . import pybser as bser
51 from . import pybser as bser
50
52
51 from mercurial.utils import (
52 procutil,
53 )
54
53
55 from mercurial import (
54 if os.name == "nt":
56 pycompat,
57 )
58
59 from . import (
60 capabilities,
61 compat,
62 encoding,
63 load,
64 )
65
66
67 if os.name == 'nt':
68 import ctypes
55 import ctypes
69 import ctypes.wintypes
56 import ctypes.wintypes
70
57
@@ -73,7 +60,7 b" if os.name == 'nt':"
73 GENERIC_WRITE = 0x40000000
60 GENERIC_WRITE = 0x40000000
74 FILE_FLAG_OVERLAPPED = 0x40000000
61 FILE_FLAG_OVERLAPPED = 0x40000000
75 OPEN_EXISTING = 3
62 OPEN_EXISTING = 3
76 INVALID_HANDLE_VALUE = -1
63 INVALID_HANDLE_VALUE = ctypes.c_void_p(-1).value
77 FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
64 FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
78 FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100
65 FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100
79 FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
66 FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
@@ -92,9 +79,11 b" if os.name == 'nt':"
92
79
93 class OVERLAPPED(ctypes.Structure):
80 class OVERLAPPED(ctypes.Structure):
94 _fields_ = [
81 _fields_ = [
95 ("Internal", ULONG_PTR), ("InternalHigh", ULONG_PTR),
82 ("Internal", ULONG_PTR),
96 ("Offset", wintypes.DWORD), ("OffsetHigh", wintypes.DWORD),
83 ("InternalHigh", ULONG_PTR),
97 ("hEvent", wintypes.HANDLE)
84 ("Offset", wintypes.DWORD),
85 ("OffsetHigh", wintypes.DWORD),
86 ("hEvent", wintypes.HANDLE),
98 ]
87 ]
99
88
100 def __init__(self):
89 def __init__(self):
@@ -107,9 +96,15 b" if os.name == 'nt':"
107 LPDWORD = ctypes.POINTER(wintypes.DWORD)
96 LPDWORD = ctypes.POINTER(wintypes.DWORD)
108
97
109 CreateFile = ctypes.windll.kernel32.CreateFileA
98 CreateFile = ctypes.windll.kernel32.CreateFileA
110 CreateFile.argtypes = [wintypes.LPSTR, wintypes.DWORD, wintypes.DWORD,
99 CreateFile.argtypes = [
111 wintypes.LPVOID, wintypes.DWORD, wintypes.DWORD,
100 wintypes.LPSTR,
112 wintypes.HANDLE]
101 wintypes.DWORD,
102 wintypes.DWORD,
103 wintypes.LPVOID,
104 wintypes.DWORD,
105 wintypes.DWORD,
106 wintypes.HANDLE,
107 ]
113 CreateFile.restype = wintypes.HANDLE
108 CreateFile.restype = wintypes.HANDLE
114
109
115 CloseHandle = ctypes.windll.kernel32.CloseHandle
110 CloseHandle = ctypes.windll.kernel32.CloseHandle
@@ -117,13 +112,23 b" if os.name == 'nt':"
117 CloseHandle.restype = wintypes.BOOL
112 CloseHandle.restype = wintypes.BOOL
118
113
119 ReadFile = ctypes.windll.kernel32.ReadFile
114 ReadFile = ctypes.windll.kernel32.ReadFile
120 ReadFile.argtypes = [wintypes.HANDLE, wintypes.LPVOID, wintypes.DWORD,
115 ReadFile.argtypes = [
121 LPDWORD, ctypes.POINTER(OVERLAPPED)]
116 wintypes.HANDLE,
117 wintypes.LPVOID,
118 wintypes.DWORD,
119 LPDWORD,
120 ctypes.POINTER(OVERLAPPED),
121 ]
122 ReadFile.restype = wintypes.BOOL
122 ReadFile.restype = wintypes.BOOL
123
123
124 WriteFile = ctypes.windll.kernel32.WriteFile
124 WriteFile = ctypes.windll.kernel32.WriteFile
125 WriteFile.argtypes = [wintypes.HANDLE, wintypes.LPVOID, wintypes.DWORD,
125 WriteFile.argtypes = [
126 LPDWORD, ctypes.POINTER(OVERLAPPED)]
126 wintypes.HANDLE,
127 wintypes.LPVOID,
128 wintypes.DWORD,
129 LPDWORD,
130 ctypes.POINTER(OVERLAPPED),
131 ]
127 WriteFile.restype = wintypes.BOOL
132 WriteFile.restype = wintypes.BOOL
128
133
129 GetLastError = ctypes.windll.kernel32.GetLastError
134 GetLastError = ctypes.windll.kernel32.GetLastError
@@ -135,34 +140,56 b" if os.name == 'nt':"
135 SetLastError.restype = None
140 SetLastError.restype = None
136
141
137 FormatMessage = ctypes.windll.kernel32.FormatMessageA
142 FormatMessage = ctypes.windll.kernel32.FormatMessageA
138 FormatMessage.argtypes = [wintypes.DWORD, wintypes.LPVOID, wintypes.DWORD,
143 FormatMessage.argtypes = [
139 wintypes.DWORD, ctypes.POINTER(wintypes.LPSTR),
144 wintypes.DWORD,
140 wintypes.DWORD, wintypes.LPVOID]
145 wintypes.LPVOID,
146 wintypes.DWORD,
147 wintypes.DWORD,
148 ctypes.POINTER(wintypes.LPSTR),
149 wintypes.DWORD,
150 wintypes.LPVOID,
151 ]
141 FormatMessage.restype = wintypes.DWORD
152 FormatMessage.restype = wintypes.DWORD
142
153
143 LocalFree = ctypes.windll.kernel32.LocalFree
154 LocalFree = ctypes.windll.kernel32.LocalFree
144
155
145 GetOverlappedResult = ctypes.windll.kernel32.GetOverlappedResult
156 GetOverlappedResult = ctypes.windll.kernel32.GetOverlappedResult
146 GetOverlappedResult.argtypes = [wintypes.HANDLE,
157 GetOverlappedResult.argtypes = [
147 ctypes.POINTER(OVERLAPPED), LPDWORD,
158 wintypes.HANDLE,
148 wintypes.BOOL]
159 ctypes.POINTER(OVERLAPPED),
160 LPDWORD,
161 wintypes.BOOL,
162 ]
149 GetOverlappedResult.restype = wintypes.BOOL
163 GetOverlappedResult.restype = wintypes.BOOL
150
164
151 GetOverlappedResultEx = getattr(ctypes.windll.kernel32,
165 GetOverlappedResultEx = getattr(
152 'GetOverlappedResultEx', None)
166 ctypes.windll.kernel32, "GetOverlappedResultEx", None
167 )
153 if GetOverlappedResultEx is not None:
168 if GetOverlappedResultEx is not None:
154 GetOverlappedResultEx.argtypes = [wintypes.HANDLE,
169 GetOverlappedResultEx.argtypes = [
155 ctypes.POINTER(OVERLAPPED), LPDWORD,
170 wintypes.HANDLE,
156 wintypes.DWORD, wintypes.BOOL]
171 ctypes.POINTER(OVERLAPPED),
172 LPDWORD,
173 wintypes.DWORD,
174 wintypes.BOOL,
175 ]
157 GetOverlappedResultEx.restype = wintypes.BOOL
176 GetOverlappedResultEx.restype = wintypes.BOOL
158
177
159 WaitForSingleObjectEx = ctypes.windll.kernel32.WaitForSingleObjectEx
178 WaitForSingleObjectEx = ctypes.windll.kernel32.WaitForSingleObjectEx
160 WaitForSingleObjectEx.argtypes = [wintypes.HANDLE, wintypes.DWORD, wintypes.BOOL]
179 WaitForSingleObjectEx.argtypes = [
180 wintypes.HANDLE,
181 wintypes.DWORD,
182 wintypes.BOOL,
183 ]
161 WaitForSingleObjectEx.restype = wintypes.DWORD
184 WaitForSingleObjectEx.restype = wintypes.DWORD
162
185
163 CreateEvent = ctypes.windll.kernel32.CreateEventA
186 CreateEvent = ctypes.windll.kernel32.CreateEventA
164 CreateEvent.argtypes = [LPDWORD, wintypes.BOOL, wintypes.BOOL,
187 CreateEvent.argtypes = [
165 wintypes.LPSTR]
188 LPDWORD,
189 wintypes.BOOL,
190 wintypes.BOOL,
191 wintypes.LPSTR,
192 ]
166 CreateEvent.restype = wintypes.HANDLE
193 CreateEvent.restype = wintypes.HANDLE
167
194
168 # Windows Vista is the minimum supported client for CancelIoEx.
195 # Windows Vista is the minimum supported client for CancelIoEx.
@@ -178,9 +205,15 b' sniff_len = 13'
178 if _debugging:
205 if _debugging:
179
206
180 def log(fmt, *args):
207 def log(fmt, *args):
181 print('[%s] %s' %
208 print(
182 (time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime()),
209 "[%s] %s"
183 fmt % args[:]))
210 % (
211 time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime()),
212 fmt % args[:],
213 )
214 )
215
216
184 else:
217 else:
185
218
186 def log(fmt, *args):
219 def log(fmt, *args):
@@ -193,8 +226,16 b' def _win32_strerror(err):'
193 # FormatMessage will allocate memory and assign it here
226 # FormatMessage will allocate memory and assign it here
194 buf = ctypes.c_char_p()
227 buf = ctypes.c_char_p()
195 FormatMessage(
228 FormatMessage(
196 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
229 FORMAT_MESSAGE_FROM_SYSTEM
197 | FORMAT_MESSAGE_IGNORE_INSERTS, None, err, 0, buf, 0, None)
230 | FORMAT_MESSAGE_ALLOCATE_BUFFER
231 | FORMAT_MESSAGE_IGNORE_INSERTS,
232 None,
233 err,
234 0,
235 buf,
236 0,
237 None,
238 )
198 try:
239 try:
199 return buf.value
240 return buf.value
200 finally:
241 finally:
@@ -211,21 +252,30 b' class WatchmanError(Exception):'
211
252
212 def __str__(self):
253 def __str__(self):
213 if self.cmd:
254 if self.cmd:
214 return '%s, while executing %s' % (self.msg, self.cmd)
255 return "%s, while executing %s" % (self.msg, self.cmd)
215 return self.msg
256 return self.msg
216
257
217
258
259 class BSERv1Unsupported(WatchmanError):
260 pass
261
262
263 class UseAfterFork(WatchmanError):
264 pass
265
266
218 class WatchmanEnvironmentError(WatchmanError):
267 class WatchmanEnvironmentError(WatchmanError):
219 def __init__(self, msg, errno, errmsg, cmd=None):
268 def __init__(self, msg, errno, errmsg, cmd=None):
220 super(WatchmanEnvironmentError, self).__init__(
269 super(WatchmanEnvironmentError, self).__init__(
221 '{0}: errno={1} errmsg={2}'.format(msg, errno, errmsg),
270 "{0}: errno={1} errmsg={2}".format(msg, errno, errmsg), cmd
222 cmd)
271 )
223
272
224
273
225 class SocketConnectError(WatchmanError):
274 class SocketConnectError(WatchmanError):
226 def __init__(self, sockpath, exc):
275 def __init__(self, sockpath, exc):
227 super(SocketConnectError, self).__init__(
276 super(SocketConnectError, self).__init__(
228 'unable to connect to %s: %s' % (sockpath, exc))
277 "unable to connect to %s: %s" % (sockpath, exc)
278 )
229 self.sockpath = sockpath
279 self.sockpath = sockpath
230 self.exc = exc
280 self.exc = exc
231
281
@@ -245,15 +295,16 b' class CommandError(WatchmanError):'
245
295
246 self.msg is the message returned by watchman.
296 self.msg is the message returned by watchman.
247 """
297 """
298
248 def __init__(self, msg, cmd=None):
299 def __init__(self, msg, cmd=None):
249 super(CommandError, self).__init__(
300 super(CommandError, self).__init__(
250 'watchman command error: %s' % (msg, ),
301 "watchman command error: %s" % (msg,), cmd
251 cmd,
252 )
302 )
253
303
254
304
255 class Transport(object):
305 class Transport(object):
256 """ communication transport to the watchman server """
306 """ communication transport to the watchman server """
307
257 buf = None
308 buf = None
258
309
259 def close(self):
310 def close(self):
@@ -289,7 +340,7 b' class Transport(object):'
289 while True:
340 while True:
290 b = self.readBytes(4096)
341 b = self.readBytes(4096)
291 if b"\n" in b:
342 if b"\n" in b:
292 result = b''.join(self.buf)
343 result = b"".join(self.buf)
293 (line, b) = b.split(b"\n", 1)
344 (line, b) = b.split(b"\n", 1)
294 self.buf = [b]
345 self.buf = [b]
295 return result + line
346 return result + line
@@ -298,6 +349,7 b' class Transport(object):'
298
349
299 class Codec(object):
350 class Codec(object):
300 """ communication encoding for the watchman server """
351 """ communication encoding for the watchman server """
352
301 transport = None
353 transport = None
302
354
303 def __init__(self, transport):
355 def __init__(self, transport):
@@ -315,9 +367,10 b' class Codec(object):'
315
367
316 class UnixSocketTransport(Transport):
368 class UnixSocketTransport(Transport):
317 """ local unix domain socket transport """
369 """ local unix domain socket transport """
370
318 sock = None
371 sock = None
319
372
320 def __init__(self, sockpath, timeout, watchman_exe):
373 def __init__(self, sockpath, timeout):
321 self.sockpath = sockpath
374 self.sockpath = sockpath
322 self.timeout = timeout
375 self.timeout = timeout
323
376
@@ -331,8 +384,9 b' class UnixSocketTransport(Transport):'
331 raise SocketConnectError(self.sockpath, e)
384 raise SocketConnectError(self.sockpath, e)
332
385
333 def close(self):
386 def close(self):
334 self.sock.close()
387 if self.sock:
335 self.sock = None
388 self.sock.close()
389 self.sock = None
336
390
337 def setTimeout(self, value):
391 def setTimeout(self, value):
338 self.timeout = value
392 self.timeout = value
@@ -342,16 +396,16 b' class UnixSocketTransport(Transport):'
342 try:
396 try:
343 buf = [self.sock.recv(size)]
397 buf = [self.sock.recv(size)]
344 if not buf[0]:
398 if not buf[0]:
345 raise WatchmanError('empty watchman response')
399 raise WatchmanError("empty watchman response")
346 return buf[0]
400 return buf[0]
347 except socket.timeout:
401 except socket.timeout:
348 raise SocketTimeout('timed out waiting for response')
402 raise SocketTimeout("timed out waiting for response")
349
403
350 def write(self, data):
404 def write(self, data):
351 try:
405 try:
352 self.sock.sendall(data)
406 self.sock.sendall(data)
353 except socket.timeout:
407 except socket.timeout:
354 raise SocketTimeout('timed out sending query command')
408 raise SocketTimeout("timed out sending query command")
355
409
356
410
357 def _get_overlapped_result_ex_impl(pipe, olap, nbytes, millis, alertable):
411 def _get_overlapped_result_ex_impl(pipe, olap, nbytes, millis, alertable):
@@ -364,7 +418,7 b' def _get_overlapped_result_ex_impl(pipe,'
364 source code (see get_overlapped_result_ex_impl in stream_win.c). This
418 source code (see get_overlapped_result_ex_impl in stream_win.c). This
365 way, maintenance should be simplified.
419 way, maintenance should be simplified.
366 """
420 """
367 log('Preparing to wait for maximum %dms', millis )
421 log("Preparing to wait for maximum %dms", millis)
368 if millis != 0:
422 if millis != 0:
369 waitReturnCode = WaitForSingleObjectEx(olap.hEvent, millis, alertable)
423 waitReturnCode = WaitForSingleObjectEx(olap.hEvent, millis, alertable)
370 if waitReturnCode == WAIT_OBJECT_0:
424 if waitReturnCode == WAIT_OBJECT_0:
@@ -383,12 +437,12 b' def _get_overlapped_result_ex_impl(pipe,'
383 elif waitReturnCode == WAIT_FAILED:
437 elif waitReturnCode == WAIT_FAILED:
384 # something went wrong calling WaitForSingleObjectEx
438 # something went wrong calling WaitForSingleObjectEx
385 err = GetLastError()
439 err = GetLastError()
386 log('WaitForSingleObjectEx failed: %s', _win32_strerror(err))
440 log("WaitForSingleObjectEx failed: %s", _win32_strerror(err))
387 return False
441 return False
388 else:
442 else:
389 # unexpected situation deserving investigation.
443 # unexpected situation deserving investigation.
390 err = GetLastError()
444 err = GetLastError()
391 log('Unexpected error: %s', _win32_strerror(err))
445 log("Unexpected error: %s", _win32_strerror(err))
392 return False
446 return False
393
447
394 return GetOverlappedResult(pipe, olap, nbytes, False)
448 return GetOverlappedResult(pipe, olap, nbytes, False)
@@ -397,36 +451,52 b' def _get_overlapped_result_ex_impl(pipe,'
397 class WindowsNamedPipeTransport(Transport):
451 class WindowsNamedPipeTransport(Transport):
398 """ connect to a named pipe """
452 """ connect to a named pipe """
399
453
400 def __init__(self, sockpath, timeout, watchman_exe):
454 def __init__(self, sockpath, timeout):
401 self.sockpath = sockpath
455 self.sockpath = sockpath
402 self.timeout = int(math.ceil(timeout * 1000))
456 self.timeout = int(math.ceil(timeout * 1000))
403 self._iobuf = None
457 self._iobuf = None
404
458
405 self.pipe = CreateFile(sockpath, GENERIC_READ | GENERIC_WRITE, 0, None,
459 if compat.PYTHON3:
406 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, None)
460 sockpath = os.fsencode(sockpath)
461 self.pipe = CreateFile(
462 sockpath,
463 GENERIC_READ | GENERIC_WRITE,
464 0,
465 None,
466 OPEN_EXISTING,
467 FILE_FLAG_OVERLAPPED,
468 None,
469 )
407
470
408 if self.pipe == INVALID_HANDLE_VALUE:
471 err = GetLastError()
472 if self.pipe == INVALID_HANDLE_VALUE or self.pipe == 0:
409 self.pipe = None
473 self.pipe = None
410 self._raise_win_err('failed to open pipe %s' % sockpath,
474 raise SocketConnectError(self.sockpath, self._make_win_err("", err))
411 GetLastError())
412
475
413 # event for the overlapped I/O operations
476 # event for the overlapped I/O operations
414 self._waitable = CreateEvent(None, True, False, None)
477 self._waitable = CreateEvent(None, True, False, None)
478 err = GetLastError()
415 if self._waitable is None:
479 if self._waitable is None:
416 self._raise_win_err('CreateEvent failed', GetLastError())
480 self._raise_win_err("CreateEvent failed", err)
417
481
418 self._get_overlapped_result_ex = GetOverlappedResultEx
482 self._get_overlapped_result_ex = GetOverlappedResultEx
419 if (os.getenv('WATCHMAN_WIN7_COMPAT') == '1' or
483 if (
420 self._get_overlapped_result_ex is None):
484 os.getenv("WATCHMAN_WIN7_COMPAT") == "1"
485 or self._get_overlapped_result_ex is None
486 ):
421 self._get_overlapped_result_ex = _get_overlapped_result_ex_impl
487 self._get_overlapped_result_ex = _get_overlapped_result_ex_impl
422
488
423 def _raise_win_err(self, msg, err):
489 def _raise_win_err(self, msg, err):
424 raise IOError('%s win32 error code: %d %s' %
490 raise self._make_win_err(msg, err)
425 (msg, err, _win32_strerror(err)))
491
492 def _make_win_err(self, msg, err):
493 return IOError(
494 "%s win32 error code: %d %s" % (msg, err, _win32_strerror(err))
495 )
426
496
427 def close(self):
497 def close(self):
428 if self.pipe:
498 if self.pipe:
429 log('Closing pipe')
499 log("Closing pipe")
430 CloseHandle(self.pipe)
500 CloseHandle(self.pipe)
431 self.pipe = None
501 self.pipe = None
432
502
@@ -460,7 +530,7 b' class WindowsNamedPipeTransport(Transpor'
460 olap = OVERLAPPED()
530 olap = OVERLAPPED()
461 olap.hEvent = self._waitable
531 olap.hEvent = self._waitable
462
532
463 log('made read buff of size %d', size)
533 log("made read buff of size %d", size)
464
534
465 # ReadFile docs warn against sending in the nread parameter for async
535 # ReadFile docs warn against sending in the nread parameter for async
466 # operations, so we always collect it via GetOverlappedResultEx
536 # operations, so we always collect it via GetOverlappedResultEx
@@ -469,23 +539,23 b' class WindowsNamedPipeTransport(Transpor'
469 if not immediate:
539 if not immediate:
470 err = GetLastError()
540 err = GetLastError()
471 if err != ERROR_IO_PENDING:
541 if err != ERROR_IO_PENDING:
472 self._raise_win_err('failed to read %d bytes' % size,
542 self._raise_win_err("failed to read %d bytes" % size, err)
473 GetLastError())
474
543
475 nread = wintypes.DWORD()
544 nread = wintypes.DWORD()
476 if not self._get_overlapped_result_ex(self.pipe, olap, nread,
545 if not self._get_overlapped_result_ex(
477 0 if immediate else self.timeout,
546 self.pipe, olap, nread, 0 if immediate else self.timeout, True
478 True):
547 ):
479 err = GetLastError()
548 err = GetLastError()
480 CancelIoEx(self.pipe, olap)
549 CancelIoEx(self.pipe, olap)
481
550
482 if err == WAIT_TIMEOUT:
551 if err == WAIT_TIMEOUT:
483 log('GetOverlappedResultEx timedout')
552 log("GetOverlappedResultEx timedout")
484 raise SocketTimeout('timed out after waiting %dms for read' %
553 raise SocketTimeout(
485 self.timeout)
554 "timed out after waiting %dms for read" % self.timeout
555 )
486
556
487 log('GetOverlappedResultEx reports error %d', err)
557 log("GetOverlappedResultEx reports error %d", err)
488 self._raise_win_err('error while waiting for read', err)
558 self._raise_win_err("error while waiting for read", err)
489
559
490 nread = nread.value
560 nread = nread.value
491 if nread == 0:
561 if nread == 0:
@@ -494,7 +564,7 b' class WindowsNamedPipeTransport(Transpor'
494 # other way this shows up is if the client has gotten in a weird
564 # other way this shows up is if the client has gotten in a weird
495 # state, so let's bail out
565 # state, so let's bail out
496 CancelIoEx(self.pipe, olap)
566 CancelIoEx(self.pipe, olap)
497 raise IOError('Async read yielded 0 bytes; unpossible!')
567 raise IOError("Async read yielded 0 bytes; unpossible!")
498
568
499 # Holds precisely the bytes that we read from the prior request
569 # Holds precisely the bytes that we read from the prior request
500 buf = buf[:nread]
570 buf = buf[:nread]
@@ -511,21 +581,25 b' class WindowsNamedPipeTransport(Transpor'
511 olap = OVERLAPPED()
581 olap = OVERLAPPED()
512 olap.hEvent = self._waitable
582 olap.hEvent = self._waitable
513
583
514 immediate = WriteFile(self.pipe, ctypes.c_char_p(data), len(data),
584 immediate = WriteFile(
515 None, olap)
585 self.pipe, ctypes.c_char_p(data), len(data), None, olap
586 )
516
587
517 if not immediate:
588 if not immediate:
518 err = GetLastError()
589 err = GetLastError()
519 if err != ERROR_IO_PENDING:
590 if err != ERROR_IO_PENDING:
520 self._raise_win_err('failed to write %d bytes' % len(data),
591 self._raise_win_err(
521 GetLastError())
592 "failed to write %d bytes to handle %r"
593 % (len(data), self.pipe),
594 err,
595 )
522
596
523 # Obtain results, waiting if needed
597 # Obtain results, waiting if needed
524 nwrote = wintypes.DWORD()
598 nwrote = wintypes.DWORD()
525 if self._get_overlapped_result_ex(self.pipe, olap, nwrote,
599 if self._get_overlapped_result_ex(
526 0 if immediate else self.timeout,
600 self.pipe, olap, nwrote, 0 if immediate else self.timeout, True
527 True):
601 ):
528 log('made write of %d bytes', nwrote.value)
602 log("made write of %d bytes", nwrote.value)
529 return nwrote.value
603 return nwrote.value
530
604
531 err = GetLastError()
605 err = GetLastError()
@@ -535,10 +609,21 b' class WindowsNamedPipeTransport(Transpor'
535 CancelIoEx(self.pipe, olap)
609 CancelIoEx(self.pipe, olap)
536
610
537 if err == WAIT_TIMEOUT:
611 if err == WAIT_TIMEOUT:
538 raise SocketTimeout('timed out after waiting %dms for write' %
612 raise SocketTimeout(
539 self.timeout)
613 "timed out after waiting %dms for write" % self.timeout
540 self._raise_win_err('error while waiting for write of %d bytes' %
614 )
541 len(data), err)
615 self._raise_win_err(
616 "error while waiting for write of %d bytes" % len(data), err
617 )
618
619
620 def _default_binpath(binpath=None):
621 if binpath:
622 return binpath
623 # The test harness sets WATCHMAN_BINARY to the binary under test,
624 # so we use that by default, otherwise, allow resolving watchman
625 # from the users PATH.
626 return os.environ.get("WATCHMAN_BINARY", "watchman")
542
627
543
628
544 class CLIProcessTransport(Transport):
629 class CLIProcessTransport(Transport):
@@ -560,13 +645,14 b' class CLIProcessTransport(Transport):'
560 It is the responsibility of the caller to set the send and
645 It is the responsibility of the caller to set the send and
561 receive codecs appropriately.
646 receive codecs appropriately.
562 """
647 """
648
563 proc = None
649 proc = None
564 closed = True
650 closed = True
565
651
566 def __init__(self, sockpath, timeout, watchman_exe):
652 def __init__(self, sockpath, timeout, binpath=None):
567 self.sockpath = sockpath
653 self.sockpath = sockpath
568 self.timeout = timeout
654 self.timeout = timeout
569 self.watchman_exe = watchman_exe
655 self.binpath = _default_binpath(binpath)
570
656
571 def close(self):
657 def close(self):
572 if self.proc:
658 if self.proc:
@@ -574,32 +660,32 b' class CLIProcessTransport(Transport):'
574 self.proc.kill()
660 self.proc.kill()
575 self.proc.stdin.close()
661 self.proc.stdin.close()
576 self.proc.stdout.close()
662 self.proc.stdout.close()
663 self.proc.wait()
577 self.proc = None
664 self.proc = None
578
665
579 def _connect(self):
666 def _connect(self):
580 if self.proc:
667 if self.proc:
581 return self.proc
668 return self.proc
582 args = [
669 args = [
583 self.watchman_exe,
670 self.binpath,
584 '--sockname={0}'.format(self.sockpath),
671 "--sockname={0}".format(self.sockpath),
585 '--logfile=/BOGUS',
672 "--logfile=/BOGUS",
586 '--statefile=/BOGUS',
673 "--statefile=/BOGUS",
587 '--no-spawn',
674 "--no-spawn",
588 '--no-local',
675 "--no-local",
589 '--no-pretty',
676 "--no-pretty",
590 '-j',
677 "-j",
591 ]
678 ]
592 self.proc = subprocess.Popen(pycompat.rapply(procutil.tonativestr,
679 self.proc = subprocess.Popen(
593 args),
680 args, stdin=subprocess.PIPE, stdout=subprocess.PIPE
594 stdin=subprocess.PIPE,
681 )
595 stdout=subprocess.PIPE)
596 return self.proc
682 return self.proc
597
683
598 def readBytes(self, size):
684 def readBytes(self, size):
599 self._connect()
685 self._connect()
600 res = self.proc.stdout.read(size)
686 res = self.proc.stdout.read(size)
601 if res == '':
687 if not res:
602 raise WatchmanError('EOF on CLI process transport')
688 raise WatchmanError("EOF on CLI process transport")
603 return res
689 return res
604
690
605 def write(self, data):
691 def write(self, data):
@@ -616,13 +702,22 b' class CLIProcessTransport(Transport):'
616 class BserCodec(Codec):
702 class BserCodec(Codec):
617 """ use the BSER encoding. This is the default, preferred codec """
703 """ use the BSER encoding. This is the default, preferred codec """
618
704
705 def __init__(self, transport, value_encoding, value_errors):
706 super(BserCodec, self).__init__(transport)
707 self._value_encoding = value_encoding
708 self._value_errors = value_errors
709
619 def _loads(self, response):
710 def _loads(self, response):
620 return bser.loads(response) # Defaults to BSER v1
711 return bser.loads(
712 response,
713 value_encoding=self._value_encoding,
714 value_errors=self._value_errors,
715 )
621
716
622 def receive(self):
717 def receive(self):
623 buf = [self.transport.readBytes(sniff_len)]
718 buf = [self.transport.readBytes(sniff_len)]
624 if not buf[0]:
719 if not buf[0]:
625 raise WatchmanError('empty watchman response')
720 raise WatchmanError("empty watchman response")
626
721
627 _1, _2, elen = bser.pdu_info(buf[0])
722 _1, _2, elen = bser.pdu_info(buf[0])
628
723
@@ -631,15 +726,15 b' class BserCodec(Codec):'
631 buf.append(self.transport.readBytes(elen - rlen))
726 buf.append(self.transport.readBytes(elen - rlen))
632 rlen += len(buf[-1])
727 rlen += len(buf[-1])
633
728
634 response = b''.join(buf)
729 response = b"".join(buf)
635 try:
730 try:
636 res = self._loads(response)
731 res = self._loads(response)
637 return res
732 return res
638 except ValueError as e:
733 except ValueError as e:
639 raise WatchmanError('watchman response decode error: %s' % e)
734 raise WatchmanError("watchman response decode error: %s" % e)
640
735
641 def send(self, *args):
736 def send(self, *args):
642 cmd = bser.dumps(*args) # Defaults to BSER v1
737 cmd = bser.dumps(*args) # Defaults to BSER v1
643 self.transport.write(cmd)
738 self.transport.write(cmd)
644
739
645
740
@@ -648,74 +743,96 b' class ImmutableBserCodec(BserCodec):'
648 immutable object support """
743 immutable object support """
649
744
650 def _loads(self, response):
745 def _loads(self, response):
651 return bser.loads(response, False) # Defaults to BSER v1
746 return bser.loads(
747 response,
748 False,
749 value_encoding=self._value_encoding,
750 value_errors=self._value_errors,
751 )
652
752
653
753
654 class Bser2WithFallbackCodec(BserCodec):
754 class Bser2WithFallbackCodec(BserCodec):
655 """ use BSER v2 encoding """
755 """ use BSER v2 encoding """
656
756
657 def __init__(self, transport):
757 def __init__(self, transport, value_encoding, value_errors):
658 super(Bser2WithFallbackCodec, self).__init__(transport)
758 super(Bser2WithFallbackCodec, self).__init__(
659 # Once the server advertises support for bser-v2 we should switch this
759 transport, value_encoding, value_errors
660 # to 'required' on Python 3.
760 )
661 self.send(["version", {"optional": ["bser-v2"]}])
761 if compat.PYTHON3:
762 bserv2_key = "required"
763 else:
764 bserv2_key = "optional"
765
766 self.send(["version", {bserv2_key: ["bser-v2"]}])
662
767
663 capabilities = self.receive()
768 capabilities = self.receive()
664
769
665 if 'error' in capabilities:
770 if "error" in capabilities:
666 raise Exception('Unsupported BSER version')
771 raise BSERv1Unsupported(
772 "The watchman server version does not support Python 3. Please "
773 "upgrade your watchman server."
774 )
667
775
668 if capabilities['capabilities']['bser-v2']:
776 if capabilities["capabilities"]["bser-v2"]:
669 self.bser_version = 2
777 self.bser_version = 2
670 self.bser_capabilities = 0
778 self.bser_capabilities = 0
671 else:
779 else:
672 self.bser_version = 1
780 self.bser_version = 1
673 self.bser_capabilities = 0
781 self.bser_capabilities = 0
674
782
675 def _loads(self, response):
676 return bser.loads(response)
677
678 def receive(self):
783 def receive(self):
679 buf = [self.transport.readBytes(sniff_len)]
784 buf = [self.transport.readBytes(sniff_len)]
680 if not buf[0]:
785 if not buf[0]:
681 raise WatchmanError('empty watchman response')
786 raise WatchmanError("empty watchman response")
682
787
683 recv_bser_version, recv_bser_capabilities, elen = bser.pdu_info(buf[0])
788 recv_bser_version, recv_bser_capabilities, elen = bser.pdu_info(buf[0])
684
789
685 if hasattr(self, 'bser_version'):
790 if hasattr(self, "bser_version"):
686 # Readjust BSER version and capabilities if necessary
791 # Readjust BSER version and capabilities if necessary
687 self.bser_version = max(self.bser_version, recv_bser_version)
792 self.bser_version = max(self.bser_version, recv_bser_version)
688 self.capabilities = self.bser_capabilities & recv_bser_capabilities
793 self.capabilities = self.bser_capabilities & recv_bser_capabilities
689
794
690 rlen = len(buf[0])
795 rlen = len(buf[0])
691 while elen > rlen:
796 while elen > rlen:
692 buf.append(self.transport.readBytes(elen - rlen))
797 buf.append(self.transport.readBytes(elen - rlen))
693 rlen += len(buf[-1])
798 rlen += len(buf[-1])
694
799
695 response = b''.join(buf)
800 response = b"".join(buf)
696 try:
801 try:
697 res = self._loads(response)
802 res = self._loads(response)
698 return res
803 return res
699 except ValueError as e:
804 except ValueError as e:
700 raise WatchmanError('watchman response decode error: %s' % e)
805 raise WatchmanError("watchman response decode error: %s" % e)
701
806
702 def send(self, *args):
807 def send(self, *args):
703 if hasattr(self, 'bser_version'):
808 if hasattr(self, "bser_version"):
704 cmd = bser.dumps(*args, version=self.bser_version,
809 cmd = bser.dumps(
705 capabilities=self.bser_capabilities)
810 *args,
811 version=self.bser_version,
812 capabilities=self.bser_capabilities
813 )
706 else:
814 else:
707 cmd = bser.dumps(*args)
815 cmd = bser.dumps(*args)
708 self.transport.write(cmd)
816 self.transport.write(cmd)
709
817
710
818
819 class ImmutableBser2Codec(Bser2WithFallbackCodec, ImmutableBserCodec):
820 """ use the BSER encoding, decoding values using the newer
821 immutable object support """
822
823 pass
824
825
711 class JsonCodec(Codec):
826 class JsonCodec(Codec):
712 """ Use json codec. This is here primarily for testing purposes """
827 """ Use json codec. This is here primarily for testing purposes """
828
713 json = None
829 json = None
714
830
715 def __init__(self, transport):
831 def __init__(self, transport):
716 super(JsonCodec, self).__init__(transport)
832 super(JsonCodec, self).__init__(transport)
717 # optional dep on json, only if JsonCodec is used
833 # optional dep on json, only if JsonCodec is used
718 import json
834 import json
835
719 self.json = json
836 self.json = json
720
837
721 def receive(self):
838 def receive(self):
@@ -727,7 +844,7 b' class JsonCodec(Codec):'
727 # but it's possible we might get non-ASCII bytes that are valid
844 # but it's possible we might get non-ASCII bytes that are valid
728 # UTF-8.
845 # UTF-8.
729 if compat.PYTHON3:
846 if compat.PYTHON3:
730 line = line.decode('utf-8')
847 line = line.decode("utf-8")
731 return self.json.loads(line)
848 return self.json.loads(line)
732 except Exception as e:
849 except Exception as e:
733 print(e, line)
850 print(e, line)
@@ -739,12 +856,13 b' class JsonCodec(Codec):'
739 # containing Unicode strings to Unicode string. Even with (the default)
856 # containing Unicode strings to Unicode string. Even with (the default)
740 # ensure_ascii=True, dumps returns a Unicode string.
857 # ensure_ascii=True, dumps returns a Unicode string.
741 if compat.PYTHON3:
858 if compat.PYTHON3:
742 cmd = cmd.encode('ascii')
859 cmd = cmd.encode("ascii")
743 self.transport.write(cmd + b"\n")
860 self.transport.write(cmd + b"\n")
744
861
745
862
746 class client(object):
863 class client(object):
747 """ Handles the communication with the watchman service """
864 """ Handles the communication with the watchman service """
865
748 sockpath = None
866 sockpath = None
749 transport = None
867 transport = None
750 sendCodec = None
868 sendCodec = None
@@ -754,60 +872,100 b' class client(object):'
754 subs = {} # Keyed by subscription name
872 subs = {} # Keyed by subscription name
755 sub_by_root = {} # Keyed by root, then by subscription name
873 sub_by_root = {} # Keyed by root, then by subscription name
756 logs = [] # When log level is raised
874 logs = [] # When log level is raised
757 unilateral = ['log', 'subscription']
875 unilateral = ["log", "subscription"]
758 tport = None
876 tport = None
759 useImmutableBser = None
877 useImmutableBser = None
760 watchman_exe = None
878 pid = None
761
879
762 def __init__(self,
880 def __init__(
763 sockpath=None,
881 self,
764 timeout=1.0,
882 sockpath=None,
765 transport=None,
883 timeout=1.0,
766 sendEncoding=None,
884 transport=None,
767 recvEncoding=None,
885 sendEncoding=None,
768 useImmutableBser=False,
886 recvEncoding=None,
769 watchman_exe=None):
887 useImmutableBser=False,
888 # use False for these two because None has a special
889 # meaning
890 valueEncoding=False,
891 valueErrors=False,
892 binpath=None,
893 ):
770 self.sockpath = sockpath
894 self.sockpath = sockpath
771 self.timeout = timeout
895 self.timeout = timeout
772 self.useImmutableBser = useImmutableBser
896 self.useImmutableBser = useImmutableBser
773 self.watchman_exe = watchman_exe
897 self.binpath = _default_binpath(binpath)
774
898
775 if inspect.isclass(transport) and issubclass(transport, Transport):
899 if inspect.isclass(transport) and issubclass(transport, Transport):
776 self.transport = transport
900 self.transport = transport
777 else:
901 else:
778 transport = transport or os.getenv('WATCHMAN_TRANSPORT') or 'local'
902 transport = transport or os.getenv("WATCHMAN_TRANSPORT") or "local"
779 if transport == 'local' and os.name == 'nt':
903 if transport == "local" and os.name == "nt":
780 self.transport = WindowsNamedPipeTransport
904 self.transport = WindowsNamedPipeTransport
781 elif transport == 'local':
905 elif transport == "local":
782 self.transport = UnixSocketTransport
906 self.transport = UnixSocketTransport
783 elif transport == 'cli':
907 elif transport == "cli":
784 self.transport = CLIProcessTransport
908 self.transport = CLIProcessTransport
785 if sendEncoding is None:
909 if sendEncoding is None:
786 sendEncoding = 'json'
910 sendEncoding = "json"
787 if recvEncoding is None:
911 if recvEncoding is None:
788 recvEncoding = sendEncoding
912 recvEncoding = sendEncoding
789 else:
913 else:
790 raise WatchmanError('invalid transport %s' % transport)
914 raise WatchmanError("invalid transport %s" % transport)
791
915
792 sendEncoding = str(sendEncoding or os.getenv('WATCHMAN_ENCODING') or
916 sendEncoding = str(
793 'bser')
917 sendEncoding or os.getenv("WATCHMAN_ENCODING") or "bser"
794 recvEncoding = str(recvEncoding or os.getenv('WATCHMAN_ENCODING') or
918 )
795 'bser')
919 recvEncoding = str(
920 recvEncoding or os.getenv("WATCHMAN_ENCODING") or "bser"
921 )
796
922
797 self.recvCodec = self._parseEncoding(recvEncoding)
923 self.recvCodec = self._parseEncoding(recvEncoding)
798 self.sendCodec = self._parseEncoding(sendEncoding)
924 self.sendCodec = self._parseEncoding(sendEncoding)
799
925
926 # We want to act like the native OS methods as much as possible. This
927 # means returning bytestrings on Python 2 by default and Unicode
928 # strings on Python 3. However we take an optional argument that lets
929 # users override this.
930 if valueEncoding is False:
931 if compat.PYTHON3:
932 self.valueEncoding = encoding.get_local_encoding()
933 self.valueErrors = encoding.default_local_errors
934 else:
935 self.valueEncoding = None
936 self.valueErrors = None
937 else:
938 self.valueEncoding = valueEncoding
939 if valueErrors is False:
940 self.valueErrors = encoding.default_local_errors
941 else:
942 self.valueErrors = valueErrors
943
944 def _makeBSERCodec(self, codec):
945 def make_codec(transport):
946 return codec(transport, self.valueEncoding, self.valueErrors)
947
948 return make_codec
949
800 def _parseEncoding(self, enc):
950 def _parseEncoding(self, enc):
801 if enc == 'bser':
951 if enc == "bser":
802 if self.useImmutableBser:
952 if self.useImmutableBser:
803 return ImmutableBserCodec
953 return self._makeBSERCodec(ImmutableBser2Codec)
804 return BserCodec
954 return self._makeBSERCodec(Bser2WithFallbackCodec)
805 elif enc == 'experimental-bser-v2':
955 elif enc == "bser-v1":
806 return Bser2WithFallbackCodec
956 if compat.PYTHON3:
807 elif enc == 'json':
957 raise BSERv1Unsupported(
958 "Python 3 does not support the BSER v1 encoding: specify "
959 '"bser" or omit the sendEncoding and recvEncoding '
960 "arguments"
961 )
962 if self.useImmutableBser:
963 return self._makeBSERCodec(ImmutableBserCodec)
964 return self._makeBSERCodec(BserCodec)
965 elif enc == "json":
808 return JsonCodec
966 return JsonCodec
809 else:
967 else:
810 raise WatchmanError('invalid encoding %s' % enc)
968 raise WatchmanError("invalid encoding %s" % enc)
811
969
812 def _hasprop(self, result, name):
970 def _hasprop(self, result, name):
813 if self.useImmutableBser:
971 if self.useImmutableBser:
@@ -817,26 +975,25 b' class client(object):'
817 def _resolvesockname(self):
975 def _resolvesockname(self):
818 # if invoked via a trigger, watchman will set this env var; we
976 # if invoked via a trigger, watchman will set this env var; we
819 # should use it unless explicitly set otherwise
977 # should use it unless explicitly set otherwise
820 path = os.getenv('WATCHMAN_SOCK')
978 path = os.getenv("WATCHMAN_SOCK")
821 if path:
979 if path:
822 return path
980 return path
823
981
824 cmd = [self.watchman_exe, '--output-encoding=bser', 'get-sockname']
982 cmd = [self.binpath, "--output-encoding=bser", "get-sockname"]
825 try:
983 try:
826 args = dict(stdout=subprocess.PIPE,
984 args = dict(
827 stderr=subprocess.PIPE,
985 stdout=subprocess.PIPE, stderr=subprocess.PIPE
828 close_fds=os.name != 'nt')
986 ) # noqa: C408
829
987
830 if os.name == 'nt':
988 if os.name == "nt":
831 # if invoked via an application with graphical user interface,
989 # if invoked via an application with graphical user interface,
832 # this call will cause a brief command window pop-up.
990 # this call will cause a brief command window pop-up.
833 # Using the flag STARTF_USESHOWWINDOW to avoid this behavior.
991 # Using the flag STARTF_USESHOWWINDOW to avoid this behavior.
834 startupinfo = subprocess.STARTUPINFO()
992 startupinfo = subprocess.STARTUPINFO()
835 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
993 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
836 args['startupinfo'] = startupinfo
994 args["startupinfo"] = startupinfo
837
995
838 p = subprocess.Popen(pycompat.rapply(procutil.tonativestr, cmd),
996 p = subprocess.Popen(cmd, **args)
839 **args)
840
997
841 except OSError as e:
998 except OSError as e:
842 raise WatchmanError('"watchman" executable not in PATH (%s)' % e)
999 raise WatchmanError('"watchman" executable not in PATH (%s)' % e)
@@ -848,27 +1005,43 b' class client(object):'
848 raise WatchmanError("watchman exited with code %d" % exitcode)
1005 raise WatchmanError("watchman exited with code %d" % exitcode)
849
1006
850 result = bser.loads(stdout)
1007 result = bser.loads(stdout)
851 if b'error' in result:
1008 if "error" in result:
852 raise WatchmanError('get-sockname error: %s' % result['error'])
1009 raise WatchmanError("get-sockname error: %s" % result["error"])
853
1010
854 return result[b'sockname']
1011 return result["sockname"]
855
1012
856 def _connect(self):
1013 def _connect(self):
857 """ establish transport connection """
1014 """ establish transport connection """
858
1015
859 if self.recvConn:
1016 if self.recvConn:
1017 if self.pid != os.getpid():
1018 raise UseAfterFork(
1019 "do not re-use a connection after fork; open a new client instead"
1020 )
860 return
1021 return
861
1022
862 if self.sockpath is None:
1023 if self.sockpath is None:
863 self.sockpath = self._resolvesockname()
1024 self.sockpath = self._resolvesockname()
864
1025
865 self.tport = self.transport(self.sockpath, self.timeout, self.watchman_exe)
1026 kwargs = {}
1027 if self.transport == CLIProcessTransport:
1028 kwargs["binpath"] = self.binpath
1029
1030 self.tport = self.transport(self.sockpath, self.timeout, **kwargs)
866 self.sendConn = self.sendCodec(self.tport)
1031 self.sendConn = self.sendCodec(self.tport)
867 self.recvConn = self.recvCodec(self.tport)
1032 self.recvConn = self.recvCodec(self.tport)
1033 self.pid = os.getpid()
868
1034
869 def __del__(self):
1035 def __del__(self):
870 self.close()
1036 self.close()
871
1037
1038 def __enter__(self):
1039 self._connect()
1040 return self
1041
1042 def __exit__(self, exc_type, exc_value, exc_traceback):
1043 self.close()
1044
872 def close(self):
1045 def close(self):
873 if self.tport:
1046 if self.tport:
874 self.tport.close()
1047 self.tport.close()
@@ -893,26 +1066,20 b' class client(object):'
893
1066
894 self._connect()
1067 self._connect()
895 result = self.recvConn.receive()
1068 result = self.recvConn.receive()
896 if self._hasprop(result, 'error'):
1069 if self._hasprop(result, "error"):
897 error = result['error']
1070 raise CommandError(result["error"])
898 if compat.PYTHON3 and isinstance(self.recvConn, BserCodec):
899 error = result['error'].decode('utf-8', 'surrogateescape')
900 raise CommandError(error)
901
1071
902 if self._hasprop(result, 'log'):
1072 if self._hasprop(result, "log"):
903 log = result['log']
1073 self.logs.append(result["log"])
904 if compat.PYTHON3 and isinstance(self.recvConn, BserCodec):
905 log = log.decode('utf-8', 'surrogateescape')
906 self.logs.append(log)
907
1074
908 if self._hasprop(result, 'subscription'):
1075 if self._hasprop(result, "subscription"):
909 sub = result['subscription']
1076 sub = result["subscription"]
910 if not (sub in self.subs):
1077 if not (sub in self.subs):
911 self.subs[sub] = []
1078 self.subs[sub] = []
912 self.subs[sub].append(result)
1079 self.subs[sub].append(result)
913
1080
914 # also accumulate in {root,sub} keyed store
1081 # also accumulate in {root,sub} keyed store
915 root = os.path.normcase(result['root'])
1082 root = os.path.normpath(os.path.normcase(result["root"]))
916 if not root in self.sub_by_root:
1083 if not root in self.sub_by_root:
917 self.sub_by_root[root] = {}
1084 self.sub_by_root[root] = {}
918 if not sub in self.sub_by_root[root]:
1085 if not sub in self.sub_by_root[root]:
@@ -922,7 +1089,7 b' class client(object):'
922 return result
1089 return result
923
1090
924 def isUnilateralResponse(self, res):
1091 def isUnilateralResponse(self, res):
925 if 'unilateral' in res and res['unilateral']:
1092 if "unilateral" in res and res["unilateral"]:
926 return True
1093 return True
927 # Fall back to checking for known unilateral responses
1094 # Fall back to checking for known unilateral responses
928 for k in self.unilateral:
1095 for k in self.unilateral:
@@ -955,18 +1122,11 b' class client(object):'
955 remove processing impacts both the unscoped and scoped stores
1122 remove processing impacts both the unscoped and scoped stores
956 for the subscription data.
1123 for the subscription data.
957 """
1124 """
958 if compat.PYTHON3 and issubclass(self.recvCodec, BserCodec):
959 # People may pass in Unicode strings here -- but currently BSER only
960 # returns bytestrings. Deal with that.
961 if isinstance(root, str):
962 root = encoding.encode_local(root)
963 if isinstance(name, str):
964 name = name.encode('utf-8')
965
966 if root is not None:
1125 if root is not None:
967 if not root in self.sub_by_root:
1126 root = os.path.normpath(os.path.normcase(root))
1127 if root not in self.sub_by_root:
968 return None
1128 return None
969 if not name in self.sub_by_root[root]:
1129 if name not in self.sub_by_root[root]:
970 return None
1130 return None
971 sub = self.sub_by_root[root][name]
1131 sub = self.sub_by_root[root][name]
972 if remove:
1132 if remove:
@@ -976,7 +1136,7 b' class client(object):'
976 del self.subs[name]
1136 del self.subs[name]
977 return sub
1137 return sub
978
1138
979 if not (name in self.subs):
1139 if name not in self.subs:
980 return None
1140 return None
981 sub = self.subs[name]
1141 sub = self.subs[name]
982 if remove:
1142 if remove:
@@ -992,7 +1152,7 b' class client(object):'
992 and NOT returned via this method.
1152 and NOT returned via this method.
993 """
1153 """
994
1154
995 log('calling client.query')
1155 log("calling client.query")
996 self._connect()
1156 self._connect()
997 try:
1157 try:
998 self.sendConn.send(args)
1158 self.sendConn.send(args)
@@ -1006,27 +1166,27 b' class client(object):'
1006 # When we can depend on Python 3, we can use PEP 3134
1166 # When we can depend on Python 3, we can use PEP 3134
1007 # exception chaining here.
1167 # exception chaining here.
1008 raise WatchmanEnvironmentError(
1168 raise WatchmanEnvironmentError(
1009 'I/O error communicating with watchman daemon',
1169 "I/O error communicating with watchman daemon",
1010 ee.errno,
1170 ee.errno,
1011 ee.strerror,
1171 ee.strerror,
1012 args)
1172 args,
1173 )
1013 except WatchmanError as ex:
1174 except WatchmanError as ex:
1014 ex.setCommand(args)
1175 ex.setCommand(args)
1015 raise
1176 raise
1016
1177
1017 def capabilityCheck(self, optional=None, required=None):
1178 def capabilityCheck(self, optional=None, required=None):
1018 """ Perform a server capability check """
1179 """ Perform a server capability check """
1019 res = self.query('version', {
1180 res = self.query(
1020 'optional': optional or [],
1181 "version", {"optional": optional or [], "required": required or []}
1021 'required': required or []
1182 )
1022 })
1023
1183
1024 if not self._hasprop(res, 'capabilities'):
1184 if not self._hasprop(res, "capabilities"):
1025 # Server doesn't support capabilities, so we need to
1185 # Server doesn't support capabilities, so we need to
1026 # synthesize the results based on the version
1186 # synthesize the results based on the version
1027 capabilities.synthesize(res, optional)
1187 capabilities.synthesize(res, optional)
1028 if 'error' in res:
1188 if "error" in res:
1029 raise CommandError(res['error'])
1189 raise CommandError(res["error"])
1030
1190
1031 return res
1191 return res
1032
1192
@@ -175,7 +175,22 b' static PyObject* bserobj_getattrro(PyObj'
175 const char* item_name = NULL;
175 const char* item_name = NULL;
176 PyObject* key = PyTuple_GET_ITEM(obj->keys, i);
176 PyObject* key = PyTuple_GET_ITEM(obj->keys, i);
177
177
178 item_name = PyBytes_AsString(key);
178 if (PyUnicode_Check(key)) {
179 #if PY_MAJOR_VERSION >= 3
180 item_name = PyUnicode_AsUTF8(key);
181 #else
182 PyObject* utf = PyUnicode_AsEncodedString(key, "utf-8", "ignore");
183 if (utf == NULL) {
184 goto bail;
185 }
186 item_name = PyBytes_AsString(utf);
187 #endif
188 } else {
189 item_name = PyBytes_AsString(key);
190 }
191 if (item_name == NULL) {
192 goto bail;
193 }
179 if (!strcmp(item_name, namestr)) {
194 if (!strcmp(item_name, namestr)) {
180 ret = PySequence_GetItem(obj->values, i);
195 ret = PySequence_GetItem(obj->values, i);
181 goto bail;
196 goto bail;
@@ -1147,11 +1162,15 b' static PyObject* bser_loads(PyObject* se'
1147 }
1162 }
1148
1163
1149 static PyObject* bser_load(PyObject* self, PyObject* args, PyObject* kw) {
1164 static PyObject* bser_load(PyObject* self, PyObject* args, PyObject* kw) {
1150 PyObject *load, *string;
1165 PyObject* load;
1166 PyObject* load_method;
1167 PyObject* string;
1168 PyObject* load_method_args;
1169 PyObject* load_method_kwargs;
1151 PyObject* fp = NULL;
1170 PyObject* fp = NULL;
1152 PyObject* mutable_obj = NULL;
1171 PyObject* mutable_obj = NULL;
1153 const char* value_encoding = NULL;
1172 PyObject* value_encoding = NULL;
1154 const char* value_errors = NULL;
1173 PyObject* value_errors = NULL;
1155
1174
1156 static char* kw_list[] = {
1175 static char* kw_list[] = {
1157 "fp", "mutable", "value_encoding", "value_errors", NULL};
1176 "fp", "mutable", "value_encoding", "value_errors", NULL};
@@ -1159,7 +1178,7 b' static PyObject* bser_load(PyObject* sel'
1159 if (!PyArg_ParseTupleAndKeywords(
1178 if (!PyArg_ParseTupleAndKeywords(
1160 args,
1179 args,
1161 kw,
1180 kw,
1162 "OOzz:load",
1181 "O|OOO:load",
1163 kw_list,
1182 kw_list,
1164 &fp,
1183 &fp,
1165 &mutable_obj,
1184 &mutable_obj,
@@ -1172,8 +1191,33 b' static PyObject* bser_load(PyObject* sel'
1172 if (load == NULL) {
1191 if (load == NULL) {
1173 return NULL;
1192 return NULL;
1174 }
1193 }
1175 string = PyObject_CallMethod(
1194 load_method = PyObject_GetAttrString(load, "load");
1176 load, "load", "OOzz", fp, mutable_obj, value_encoding, value_errors);
1195 if (load_method == NULL) {
1196 return NULL;
1197 }
1198 // Mandatory method arguments
1199 load_method_args = Py_BuildValue("(O)", fp);
1200 if (load_method_args == NULL) {
1201 return NULL;
1202 }
1203 // Optional method arguments
1204 load_method_kwargs = PyDict_New();
1205 if (load_method_kwargs == NULL) {
1206 return NULL;
1207 }
1208 if (mutable_obj) {
1209 PyDict_SetItemString(load_method_kwargs, "mutable", mutable_obj);
1210 }
1211 if (value_encoding) {
1212 PyDict_SetItemString(load_method_kwargs, "value_encoding", value_encoding);
1213 }
1214 if (value_errors) {
1215 PyDict_SetItemString(load_method_kwargs, "value_errors", value_errors);
1216 }
1217 string = PyObject_Call(load_method, load_method_args, load_method_kwargs);
1218 Py_DECREF(load_method_kwargs);
1219 Py_DECREF(load_method_args);
1220 Py_DECREF(load_method);
1177 Py_DECREF(load);
1221 Py_DECREF(load);
1178 return string;
1222 return string;
1179 }
1223 }
@@ -26,20 +26,20 b''
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
29 from __future__ import absolute_import
30 from __future__ import division
31 from __future__ import print_function
32 # no unicode literals
29 # no unicode literals
30 from __future__ import absolute_import, division, print_function
33
31
34 import re
32 import re
35
33
34
36 def parse_version(vstr):
35 def parse_version(vstr):
37 res = 0
36 res = 0
38 for n in vstr.split('.'):
37 for n in vstr.split("."):
39 res = res * 1000
38 res = res * 1000
40 res = res + int(n)
39 res = res + int(n)
41 return res
40 return res
42
41
42
43 cap_versions = {
43 cap_versions = {
44 "cmd-watch-del-all": "3.1.1",
44 "cmd-watch-del-all": "3.1.1",
45 "cmd-watch-project": "3.1",
45 "cmd-watch-project": "3.1",
@@ -49,23 +49,29 b' cap_versions = {'
49 "wildmatch": "3.7",
49 "wildmatch": "3.7",
50 }
50 }
51
51
52
52 def check(version, name):
53 def check(version, name):
53 if name in cap_versions:
54 if name in cap_versions:
54 return version >= parse_version(cap_versions[name])
55 return version >= parse_version(cap_versions[name])
55 return False
56 return False
56
57
58
57 def synthesize(vers, opts):
59 def synthesize(vers, opts):
58 """ Synthesize a capability enabled version response
60 """ Synthesize a capability enabled version response
59 This is a very limited emulation for relatively recent feature sets
61 This is a very limited emulation for relatively recent feature sets
60 """
62 """
61 parsed_version = parse_version(vers['version'])
63 parsed_version = parse_version(vers["version"])
62 vers['capabilities'] = {}
64 vers["capabilities"] = {}
63 for name in opts['optional']:
65 for name in opts["optional"]:
64 vers['capabilities'][name] = check(parsed_version, name)
66 vers["capabilities"][name] = check(parsed_version, name)
65 for name in opts['required']:
67 failed = False # noqa: F841 T25377293 Grandfathered in
68 for name in opts["required"]:
66 have = check(parsed_version, name)
69 have = check(parsed_version, name)
67 vers['capabilities'][name] = have
70 vers["capabilities"][name] = have
68 if not have:
71 if not have:
69 vers['error'] = 'client required capability `' + name + \
72 vers["error"] = (
70 '` is not supported by this server'
73 "client required capability `"
74 + name
75 + "` is not supported by this server"
76 )
71 return vers
77 return vers
@@ -26,20 +26,22 b''
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
29 from __future__ import absolute_import
30 from __future__ import division
31 from __future__ import print_function
32 # no unicode literals
29 # no unicode literals
33
30 from __future__ import absolute_import, division, print_function
34 '''Compatibility module across Python 2 and 3.'''
35
31
36 import sys
32 import sys
37
33
34
35 """Compatibility module across Python 2 and 3."""
36
37
38 PYTHON2 = sys.version_info < (3, 0)
38 PYTHON3 = sys.version_info >= (3, 0)
39 PYTHON3 = sys.version_info >= (3, 0)
39
40
40 # This is adapted from https://bitbucket.org/gutworth/six, and used under the
41 # This is adapted from https://bitbucket.org/gutworth/six, and used under the
41 # MIT license. See LICENSE for a full copyright notice.
42 # MIT license. See LICENSE for a full copyright notice.
42 if PYTHON3:
43 if PYTHON3:
44
43 def reraise(tp, value, tb=None):
45 def reraise(tp, value, tb=None):
44 try:
46 try:
45 if value is None:
47 if value is None:
@@ -50,16 +52,20 b' if PYTHON3:'
50 finally:
52 finally:
51 value = None
53 value = None
52 tb = None
54 tb = None
55
56
53 else:
57 else:
54 exec('''
58 exec(
59 """
55 def reraise(tp, value, tb=None):
60 def reraise(tp, value, tb=None):
56 try:
61 try:
57 raise tp, value, tb
62 raise tp, value, tb
58 finally:
63 finally:
59 tb = None
64 tb = None
60 '''.strip())
65 """.strip()
66 )
61
67
62 if PYTHON3:
68 if PYTHON3:
63 UNICODE = str
69 UNICODE = str
64 else:
70 else:
65 UNICODE = unicode
71 UNICODE = unicode # noqa: F821 We handled versioning above
@@ -26,48 +26,50 b''
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
29 from __future__ import absolute_import
30 from __future__ import division
31 from __future__ import print_function
32 # no unicode literals
29 # no unicode literals
33
30 from __future__ import absolute_import, division, print_function
34 '''Module to deal with filename encoding on the local system, as returned by
35 Watchman.'''
36
31
37 import sys
32 import sys
38
33
39 from . import (
34 from . import compat
40 compat,
35
41 )
36
37 """Module to deal with filename encoding on the local system, as returned by
38 Watchman."""
39
42
40
43 if compat.PYTHON3:
41 if compat.PYTHON3:
44 default_local_errors = 'surrogateescape'
42 default_local_errors = "surrogateescape"
45
43
46 def get_local_encoding():
44 def get_local_encoding():
47 if sys.platform == 'win32':
45 if sys.platform == "win32":
48 # Watchman always returns UTF-8 encoded strings on Windows.
46 # Watchman always returns UTF-8 encoded strings on Windows.
49 return 'utf-8'
47 return "utf-8"
50 # On the Python 3 versions we support, sys.getfilesystemencoding never
48 # On the Python 3 versions we support, sys.getfilesystemencoding never
51 # returns None.
49 # returns None.
52 return sys.getfilesystemencoding()
50 return sys.getfilesystemencoding()
51
52
53 else:
53 else:
54 # Python 2 doesn't support surrogateescape, so use 'strict' by
54 # Python 2 doesn't support surrogateescape, so use 'strict' by
55 # default. Users can register a custom surrogateescape error handler and use
55 # default. Users can register a custom surrogateescape error handler and use
56 # that if they so desire.
56 # that if they so desire.
57 default_local_errors = 'strict'
57 default_local_errors = "strict"
58
58
59 def get_local_encoding():
59 def get_local_encoding():
60 if sys.platform == 'win32':
60 if sys.platform == "win32":
61 # Watchman always returns UTF-8 encoded strings on Windows.
61 # Watchman always returns UTF-8 encoded strings on Windows.
62 return 'utf-8'
62 return "utf-8"
63 fsencoding = sys.getfilesystemencoding()
63 fsencoding = sys.getfilesystemencoding()
64 if fsencoding is None:
64 if fsencoding is None:
65 # This is very unlikely to happen, but if it does, just use UTF-8
65 # This is very unlikely to happen, but if it does, just use UTF-8
66 fsencoding = 'utf-8'
66 fsencoding = "utf-8"
67 return fsencoding
67 return fsencoding
68
68
69
69 def encode_local(s):
70 def encode_local(s):
70 return s.encode(get_local_encoding(), default_local_errors)
71 return s.encode(get_local_encoding(), default_local_errors)
71
72
73
72 def decode_local(bs):
74 def decode_local(bs):
73 return bs.decode(get_local_encoding(), default_local_errors)
75 return bs.decode(get_local_encoding(), default_local_errors)
@@ -26,17 +26,17 b''
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
29 from __future__ import absolute_import
30 from __future__ import division
31 from __future__ import print_function
32 # no unicode literals
29 # no unicode literals
30 from __future__ import absolute_import, division, print_function
31
32 import ctypes
33
33
34
34 try:
35 try:
35 from . import bser
36 from . import bser
36 except ImportError:
37 except ImportError:
37 from . import pybser as bser
38 from . import pybser as bser
38
39
39 import ctypes
40
40
41 EMPTY_HEADER = b"\x00\x01\x05\x00\x00\x00\x00"
41 EMPTY_HEADER = b"\x00\x01\x05\x00\x00\x00\x00"
42
42
@@ -95,13 +95,15 b' def load(fp, mutable=True, value_encodin'
95 ctypes.resize(buf, total_len)
95 ctypes.resize(buf, total_len)
96
96
97 body = (ctypes.c_char * (total_len - len(header))).from_buffer(
97 body = (ctypes.c_char * (total_len - len(header))).from_buffer(
98 buf, len(header))
98 buf, len(header)
99 )
99 read_len = _read_bytes(fp, body)
100 read_len = _read_bytes(fp, body)
100 if read_len < len(body):
101 if read_len < len(body):
101 raise RuntimeError('bser data ended early')
102 raise RuntimeError("bser data ended early")
102
103
103 return bser.loads(
104 return bser.loads(
104 (ctypes.c_char * total_len).from_buffer(buf, 0),
105 (ctypes.c_char * total_len).from_buffer(buf, 0),
105 mutable,
106 mutable,
106 value_encoding,
107 value_encoding,
107 value_errors)
108 value_errors,
109 )
@@ -26,10 +26,8 b''
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
29 from __future__ import absolute_import
30 from __future__ import division
31 from __future__ import print_function
32 # no unicode literals
29 # no unicode literals
30 from __future__ import absolute_import, division, print_function
33
31
34 import binascii
32 import binascii
35 import collections
33 import collections
@@ -37,30 +35,31 b' import ctypes'
37 import struct
35 import struct
38 import sys
36 import sys
39
37
40 from . import (
38 from . import compat
41 compat,
39
42 )
43
40
44 BSER_ARRAY = b'\x00'
41 BSER_ARRAY = b"\x00"
45 BSER_OBJECT = b'\x01'
42 BSER_OBJECT = b"\x01"
46 BSER_BYTESTRING = b'\x02'
43 BSER_BYTESTRING = b"\x02"
47 BSER_INT8 = b'\x03'
44 BSER_INT8 = b"\x03"
48 BSER_INT16 = b'\x04'
45 BSER_INT16 = b"\x04"
49 BSER_INT32 = b'\x05'
46 BSER_INT32 = b"\x05"
50 BSER_INT64 = b'\x06'
47 BSER_INT64 = b"\x06"
51 BSER_REAL = b'\x07'
48 BSER_REAL = b"\x07"
52 BSER_TRUE = b'\x08'
49 BSER_TRUE = b"\x08"
53 BSER_FALSE = b'\x09'
50 BSER_FALSE = b"\x09"
54 BSER_NULL = b'\x0a'
51 BSER_NULL = b"\x0a"
55 BSER_TEMPLATE = b'\x0b'
52 BSER_TEMPLATE = b"\x0b"
56 BSER_SKIP = b'\x0c'
53 BSER_SKIP = b"\x0c"
57 BSER_UTF8STRING = b'\x0d'
54 BSER_UTF8STRING = b"\x0d"
58
55
59 if compat.PYTHON3:
56 if compat.PYTHON3:
60 STRING_TYPES = (str, bytes)
57 STRING_TYPES = (str, bytes)
61 unicode = str
58 unicode = str
59
62 def tobytes(i):
60 def tobytes(i):
63 return str(i).encode('ascii')
61 return str(i).encode("ascii")
62
64 long = int
63 long = int
65 else:
64 else:
66 STRING_TYPES = (unicode, str)
65 STRING_TYPES = (unicode, str)
@@ -72,6 +71,7 b' else:'
72 EMPTY_HEADER = b"\x00\x01\x05\x00\x00\x00\x00"
71 EMPTY_HEADER = b"\x00\x01\x05\x00\x00\x00\x00"
73 EMPTY_HEADER_V2 = b"\x00\x02\x00\x00\x00\x00\x05\x00\x00\x00\x00"
72 EMPTY_HEADER_V2 = b"\x00\x02\x00\x00\x00\x00\x05\x00\x00\x00\x00"
74
73
74
75 def _int_size(x):
75 def _int_size(x):
76 """Return the smallest size int that can store the value"""
76 """Return the smallest size int that can store the value"""
77 if -0x80 <= x <= 0x7F:
77 if -0x80 <= x <= 0x7F:
@@ -83,29 +83,34 b' def _int_size(x):'
83 elif long(-0x8000000000000000) <= x <= long(0x7FFFFFFFFFFFFFFF):
83 elif long(-0x8000000000000000) <= x <= long(0x7FFFFFFFFFFFFFFF):
84 return 8
84 return 8
85 else:
85 else:
86 raise RuntimeError('Cannot represent value: ' + str(x))
86 raise RuntimeError("Cannot represent value: " + str(x))
87
87
88
88 def _buf_pos(buf, pos):
89 def _buf_pos(buf, pos):
89 ret = buf[pos]
90 ret = buf[pos]
90 # In Python 2, buf is a str array so buf[pos] is a string. In Python 3, buf
91 # Normalize the return type to bytes
91 # is a bytes array and buf[pos] is an integer.
92 if compat.PYTHON3 and not isinstance(ret, bytes):
92 if compat.PYTHON3:
93 ret = bytes((ret,))
93 ret = bytes((ret,))
94 return ret
94 return ret
95
95
96
96 class _bser_buffer(object):
97 class _bser_buffer(object):
97
98 def __init__(self, version):
98 def __init__(self, version):
99 self.bser_version = version
99 self.bser_version = version
100 self.buf = ctypes.create_string_buffer(8192)
100 self.buf = ctypes.create_string_buffer(8192)
101 if self.bser_version == 1:
101 if self.bser_version == 1:
102 struct.pack_into(tobytes(len(EMPTY_HEADER)) + b's', self.buf, 0,
102 struct.pack_into(
103 EMPTY_HEADER)
103 tobytes(len(EMPTY_HEADER)) + b"s", self.buf, 0, EMPTY_HEADER
104 )
104 self.wpos = len(EMPTY_HEADER)
105 self.wpos = len(EMPTY_HEADER)
105 else:
106 else:
106 assert self.bser_version == 2
107 assert self.bser_version == 2
107 struct.pack_into(tobytes(len(EMPTY_HEADER_V2)) + b's', self.buf, 0,
108 struct.pack_into(
108 EMPTY_HEADER_V2)
109 tobytes(len(EMPTY_HEADER_V2)) + b"s",
110 self.buf,
111 0,
112 EMPTY_HEADER_V2,
113 )
109 self.wpos = len(EMPTY_HEADER_V2)
114 self.wpos = len(EMPTY_HEADER_V2)
110
115
111 def ensure_size(self, size):
116 def ensure_size(self, size):
@@ -117,42 +122,68 b' class _bser_buffer(object):'
117 to_write = size + 1
122 to_write = size + 1
118 self.ensure_size(to_write)
123 self.ensure_size(to_write)
119 if size == 1:
124 if size == 1:
120 struct.pack_into(b'=cb', self.buf, self.wpos, BSER_INT8, val)
125 struct.pack_into(b"=cb", self.buf, self.wpos, BSER_INT8, val)
121 elif size == 2:
126 elif size == 2:
122 struct.pack_into(b'=ch', self.buf, self.wpos, BSER_INT16, val)
127 struct.pack_into(b"=ch", self.buf, self.wpos, BSER_INT16, val)
123 elif size == 4:
128 elif size == 4:
124 struct.pack_into(b'=ci', self.buf, self.wpos, BSER_INT32, val)
129 struct.pack_into(b"=ci", self.buf, self.wpos, BSER_INT32, val)
125 elif size == 8:
130 elif size == 8:
126 struct.pack_into(b'=cq', self.buf, self.wpos, BSER_INT64, val)
131 struct.pack_into(b"=cq", self.buf, self.wpos, BSER_INT64, val)
127 else:
132 else:
128 raise RuntimeError('Cannot represent this long value')
133 raise RuntimeError("Cannot represent this long value")
129 self.wpos += to_write
134 self.wpos += to_write
130
135
131
132 def append_string(self, s):
136 def append_string(self, s):
133 if isinstance(s, unicode):
137 if isinstance(s, unicode):
134 s = s.encode('utf-8')
138 s = s.encode("utf-8")
135 s_len = len(s)
139 s_len = len(s)
136 size = _int_size(s_len)
140 size = _int_size(s_len)
137 to_write = 2 + size + s_len
141 to_write = 2 + size + s_len
138 self.ensure_size(to_write)
142 self.ensure_size(to_write)
139 if size == 1:
143 if size == 1:
140 struct.pack_into(b'=ccb' + tobytes(s_len) + b's', self.buf,
144 struct.pack_into(
141 self.wpos, BSER_BYTESTRING, BSER_INT8, s_len, s)
145 b"=ccb" + tobytes(s_len) + b"s",
146 self.buf,
147 self.wpos,
148 BSER_BYTESTRING,
149 BSER_INT8,
150 s_len,
151 s,
152 )
142 elif size == 2:
153 elif size == 2:
143 struct.pack_into(b'=cch' + tobytes(s_len) + b's', self.buf,
154 struct.pack_into(
144 self.wpos, BSER_BYTESTRING, BSER_INT16, s_len, s)
155 b"=cch" + tobytes(s_len) + b"s",
156 self.buf,
157 self.wpos,
158 BSER_BYTESTRING,
159 BSER_INT16,
160 s_len,
161 s,
162 )
145 elif size == 4:
163 elif size == 4:
146 struct.pack_into(b'=cci' + tobytes(s_len) + b's', self.buf,
164 struct.pack_into(
147 self.wpos, BSER_BYTESTRING, BSER_INT32, s_len, s)
165 b"=cci" + tobytes(s_len) + b"s",
166 self.buf,
167 self.wpos,
168 BSER_BYTESTRING,
169 BSER_INT32,
170 s_len,
171 s,
172 )
148 elif size == 8:
173 elif size == 8:
149 struct.pack_into(b'=ccq' + tobytes(s_len) + b's', self.buf,
174 struct.pack_into(
150 self.wpos, BSER_BYTESTRING, BSER_INT64, s_len, s)
175 b"=ccq" + tobytes(s_len) + b"s",
176 self.buf,
177 self.wpos,
178 BSER_BYTESTRING,
179 BSER_INT64,
180 s_len,
181 s,
182 )
151 else:
183 else:
152 raise RuntimeError('Cannot represent this string value')
184 raise RuntimeError("Cannot represent this string value")
153 self.wpos += to_write
185 self.wpos += to_write
154
186
155
156 def append_recursive(self, val):
187 def append_recursive(self, val):
157 if isinstance(val, bool):
188 if isinstance(val, bool):
158 needed = 1
189 needed = 1
@@ -161,12 +192,12 b' class _bser_buffer(object):'
161 to_encode = BSER_TRUE
192 to_encode = BSER_TRUE
162 else:
193 else:
163 to_encode = BSER_FALSE
194 to_encode = BSER_FALSE
164 struct.pack_into(b'=c', self.buf, self.wpos, to_encode)
195 struct.pack_into(b"=c", self.buf, self.wpos, to_encode)
165 self.wpos += needed
196 self.wpos += needed
166 elif val is None:
197 elif val is None:
167 needed = 1
198 needed = 1
168 self.ensure_size(needed)
199 self.ensure_size(needed)
169 struct.pack_into(b'=c', self.buf, self.wpos, BSER_NULL)
200 struct.pack_into(b"=c", self.buf, self.wpos, BSER_NULL)
170 self.wpos += needed
201 self.wpos += needed
171 elif isinstance(val, (int, long)):
202 elif isinstance(val, (int, long)):
172 self.append_long(val)
203 self.append_long(val)
@@ -175,61 +206,106 b' class _bser_buffer(object):'
175 elif isinstance(val, float):
206 elif isinstance(val, float):
176 needed = 9
207 needed = 9
177 self.ensure_size(needed)
208 self.ensure_size(needed)
178 struct.pack_into(b'=cd', self.buf, self.wpos, BSER_REAL, val)
209 struct.pack_into(b"=cd", self.buf, self.wpos, BSER_REAL, val)
179 self.wpos += needed
210 self.wpos += needed
180 elif isinstance(val, collections.Mapping) and \
211 elif isinstance(val, collections.Mapping) and isinstance(
181 isinstance(val, collections.Sized):
212 val, collections.Sized
213 ):
182 val_len = len(val)
214 val_len = len(val)
183 size = _int_size(val_len)
215 size = _int_size(val_len)
184 needed = 2 + size
216 needed = 2 + size
185 self.ensure_size(needed)
217 self.ensure_size(needed)
186 if size == 1:
218 if size == 1:
187 struct.pack_into(b'=ccb', self.buf, self.wpos, BSER_OBJECT,
219 struct.pack_into(
188 BSER_INT8, val_len)
220 b"=ccb",
221 self.buf,
222 self.wpos,
223 BSER_OBJECT,
224 BSER_INT8,
225 val_len,
226 )
189 elif size == 2:
227 elif size == 2:
190 struct.pack_into(b'=cch', self.buf, self.wpos, BSER_OBJECT,
228 struct.pack_into(
191 BSER_INT16, val_len)
229 b"=cch",
230 self.buf,
231 self.wpos,
232 BSER_OBJECT,
233 BSER_INT16,
234 val_len,
235 )
192 elif size == 4:
236 elif size == 4:
193 struct.pack_into(b'=cci', self.buf, self.wpos, BSER_OBJECT,
237 struct.pack_into(
194 BSER_INT32, val_len)
238 b"=cci",
239 self.buf,
240 self.wpos,
241 BSER_OBJECT,
242 BSER_INT32,
243 val_len,
244 )
195 elif size == 8:
245 elif size == 8:
196 struct.pack_into(b'=ccq', self.buf, self.wpos, BSER_OBJECT,
246 struct.pack_into(
197 BSER_INT64, val_len)
247 b"=ccq",
248 self.buf,
249 self.wpos,
250 BSER_OBJECT,
251 BSER_INT64,
252 val_len,
253 )
198 else:
254 else:
199 raise RuntimeError('Cannot represent this mapping value')
255 raise RuntimeError("Cannot represent this mapping value")
200 self.wpos += needed
256 self.wpos += needed
201 if compat.PYTHON3:
257 if compat.PYTHON3:
202 iteritems = val.items()
258 iteritems = val.items()
203 else:
259 else:
204 iteritems = val.iteritems()
260 iteritems = val.iteritems() # noqa: B301 Checked version above
205 for k, v in iteritems:
261 for k, v in iteritems:
206 self.append_string(k)
262 self.append_string(k)
207 self.append_recursive(v)
263 self.append_recursive(v)
208 elif isinstance(val, collections.Iterable) and \
264 elif isinstance(val, collections.Iterable) and isinstance(
209 isinstance(val, collections.Sized):
265 val, collections.Sized
266 ):
210 val_len = len(val)
267 val_len = len(val)
211 size = _int_size(val_len)
268 size = _int_size(val_len)
212 needed = 2 + size
269 needed = 2 + size
213 self.ensure_size(needed)
270 self.ensure_size(needed)
214 if size == 1:
271 if size == 1:
215 struct.pack_into(b'=ccb', self.buf, self.wpos, BSER_ARRAY,
272 struct.pack_into(
216 BSER_INT8, val_len)
273 b"=ccb", self.buf, self.wpos, BSER_ARRAY, BSER_INT8, val_len
274 )
217 elif size == 2:
275 elif size == 2:
218 struct.pack_into(b'=cch', self.buf, self.wpos, BSER_ARRAY,
276 struct.pack_into(
219 BSER_INT16, val_len)
277 b"=cch",
278 self.buf,
279 self.wpos,
280 BSER_ARRAY,
281 BSER_INT16,
282 val_len,
283 )
220 elif size == 4:
284 elif size == 4:
221 struct.pack_into(b'=cci', self.buf, self.wpos, BSER_ARRAY,
285 struct.pack_into(
222 BSER_INT32, val_len)
286 b"=cci",
287 self.buf,
288 self.wpos,
289 BSER_ARRAY,
290 BSER_INT32,
291 val_len,
292 )
223 elif size == 8:
293 elif size == 8:
224 struct.pack_into(b'=ccq', self.buf, self.wpos, BSER_ARRAY,
294 struct.pack_into(
225 BSER_INT64, val_len)
295 b"=ccq",
296 self.buf,
297 self.wpos,
298 BSER_ARRAY,
299 BSER_INT64,
300 val_len,
301 )
226 else:
302 else:
227 raise RuntimeError('Cannot represent this sequence value')
303 raise RuntimeError("Cannot represent this sequence value")
228 self.wpos += needed
304 self.wpos += needed
229 for v in val:
305 for v in val:
230 self.append_recursive(v)
306 self.append_recursive(v)
231 else:
307 else:
232 raise RuntimeError('Cannot represent unknown value type')
308 raise RuntimeError("Cannot represent unknown value type")
233
309
234
310
235 def dumps(obj, version=1, capabilities=0):
311 def dumps(obj, version=1, capabilities=0):
@@ -238,18 +314,19 b' def dumps(obj, version=1, capabilities=0'
238 # Now fill in the overall length
314 # Now fill in the overall length
239 if version == 1:
315 if version == 1:
240 obj_len = bser_buf.wpos - len(EMPTY_HEADER)
316 obj_len = bser_buf.wpos - len(EMPTY_HEADER)
241 struct.pack_into(b'=i', bser_buf.buf, 3, obj_len)
317 struct.pack_into(b"=i", bser_buf.buf, 3, obj_len)
242 else:
318 else:
243 obj_len = bser_buf.wpos - len(EMPTY_HEADER_V2)
319 obj_len = bser_buf.wpos - len(EMPTY_HEADER_V2)
244 struct.pack_into(b'=i', bser_buf.buf, 2, capabilities)
320 struct.pack_into(b"=i", bser_buf.buf, 2, capabilities)
245 struct.pack_into(b'=i', bser_buf.buf, 7, obj_len)
321 struct.pack_into(b"=i", bser_buf.buf, 7, obj_len)
246 return bser_buf.buf.raw[:bser_buf.wpos]
322 return bser_buf.buf.raw[: bser_buf.wpos]
323
247
324
248 # This is a quack-alike with the bserObjectType in bser.c
325 # This is a quack-alike with the bserObjectType in bser.c
249 # It provides by getattr accessors and getitem for both index
326 # It provides by getattr accessors and getitem for both index
250 # and name.
327 # and name.
251 class _BunserDict(object):
328 class _BunserDict(object):
252 __slots__ = ('_keys', '_values')
329 __slots__ = ("_keys", "_values")
253
330
254 def __init__(self, keys, values):
331 def __init__(self, keys, values):
255 self._keys = keys
332 self._keys = keys
@@ -261,18 +338,19 b' class _BunserDict(object):'
261 def __getitem__(self, key):
338 def __getitem__(self, key):
262 if isinstance(key, (int, long)):
339 if isinstance(key, (int, long)):
263 return self._values[key]
340 return self._values[key]
264 elif key.startswith('st_'):
341 elif key.startswith("st_"):
265 # hack^Wfeature to allow mercurial to use "st_size" to
342 # hack^Wfeature to allow mercurial to use "st_size" to
266 # reference "size"
343 # reference "size"
267 key = key[3:]
344 key = key[3:]
268 try:
345 try:
269 return self._values[self._keys.index(key)]
346 return self._values[self._keys.index(key)]
270 except ValueError:
347 except ValueError:
271 raise KeyError('_BunserDict has no key %s' % key)
348 raise KeyError("_BunserDict has no key %s" % key)
272
349
273 def __len__(self):
350 def __len__(self):
274 return len(self._keys)
351 return len(self._keys)
275
352
353
276 class Bunser(object):
354 class Bunser(object):
277 def __init__(self, mutable=True, value_encoding=None, value_errors=None):
355 def __init__(self, mutable=True, value_encoding=None, value_errors=None):
278 self.mutable = mutable
356 self.mutable = mutable
@@ -281,7 +359,7 b' class Bunser(object):'
281 if value_encoding is None:
359 if value_encoding is None:
282 self.value_errors = None
360 self.value_errors = None
283 elif value_errors is None:
361 elif value_errors is None:
284 self.value_errors = 'strict'
362 self.value_errors = "strict"
285 else:
363 else:
286 self.value_errors = value_errors
364 self.value_errors = value_errors
287
365
@@ -290,33 +368,35 b' class Bunser(object):'
290 try:
368 try:
291 int_type = _buf_pos(buf, pos)
369 int_type = _buf_pos(buf, pos)
292 except IndexError:
370 except IndexError:
293 raise ValueError('Invalid bser int encoding, pos out of range')
371 raise ValueError("Invalid bser int encoding, pos out of range")
294 if int_type == BSER_INT8:
372 if int_type == BSER_INT8:
295 needed = 2
373 needed = 2
296 fmt = b'=b'
374 fmt = b"=b"
297 elif int_type == BSER_INT16:
375 elif int_type == BSER_INT16:
298 needed = 3
376 needed = 3
299 fmt = b'=h'
377 fmt = b"=h"
300 elif int_type == BSER_INT32:
378 elif int_type == BSER_INT32:
301 needed = 5
379 needed = 5
302 fmt = b'=i'
380 fmt = b"=i"
303 elif int_type == BSER_INT64:
381 elif int_type == BSER_INT64:
304 needed = 9
382 needed = 9
305 fmt = b'=q'
383 fmt = b"=q"
306 else:
384 else:
307 raise ValueError('Invalid bser int encoding 0x%s' %
385 raise ValueError(
308 binascii.hexlify(int_type).decode('ascii'))
386 "Invalid bser int encoding 0x%s at position %s"
387 % (binascii.hexlify(int_type).decode("ascii"), pos)
388 )
309 int_val = struct.unpack_from(fmt, buf, pos + 1)[0]
389 int_val = struct.unpack_from(fmt, buf, pos + 1)[0]
310 return (int_val, pos + needed)
390 return (int_val, pos + needed)
311
391
312 def unser_utf8_string(self, buf, pos):
392 def unser_utf8_string(self, buf, pos):
313 str_len, pos = self.unser_int(buf, pos + 1)
393 str_len, pos = self.unser_int(buf, pos + 1)
314 str_val = struct.unpack_from(tobytes(str_len) + b's', buf, pos)[0]
394 str_val = struct.unpack_from(tobytes(str_len) + b"s", buf, pos)[0]
315 return (str_val.decode('utf-8'), pos + str_len)
395 return (str_val.decode("utf-8"), pos + str_len)
316
396
317 def unser_bytestring(self, buf, pos):
397 def unser_bytestring(self, buf, pos):
318 str_len, pos = self.unser_int(buf, pos + 1)
398 str_len, pos = self.unser_int(buf, pos + 1)
319 str_val = struct.unpack_from(tobytes(str_len) + b's', buf, pos)[0]
399 str_val = struct.unpack_from(tobytes(str_len) + b"s", buf, pos)[0]
320 if self.value_encoding is not None:
400 if self.value_encoding is not None:
321 str_val = str_val.decode(self.value_encoding, self.value_errors)
401 str_val = str_val.decode(self.value_encoding, self.value_errors)
322 # str_len stays the same because that's the length in bytes
402 # str_len stays the same because that's the length in bytes
@@ -325,12 +405,12 b' class Bunser(object):'
325 def unser_array(self, buf, pos):
405 def unser_array(self, buf, pos):
326 arr_len, pos = self.unser_int(buf, pos + 1)
406 arr_len, pos = self.unser_int(buf, pos + 1)
327 arr = []
407 arr = []
328 for i in range(arr_len):
408 for _ in range(arr_len):
329 arr_item, pos = self.loads_recursive(buf, pos)
409 arr_item, pos = self.loads_recursive(buf, pos)
330 arr.append(arr_item)
410 arr.append(arr_item)
331
411
332 if not self.mutable:
412 if not self.mutable:
333 arr = tuple(arr)
413 arr = tuple(arr)
334
414
335 return arr, pos
415 return arr, pos
336
416
@@ -342,7 +422,7 b' class Bunser(object):'
342 keys = []
422 keys = []
343 vals = []
423 vals = []
344
424
345 for i in range(obj_len):
425 for _ in range(obj_len):
346 key, pos = self.unser_utf8_string(buf, pos)
426 key, pos = self.unser_utf8_string(buf, pos)
347 val, pos = self.loads_recursive(buf, pos)
427 val, pos = self.loads_recursive(buf, pos)
348 if self.mutable:
428 if self.mutable:
@@ -359,13 +439,13 b' class Bunser(object):'
359 def unser_template(self, buf, pos):
439 def unser_template(self, buf, pos):
360 val_type = _buf_pos(buf, pos + 1)
440 val_type = _buf_pos(buf, pos + 1)
361 if val_type != BSER_ARRAY:
441 if val_type != BSER_ARRAY:
362 raise RuntimeError('Expect ARRAY to follow TEMPLATE')
442 raise RuntimeError("Expect ARRAY to follow TEMPLATE")
363 # force UTF-8 on keys
443 # force UTF-8 on keys
364 keys_bunser = Bunser(mutable=self.mutable, value_encoding='utf-8')
444 keys_bunser = Bunser(mutable=self.mutable, value_encoding="utf-8")
365 keys, pos = keys_bunser.unser_array(buf, pos + 1)
445 keys, pos = keys_bunser.unser_array(buf, pos + 1)
366 nitems, pos = self.unser_int(buf, pos)
446 nitems, pos = self.unser_int(buf, pos)
367 arr = []
447 arr = []
368 for i in range(nitems):
448 for _ in range(nitems):
369 if self.mutable:
449 if self.mutable:
370 obj = {}
450 obj = {}
371 else:
451 else:
@@ -392,11 +472,15 b' class Bunser(object):'
392
472
393 def loads_recursive(self, buf, pos):
473 def loads_recursive(self, buf, pos):
394 val_type = _buf_pos(buf, pos)
474 val_type = _buf_pos(buf, pos)
395 if (val_type == BSER_INT8 or val_type == BSER_INT16 or
475 if (
396 val_type == BSER_INT32 or val_type == BSER_INT64):
476 val_type == BSER_INT8
477 or val_type == BSER_INT16
478 or val_type == BSER_INT32
479 or val_type == BSER_INT64
480 ):
397 return self.unser_int(buf, pos)
481 return self.unser_int(buf, pos)
398 elif val_type == BSER_REAL:
482 elif val_type == BSER_REAL:
399 val = struct.unpack_from(b'=d', buf, pos + 1)[0]
483 val = struct.unpack_from(b"=d", buf, pos + 1)[0]
400 return (val, pos + 9)
484 return (val, pos + 9)
401 elif val_type == BSER_TRUE:
485 elif val_type == BSER_TRUE:
402 return (True, pos + 1)
486 return (True, pos + 1)
@@ -415,23 +499,26 b' class Bunser(object):'
415 elif val_type == BSER_TEMPLATE:
499 elif val_type == BSER_TEMPLATE:
416 return self.unser_template(buf, pos)
500 return self.unser_template(buf, pos)
417 else:
501 else:
418 raise ValueError('unhandled bser opcode 0x%s' %
502 raise ValueError(
419 binascii.hexlify(val_type).decode('ascii'))
503 "unhandled bser opcode 0x%s"
504 % binascii.hexlify(val_type).decode("ascii")
505 )
420
506
421
507
422 def _pdu_info_helper(buf):
508 def _pdu_info_helper(buf):
509 bser_version = -1
423 if buf[0:2] == EMPTY_HEADER[0:2]:
510 if buf[0:2] == EMPTY_HEADER[0:2]:
424 bser_version = 1
511 bser_version = 1
425 bser_capabilities = 0
512 bser_capabilities = 0
426 expected_len, pos2 = Bunser.unser_int(buf, 2)
513 expected_len, pos2 = Bunser.unser_int(buf, 2)
427 elif buf[0:2] == EMPTY_HEADER_V2[0:2]:
514 elif buf[0:2] == EMPTY_HEADER_V2[0:2]:
428 if len(buf) < 8:
515 if len(buf) < 8:
429 raise ValueError('Invalid BSER header')
516 raise ValueError("Invalid BSER header")
430 bser_version = 2
517 bser_version = 2
431 bser_capabilities = struct.unpack_from("I", buf, 2)[0]
518 bser_capabilities = struct.unpack_from("I", buf, 2)[0]
432 expected_len, pos2 = Bunser.unser_int(buf, 6)
519 expected_len, pos2 = Bunser.unser_int(buf, 6)
433 else:
520 else:
434 raise ValueError('Invalid BSER header')
521 raise ValueError("Invalid BSER header")
435
522
436 return bser_version, bser_capabilities, expected_len, pos2
523 return bser_version, bser_capabilities, expected_len, pos2
437
524
@@ -470,14 +557,20 b' def loads(buf, mutable=True, value_encod'
470 pos = info[3]
557 pos = info[3]
471
558
472 if len(buf) != expected_len + pos:
559 if len(buf) != expected_len + pos:
473 raise ValueError('bser data len != header len')
560 raise ValueError(
561 "bser data len %d != header len %d" % (expected_len + pos, len(buf))
562 )
474
563
475 bunser = Bunser(mutable=mutable, value_encoding=value_encoding,
564 bunser = Bunser(
476 value_errors=value_errors)
565 mutable=mutable,
566 value_encoding=value_encoding,
567 value_errors=value_errors,
568 )
477
569
478 return bunser.loads_recursive(buf, pos)[0]
570 return bunser.loads_recursive(buf, pos)[0]
479
571
480
572
481 def load(fp, mutable=True, value_encoding=None, value_errors=None):
573 def load(fp, mutable=True, value_encoding=None, value_errors=None):
482 from . import load
574 from . import load
575
483 return load.load(fp, mutable, value_encoding, value_errors)
576 return load.load(fp, mutable, value_encoding, value_errors)
@@ -14,6 +14,7 b' import struct'
14
14
15 from mercurial.i18n import _
15 from mercurial.i18n import _
16 from mercurial import (
16 from mercurial import (
17 encoding,
17 pathutil,
18 pathutil,
18 util,
19 util,
19 )
20 )
@@ -81,7 +82,7 b' class state(object):'
81 self.invalidate()
82 self.invalidate()
82 return None, None, None
83 return None, None, None
83 diskhostname = state[0]
84 diskhostname = state[0]
84 hostname = socket.gethostname()
85 hostname = encoding.strtolocal(socket.gethostname())
85 if diskhostname != hostname:
86 if diskhostname != hostname:
86 # file got moved to a different host
87 # file got moved to a different host
87 self._ui.log(
88 self._ui.log(
@@ -127,7 +128,7 b' class state(object):'
127
128
128 with file:
129 with file:
129 file.write(struct.pack(_versionformat, _version))
130 file.write(struct.pack(_versionformat, _version))
130 file.write(socket.gethostname() + b'\0')
131 file.write(encoding.strtolocal(socket.gethostname()) + b'\0')
131 file.write(clock + b'\0')
132 file.write(clock + b'\0')
132 file.write(ignorehash + b'\0')
133 file.write(ignorehash + b'\0')
133 if notefiles:
134 if notefiles:
@@ -9,7 +9,14 b' from __future__ import absolute_import'
9
9
10 import getpass
10 import getpass
11
11
12 from mercurial import util
12 from mercurial import (
13 encoding,
14 util,
15 )
16 from mercurial.utils import (
17 procutil,
18 stringutil,
19 )
13
20
14 from . import pywatchman
21 from . import pywatchman
15
22
@@ -22,12 +29,14 b' class Unavailable(Exception):'
22 self.warn = False
29 self.warn = False
23 self.invalidate = invalidate
30 self.invalidate = invalidate
24
31
25 def __str__(self):
32 def __bytes__(self):
26 if self.warn:
33 if self.warn:
27 return b'warning: Watchman unavailable: %s' % self.msg
34 return b'warning: Watchman unavailable: %s' % self.msg
28 else:
35 else:
29 return b'Watchman unavailable: %s' % self.msg
36 return b'Watchman unavailable: %s' % self.msg
30
37
38 __str__ = encoding.strmethod(__bytes__)
39
31
40
32 class WatchmanNoRoot(Unavailable):
41 class WatchmanNoRoot(Unavailable):
33 def __init__(self, root, msg):
42 def __init__(self, root, msg):
@@ -92,15 +101,17 b' class client(object):'
92 self._watchmanclient = pywatchman.client(
101 self._watchmanclient = pywatchman.client(
93 timeout=self._timeout,
102 timeout=self._timeout,
94 useImmutableBser=True,
103 useImmutableBser=True,
95 watchman_exe=watchman_exe,
104 binpath=procutil.tonativestr(watchman_exe),
96 )
105 )
97 return self._watchmanclient.query(*watchmanargs)
106 return self._watchmanclient.query(*watchmanargs)
98 except pywatchman.CommandError as ex:
107 except pywatchman.CommandError as ex:
99 if b'unable to resolve root' in ex.msg:
108 if b'unable to resolve root' in ex.msg:
100 raise WatchmanNoRoot(self._root, ex.msg)
109 raise WatchmanNoRoot(
110 self._root, stringutil.forcebytestr(ex.msg)
111 )
101 raise Unavailable(ex.msg)
112 raise Unavailable(ex.msg)
102 except pywatchman.WatchmanError as ex:
113 except pywatchman.WatchmanError as ex:
103 raise Unavailable(str(ex))
114 raise Unavailable(stringutil.forcebytestr(ex))
104
115
105 def command(self, *args):
116 def command(self, *args):
106 try:
117 try:
@@ -76,10 +76,9 b' class gpg(object):'
76 fp = os.fdopen(fd, r'wb')
76 fp = os.fdopen(fd, r'wb')
77 fp.write(data)
77 fp.write(data)
78 fp.close()
78 fp.close()
79 gpgcmd = b"%s --logger-fd 1 --status-fd 1 --verify \"%s\" \"%s\"" % (
79 gpgcmd = (
80 self.path,
80 b"%s --logger-fd 1 --status-fd 1 --verify \"%s\" \"%s\""
81 sigfile,
81 % (self.path, sigfile, datafile,)
82 datafile,
83 )
82 )
84 ret = procutil.filter(b"", gpgcmd)
83 ret = procutil.filter(b"", gpgcmd)
85 finally:
84 finally:
@@ -217,6 +217,7 b' from mercurial import ('
217 copies,
217 copies,
218 destutil,
218 destutil,
219 discovery,
219 discovery,
220 encoding,
220 error,
221 error,
221 exchange,
222 exchange,
222 extensions,
223 extensions,
@@ -1117,7 +1118,7 b' class histeditrule(object):'
1117 self.pos = pos
1118 self.pos = pos
1118 self.conflicts = []
1119 self.conflicts = []
1119
1120
1120 def __str__(self):
1121 def __bytes__(self):
1121 # Some actions ('fold' and 'roll') combine a patch with a previous one.
1122 # Some actions ('fold' and 'roll') combine a patch with a previous one.
1122 # Add a marker showing which patch they apply to, and also omit the
1123 # Add a marker showing which patch they apply to, and also omit the
1123 # description for 'roll' (since it will get discarded). Example display:
1124 # description for 'roll' (since it will get discarded). Example display:
@@ -1135,10 +1136,16 b' class histeditrule(object):'
1135 desc = self.ctx.description().splitlines()[0].strip()
1136 desc = self.ctx.description().splitlines()[0].strip()
1136 if self.action == b'roll':
1137 if self.action == b'roll':
1137 desc = b''
1138 desc = b''
1138 return b"#{0:<2} {1:<6} {2}:{3} {4}".format(
1139 return b"#%s %s %d:%s %s" % (
1139 self.origpos, action, r, h, desc
1140 (b'%d' % self.origpos).ljust(2),
1141 action.ljust(6),
1142 r,
1143 h,
1144 desc,
1140 )
1145 )
1141
1146
1147 __str__ = encoding.strmethod(__bytes__)
1148
1142 def checkconflicts(self, other):
1149 def checkconflicts(self, other):
1143 if other.pos > self.pos and other.origpos <= self.origpos:
1150 if other.pos > self.pos and other.origpos <= self.origpos:
1144 if set(other.ctx.files()) & set(self.ctx.files()) != set():
1151 if set(other.ctx.files()) & set(self.ctx.files()) != set():
@@ -1315,7 +1322,7 b' def makecommands(rules):'
1315 our list of rules"""
1322 our list of rules"""
1316 commands = []
1323 commands = []
1317 for rules in rules:
1324 for rules in rules:
1318 commands.append(b"{0} {1}\n".format(rules.action, rules.ctx))
1325 commands.append(b'%s %s\n' % (rules.action, rules.ctx))
1319 return commands
1326 return commands
1320
1327
1321
1328
@@ -1324,7 +1331,7 b' def addln(win, y, x, line, color=None):'
1324 whitespace characters, so that the color appears on the whole line"""
1331 whitespace characters, so that the color appears on the whole line"""
1325 maxy, maxx = win.getmaxyx()
1332 maxy, maxx = win.getmaxyx()
1326 length = maxx - 1 - x
1333 length = maxx - 1 - x
1327 line = (b"{0:<%d}" % length).format(str(line).strip())[:length]
1334 line = bytes(line).ljust(length)[:length]
1328 if y < 0:
1335 if y < 0:
1329 y = maxy + y
1336 y = maxy + y
1330 if x < 0:
1337 if x < 0:
@@ -1395,17 +1402,17 b' def _chisteditmain(repo, rules, stdscr):'
1395 maxy, maxx = win.getmaxyx()
1402 maxy, maxx = win.getmaxyx()
1396 length = maxx - 3
1403 length = maxx - 3
1397
1404
1398 line = b"changeset: {0}:{1:<12}".format(ctx.rev(), ctx)
1405 line = b"changeset: %d:%s" % (ctx.rev(), ctx.hex()[:12])
1399 win.addstr(1, 1, line[:length])
1406 win.addstr(1, 1, line[:length])
1400
1407
1401 line = b"user: {0}".format(ctx.user())
1408 line = b"user: %s" % ctx.user()
1402 win.addstr(2, 1, line[:length])
1409 win.addstr(2, 1, line[:length])
1403
1410
1404 bms = repo.nodebookmarks(ctx.node())
1411 bms = repo.nodebookmarks(ctx.node())
1405 line = b"bookmark: {0}".format(b' '.join(bms))
1412 line = b"bookmark: %s" % b' '.join(bms)
1406 win.addstr(3, 1, line[:length])
1413 win.addstr(3, 1, line[:length])
1407
1414
1408 line = b"summary: {0}".format(ctx.description().splitlines()[0])
1415 line = b"summary: %s" % (ctx.description().splitlines()[0])
1409 win.addstr(4, 1, line[:length])
1416 win.addstr(4, 1, line[:length])
1410
1417
1411 line = b"files: "
1418 line = b"files: "
@@ -1425,8 +1432,8 b' def _chisteditmain(repo, rules, stdscr):'
1425
1432
1426 conflicts = rule.conflicts
1433 conflicts = rule.conflicts
1427 if len(conflicts) > 0:
1434 if len(conflicts) > 0:
1428 conflictstr = b','.join(map(lambda r: str(r.ctx), conflicts))
1435 conflictstr = b','.join(map(lambda r: r.ctx.hex()[:12], conflicts))
1429 conflictstr = b"changed files overlap with {0}".format(conflictstr)
1436 conflictstr = b"changed files overlap with %s" % conflictstr
1430 else:
1437 else:
1431 conflictstr = b'no overlap'
1438 conflictstr = b'no overlap'
1432
1439
@@ -1464,7 +1471,9 b' pgup/K: move patch up, pgdn/J: move patc'
1464
1471
1465 conflicts = [r.ctx for r in rules if r.conflicts]
1472 conflicts = [r.ctx for r in rules if r.conflicts]
1466 if len(conflicts) > 0:
1473 if len(conflicts) > 0:
1467 line = b"potential conflict in %s" % b','.join(map(str, conflicts))
1474 line = b"potential conflict in %s" % b','.join(
1475 map(pycompat.bytestr, conflicts)
1476 )
1468 addln(rulesscr, -1, 0, line, curses.color_pair(COLOR_WARN))
1477 addln(rulesscr, -1, 0, line, curses.color_pair(COLOR_WARN))
1469
1478
1470 for y, rule in enumerate(rules[start:]):
1479 for y, rule in enumerate(rules[start:]):
@@ -1601,7 +1610,7 b' pgup/K: move patch up, pgdn/J: move patc'
1601 renderhelp(helpwin, state)
1610 renderhelp(helpwin, state)
1602 curses.doupdate()
1611 curses.doupdate()
1603 # done rendering
1612 # done rendering
1604 ch = stdscr.getkey()
1613 ch = encoding.strtolocal(stdscr.getkey())
1605 except curses.error:
1614 except curses.error:
1606 pass
1615 pass
1607
1616
@@ -1675,11 +1684,10 b' def _chistedit(ui, repo, *freeargs, **op'
1675 if type(rc) is list:
1684 if type(rc) is list:
1676 ui.status(_(b"performing changes\n"))
1685 ui.status(_(b"performing changes\n"))
1677 rules = makecommands(rc)
1686 rules = makecommands(rc)
1678 filename = repo.vfs.join(b'chistedit')
1687 with repo.vfs(b'chistedit', b'w+') as fp:
1679 with open(filename, b'w+') as fp:
1680 for r in rules:
1688 for r in rules:
1681 fp.write(r)
1689 fp.write(r)
1682 opts[b'commands'] = filename
1690 opts['commands'] = fp.name
1683 return _texthistedit(ui, repo, *freeargs, **opts)
1691 return _texthistedit(ui, repo, *freeargs, **opts)
1684 except KeyboardInterrupt:
1692 except KeyboardInterrupt:
1685 pass
1693 pass
@@ -959,7 +959,7 b' def logservicecall(logger, service, **kw'
959 service,
959 service,
960 eventtype=b'failure',
960 eventtype=b'failure',
961 elapsedms=(time.time() - start) * 1000,
961 elapsedms=(time.time() - start) * 1000,
962 errormsg=str(e),
962 errormsg=stringutil.forcebytestr(e),
963 **kwargs
963 **kwargs
964 )
964 )
965 raise
965 raise
@@ -1223,7 +1223,7 b' def storebundle(op, params, bundlefile):'
1223 scratchbranchparttype,
1223 scratchbranchparttype,
1224 eventtype=b'failure',
1224 eventtype=b'failure',
1225 elapsedms=(time.time() - parthandlerstart) * 1000,
1225 elapsedms=(time.time() - parthandlerstart) * 1000,
1226 errormsg=str(e),
1226 errormsg=stringutil.forcebytestr(e),
1227 )
1227 )
1228 raise
1228 raise
1229 finally:
1229 finally:
@@ -363,7 +363,7 b' class _gitlfsremote(object):'
363 _(b'LFS error: %s') % _urlerrorreason(ex), hint=hint
363 _(b'LFS error: %s') % _urlerrorreason(ex), hint=hint
364 )
364 )
365 try:
365 try:
366 response = json.loads(rawjson)
366 response = pycompat.json_loads(rawjson)
367 except ValueError:
367 except ValueError:
368 raise LfsRemoteError(
368 raise LfsRemoteError(
369 _(b'LFS server returns invalid JSON: %s')
369 _(b'LFS server returns invalid JSON: %s')
@@ -133,7 +133,7 b' def _processbatchrequest(repo, req, res)'
133 return True
133 return True
134
134
135 # XXX: specify an encoding?
135 # XXX: specify an encoding?
136 lfsreq = json.loads(req.bodyfh.read())
136 lfsreq = pycompat.json_loads(req.bodyfh.read())
137
137
138 # If no transfer handlers are explicitly requested, 'basic' is assumed.
138 # If no transfer handlers are explicitly requested, 'basic' is assumed.
139 if r'basic' not in lfsreq.get(r'transfers', [r'basic']):
139 if r'basic' not in lfsreq.get(r'transfers', [r'basic']):
@@ -148,7 +148,7 b' web.baseurl'
148 from __future__ import absolute_import
148 from __future__ import absolute_import
149
149
150 import email.errors as emailerrors
150 import email.errors as emailerrors
151 import email.parser as emailparser
151 import email.utils as emailutils
152 import fnmatch
152 import fnmatch
153 import hashlib
153 import hashlib
154 import socket
154 import socket
@@ -382,9 +382,8 b' class notifier(object):'
382 )
382 )
383 return
383 return
384
384
385 p = emailparser.Parser()
386 try:
385 try:
387 msg = p.parsestr(encoding.strfromlocal(data))
386 msg = mail.parsebytes(data)
388 except emailerrors.MessageParseError as inst:
387 except emailerrors.MessageParseError as inst:
389 raise error.Abort(inst)
388 raise error.Abort(inst)
390
389
@@ -392,16 +391,16 b' class notifier(object):'
392 sender = msg[r'From']
391 sender = msg[r'From']
393 subject = msg[r'Subject']
392 subject = msg[r'Subject']
394 if sender is not None:
393 if sender is not None:
395 sender = encoding.strtolocal(sender)
394 sender = mail.headdecode(sender)
396 if subject is not None:
395 if subject is not None:
397 subject = encoding.strtolocal(subject)
396 subject = mail.headdecode(subject)
398 del msg[r'From'], msg[r'Subject']
397 del msg[r'From'], msg[r'Subject']
399
398
400 if not msg.is_multipart():
399 if not msg.is_multipart():
401 # create fresh mime message from scratch
400 # create fresh mime message from scratch
402 # (multipart templates must take care of this themselves)
401 # (multipart templates must take care of this themselves)
403 headers = msg.items()
402 headers = msg.items()
404 payload = msg.get_payload()
403 payload = msg.get_payload(decode=pycompat.ispy3)
405 # for notification prefer readability over data precision
404 # for notification prefer readability over data precision
406 msg = mail.mimeencode(self.ui, payload, self.charsets, self.test)
405 msg = mail.mimeencode(self.ui, payload, self.charsets, self.test)
407 # reinstate custom headers
406 # reinstate custom headers
@@ -440,7 +439,7 b' class notifier(object):'
440 msg[r'Message-Id'] = messageid(ctx, self.domain, self.messageidseed)
439 msg[r'Message-Id'] = messageid(ctx, self.domain, self.messageidseed)
441 msg[r'To'] = encoding.strfromlocal(b', '.join(sorted(subs)))
440 msg[r'To'] = encoding.strfromlocal(b', '.join(sorted(subs)))
442
441
443 msgtext = encoding.strtolocal(msg.as_string())
442 msgtext = msg.as_bytes() if pycompat.ispy3 else msg.as_string()
444 if self.test:
443 if self.test:
445 self.ui.write(msgtext)
444 self.ui.write(msgtext)
446 if not msgtext.endswith(b'\n'):
445 if not msgtext.endswith(b'\n'):
@@ -452,7 +451,7 b' class notifier(object):'
452 )
451 )
453 mail.sendmail(
452 mail.sendmail(
454 self.ui,
453 self.ui,
455 stringutil.email(msg[r'From']),
454 emailutils.parseaddr(msg[r'From'])[1],
456 subs,
455 subs,
457 msgtext,
456 msgtext,
458 mbox=self.mbox,
457 mbox=self.mbox,
@@ -960,7 +960,10 b' def email(ui, repo, *revs, **opts):'
960 hdr = pycompat.strurl(hdr)
960 hdr = pycompat.strurl(hdr)
961 change = True
961 change = True
962 if isinstance(val, bytes):
962 if isinstance(val, bytes):
963 val = pycompat.strurl(val)
963 # header value should be ASCII since it's encoded by
964 # mail.headencode(), but -n/--test disables it and raw
965 # value of platform encoding is stored.
966 val = encoding.strfromlocal(val)
964 if not change:
967 if not change:
965 # prevent duplicate headers
968 # prevent duplicate headers
966 del m[hdr]
969 del m[hdr]
@@ -152,8 +152,8 b' def vcrcommand(name, flags, spec, helpca'
152 value = r1params[key][0]
152 value = r1params[key][0]
153 # we want to compare json payloads without worrying about ordering
153 # we want to compare json payloads without worrying about ordering
154 if value.startswith(b'{') and value.endswith(b'}'):
154 if value.startswith(b'{') and value.endswith(b'}'):
155 r1json = json.loads(value)
155 r1json = pycompat.json_loads(value)
156 r2json = json.loads(r2params[key][0])
156 r2json = pycompat.json_loads(r2params[key][0])
157 if r1json != r2json:
157 if r1json != r2json:
158 return False
158 return False
159 elif r2params[key][0] != value:
159 elif r2params[key][0] != value:
@@ -307,7 +307,7 b' def callconduit(ui, name, params):'
307 if isinstance(x, pycompat.unicode)
307 if isinstance(x, pycompat.unicode)
308 else x,
308 else x,
309 # json.loads only accepts bytes from py3.6+
309 # json.loads only accepts bytes from py3.6+
310 json.loads(encoding.unifromlocal(body)),
310 pycompat.json_loads(encoding.unifromlocal(body)),
311 )
311 )
312 if parsed.get(b'error_code'):
312 if parsed.get(b'error_code'):
313 msg = _(b'Conduit Error (%s): %s') % (
313 msg = _(b'Conduit Error (%s): %s') % (
@@ -332,7 +332,7 b' def debugcallconduit(ui, repo, name):'
332 lambda x: encoding.unitolocal(x)
332 lambda x: encoding.unitolocal(x)
333 if isinstance(x, pycompat.unicode)
333 if isinstance(x, pycompat.unicode)
334 else x,
334 else x,
335 json.loads(rawparams),
335 pycompat.json_loads(rawparams),
336 )
336 )
337 # json.dumps only accepts unicode strings
337 # json.dumps only accepts unicode strings
338 result = pycompat.rapply(
338 result = pycompat.rapply(
@@ -441,7 +441,7 b' def getoldnodedrevmap(repo, nodelist):'
441 )
441 )
442 unfi.ui.warn(
442 unfi.ui.warn(
443 _(
443 _(
444 b'D%s: local tag removed - does not match '
444 b'D%d: local tag removed - does not match '
445 b'Differential history\n'
445 b'Differential history\n'
446 )
446 )
447 % drev
447 % drev
@@ -1168,7 +1168,7 b' def phabsend(ui, repo, *revs, **opts):'
1168 writediffproperties(unfi[newnode], diffmap[old.node()])
1168 writediffproperties(unfi[newnode], diffmap[old.node()])
1169 except util.urlerr.urlerror:
1169 except util.urlerr.urlerror:
1170 ui.warnnoi18n(
1170 ui.warnnoi18n(
1171 b'Failed to update metadata for D%s\n' % drevid
1171 b'Failed to update metadata for D%d\n' % drevid
1172 )
1172 )
1173 # Remove local tags since it's no longer necessary
1173 # Remove local tags since it's no longer necessary
1174 tagname = b'D%d' % drevid
1174 tagname = b'D%d' % drevid
@@ -1208,7 +1208,7 b' def _confirmbeforesend(repo, revs, oldma'
1208 desc = ctx.description().splitlines()[0]
1208 desc = ctx.description().splitlines()[0]
1209 oldnode, olddiff, drevid = oldmap.get(ctx.node(), (None, None, None))
1209 oldnode, olddiff, drevid = oldmap.get(ctx.node(), (None, None, None))
1210 if drevid:
1210 if drevid:
1211 drevdesc = ui.label(b'D%s' % drevid, b'phabricator.drev')
1211 drevdesc = ui.label(b'D%d' % drevid, b'phabricator.drev')
1212 else:
1212 else:
1213 drevdesc = ui.label(_(b'NEW'), b'phabricator.drev')
1213 drevdesc = ui.label(_(b'NEW'), b'phabricator.drev')
1214
1214
@@ -1613,7 +1613,7 b' def phabupdate(ui, repo, spec, **opts):'
1613
1613
1614 actions = []
1614 actions = []
1615 for f in flags:
1615 for f in flags:
1616 actions.append({b'type': f, b'value': b'true'})
1616 actions.append({b'type': f, b'value': True})
1617
1617
1618 drevs = querydrev(repo, spec)
1618 drevs = querydrev(repo, spec)
1619 for i, drev in enumerate(drevs):
1619 for i, drev in enumerate(drevs):
@@ -2267,7 +2267,13 b' def config(ui, repo, *values, **opts):'
2267 fm.write(b'value', b'%s\n', value)
2267 fm.write(b'value', b'%s\n', value)
2268 else:
2268 else:
2269 fm.write(b'name value', b'%s=%s\n', entryname, value)
2269 fm.write(b'name value', b'%s=%s\n', entryname, value)
2270 fm.data(defaultvalue=defaultvalue)
2270 if formatter.isprintable(defaultvalue):
2271 fm.data(defaultvalue=defaultvalue)
2272 elif isinstance(defaultvalue, list) and all(
2273 formatter.isprintable(e) for e in defaultvalue
2274 ):
2275 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2276 # TODO: no idea how to process unsupported defaultvalue types
2271 matched = True
2277 matched = True
2272 fm.end()
2278 fm.end()
2273 if matched:
2279 if matched:
@@ -212,11 +212,9 b' class config(object):'
212 def read(self, path, fp=None, sections=None, remap=None):
212 def read(self, path, fp=None, sections=None, remap=None):
213 if not fp:
213 if not fp:
214 fp = util.posixfile(path, b'rb')
214 fp = util.posixfile(path, b'rb')
215 assert (
215 assert getattr(fp, 'mode', r'rb') == r'rb', (
216 getattr(fp, 'mode', r'rb') == r'rb'
216 b'config files must be opened in binary mode, got fp=%r mode=%r'
217 ), b'config files must be opened in binary mode, got fp=%r mode=%r' % (
217 % (fp, fp.mode,)
218 fp,
219 fp.mode,
220 )
218 )
221 self.parse(
219 self.parse(
222 path, fp.read(), sections=sections, remap=remap, include=self.read
220 path, fp.read(), sections=sections, remap=remap, include=self.read
@@ -1187,10 +1187,9 b' class filectx(basefilectx):'
1187
1187
1188 assert (
1188 assert (
1189 changeid is not None or fileid is not None or changectx is not None
1189 changeid is not None or fileid is not None or changectx is not None
1190 ), b"bad args: changeid=%r, fileid=%r, changectx=%r" % (
1190 ), (
1191 changeid,
1191 b"bad args: changeid=%r, fileid=%r, changectx=%r"
1192 fileid,
1192 % (changeid, fileid, changectx,)
1193 changectx,
1194 )
1193 )
1195
1194
1196 if filelog is not None:
1195 if filelog is not None:
@@ -1816,7 +1816,7 b' are you sure you want to review/edit and'
1816 try:
1816 try:
1817 patch = self.ui.edit(patch.getvalue(), b"", action=b"diff")
1817 patch = self.ui.edit(patch.getvalue(), b"", action=b"diff")
1818 except error.Abort as exc:
1818 except error.Abort as exc:
1819 self.errorstr = str(exc)
1819 self.errorstr = stringutil.forcebytestr(exc)
1820 return None
1820 return None
1821 finally:
1821 finally:
1822 self.stdscr.clear()
1822 self.stdscr.clear()
@@ -111,6 +111,14 b' class Abort(Hint, Exception):'
111
111
112 __bytes__ = _tobytes
112 __bytes__ = _tobytes
113
113
114 if pycompat.ispy3:
115
116 def __str__(self):
117 # the output would be unreadable if the message was translated,
118 # but do not replace it with encoding.strfromlocal(), which
119 # may raise another exception.
120 return pycompat.sysstr(self.__bytes__())
121
114
122
115 class HookLoadError(Abort):
123 class HookLoadError(Abort):
116 """raised when loading a hook fails, aborting an operation
124 """raised when loading a hook fails, aborting an operation
@@ -136,6 +136,16 b' from .utils import ('
136 pickle = util.pickle
136 pickle = util.pickle
137
137
138
138
139 def isprintable(obj):
140 """Check if the given object can be directly passed in to formatter's
141 write() and data() functions
142
143 Returns False if the object is unsupported or must be pre-processed by
144 formatdate(), formatdict(), or formatlist().
145 """
146 return isinstance(obj, (type(None), bool, int, pycompat.long, float, bytes))
147
148
139 class _nullconverter(object):
149 class _nullconverter(object):
140 '''convert non-primitive data types to be processed by formatter'''
150 '''convert non-primitive data types to be processed by formatter'''
141
151
@@ -505,6 +515,10 b' class templateformatter(baseformatter):'
505 if part not in self._parts:
515 if part not in self._parts:
506 return
516 return
507 ref = self._parts[part]
517 ref = self._parts[part]
518 # None can't be put in the mapping dict since it means <unset>
519 for k, v in item.items():
520 if v is None:
521 item[k] = templateutil.wrappedvalue(v)
508 self._out.write(self._t.render(ref, item))
522 self._out.write(self._t.render(ref, item))
509
523
510 @util.propertycache
524 @util.propertycache
@@ -1417,7 +1417,7 b' class localrepository(object):'
1417
1417
1418 def _refreshchangelog(self):
1418 def _refreshchangelog(self):
1419 """make sure the in memory changelog match the on-disk one"""
1419 """make sure the in memory changelog match the on-disk one"""
1420 if b'changelog' in vars(self) and self.currenttransaction() is None:
1420 if 'changelog' in vars(self) and self.currenttransaction() is None:
1421 del self.changelog
1421 del self.changelog
1422
1422
1423 @property
1423 @property
@@ -342,6 +342,7 b' def _encode(ui, s, charsets):'
342 s.decode('ascii')
342 s.decode('ascii')
343 except UnicodeDecodeError:
343 except UnicodeDecodeError:
344 for ics in (encoding.encoding, encoding.fallbackencoding):
344 for ics in (encoding.encoding, encoding.fallbackencoding):
345 ics = pycompat.sysstr(ics)
345 try:
346 try:
346 u = s.decode(ics)
347 u = s.decode(ics)
347 except UnicodeDecodeError:
348 except UnicodeDecodeError:
@@ -362,13 +363,13 b' def headencode(ui, s, charsets=None, dis'
362 if not display:
363 if not display:
363 # split into words?
364 # split into words?
364 s, cs = _encode(ui, s, charsets)
365 s, cs = _encode(ui, s, charsets)
365 return str(email.header.Header(s, cs))
366 return encoding.strtolocal(email.header.Header(s, cs).encode())
366 return s
367 return s
367
368
368
369
369 def _addressencode(ui, name, addr, charsets=None):
370 def _addressencode(ui, name, addr, charsets=None):
370 assert isinstance(addr, bytes)
371 assert isinstance(addr, bytes)
371 name = headencode(ui, name, charsets)
372 name = encoding.strfromlocal(headencode(ui, name, charsets))
372 try:
373 try:
373 acc, dom = addr.split(b'@')
374 acc, dom = addr.split(b'@')
374 acc.decode('ascii')
375 acc.decode('ascii')
@@ -440,6 +441,10 b' if pycompat.ispy3:'
440 finally:
441 finally:
441 fp.detach()
442 fp.detach()
442
443
444 def parsebytes(data):
445 ep = email.parser.BytesParser()
446 return ep.parsebytes(data)
447
443
448
444 else:
449 else:
445
450
@@ -449,6 +454,10 b' else:'
449 ep = email.parser.Parser()
454 ep = email.parser.Parser()
450 return ep.parse(fp)
455 return ep.parse(fp)
451
456
457 def parsebytes(data):
458 ep = email.parser.Parser()
459 return ep.parsestr(data)
460
452
461
453 def headdecode(s):
462 def headdecode(s):
454 '''Decodes RFC-2047 header'''
463 '''Decodes RFC-2047 header'''
@@ -458,7 +467,7 b' def headdecode(s):'
458 try:
467 try:
459 uparts.append(part.decode(charset))
468 uparts.append(part.decode(charset))
460 continue
469 continue
461 except UnicodeDecodeError:
470 except (UnicodeDecodeError, LookupError):
462 pass
471 pass
463 # On Python 3, decode_header() may return either bytes or unicode
472 # On Python 3, decode_header() may return either bytes or unicode
464 # depending on whether the header has =?<charset>? or not
473 # depending on whether the header has =?<charset>? or not
@@ -867,12 +867,15 b' class treemanifest(object):'
867 return not self._dirs or all(m._isempty() for m in self._dirs.values())
867 return not self._dirs or all(m._isempty() for m in self._dirs.values())
868
868
869 def __repr__(self):
869 def __repr__(self):
870 return b'<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>' % (
870 return (
871 self._dir,
871 b'<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>'
872 hex(self._node),
872 % (
873 bool(self._loadfunc is _noop),
873 self._dir,
874 self._dirty,
874 hex(self._node),
875 id(self),
875 bool(self._loadfunc is _noop),
876 self._dirty,
877 id(self),
878 )
876 )
879 )
877
880
878 def dir(self):
881 def dir(self):
@@ -12,6 +12,7 b' from __future__ import absolute_import'
12
12
13 import getopt
13 import getopt
14 import inspect
14 import inspect
15 import json
15 import os
16 import os
16 import shlex
17 import shlex
17 import sys
18 import sys
@@ -88,6 +89,7 b' def rapply(f, xs):'
88
89
89 if ispy3:
90 if ispy3:
90 import builtins
91 import builtins
92 import codecs
91 import functools
93 import functools
92 import io
94 import io
93 import struct
95 import struct
@@ -347,6 +349,48 b' if ispy3:'
347 iteritems = lambda x: x.items()
349 iteritems = lambda x: x.items()
348 itervalues = lambda x: x.values()
350 itervalues = lambda x: x.values()
349
351
352 # Python 3.5's json.load and json.loads require str. We polyfill its
353 # code for detecting encoding from bytes.
354 if sys.version_info[0:2] < (3, 6):
355
356 def _detect_encoding(b):
357 bstartswith = b.startswith
358 if bstartswith((codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE)):
359 return 'utf-32'
360 if bstartswith((codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE)):
361 return 'utf-16'
362 if bstartswith(codecs.BOM_UTF8):
363 return 'utf-8-sig'
364
365 if len(b) >= 4:
366 if not b[0]:
367 # 00 00 -- -- - utf-32-be
368 # 00 XX -- -- - utf-16-be
369 return 'utf-16-be' if b[1] else 'utf-32-be'
370 if not b[1]:
371 # XX 00 00 00 - utf-32-le
372 # XX 00 00 XX - utf-16-le
373 # XX 00 XX -- - utf-16-le
374 return 'utf-16-le' if b[2] or b[3] else 'utf-32-le'
375 elif len(b) == 2:
376 if not b[0]:
377 # 00 XX - utf-16-be
378 return 'utf-16-be'
379 if not b[1]:
380 # XX 00 - utf-16-le
381 return 'utf-16-le'
382 # default
383 return 'utf-8'
384
385 def json_loads(s, *args, **kwargs):
386 if isinstance(s, (bytes, bytearray)):
387 s = s.decode(_detect_encoding(s), 'surrogatepass')
388
389 return json.loads(s, *args, **kwargs)
390
391 else:
392 json_loads = json.loads
393
350 else:
394 else:
351 import cStringIO
395 import cStringIO
352
396
@@ -424,6 +468,7 b' else:'
424 getargspec = inspect.getargspec
468 getargspec = inspect.getargspec
425 iteritems = lambda x: x.iteritems()
469 iteritems = lambda x: x.iteritems()
426 itervalues = lambda x: x.itervalues()
470 itervalues = lambda x: x.itervalues()
471 json_loads = json.loads
427
472
428 isjython = sysplatform.startswith(b'java')
473 isjython = sysplatform.startswith(b'java')
429
474
@@ -1854,7 +1854,7 b' class simplekeyvaluefile(object):'
1854 raise error.CorruptedState(e % self.firstlinekey)
1854 raise error.CorruptedState(e % self.firstlinekey)
1855 d.update(updatedict)
1855 d.update(updatedict)
1856 except ValueError as e:
1856 except ValueError as e:
1857 raise error.CorruptedState(str(e))
1857 raise error.CorruptedState(stringutil.forcebytestr(e))
1858 return d
1858 return d
1859
1859
1860 def write(self, data, firstline=None):
1860 def write(self, data, firstline=None):
@@ -31,9 +31,6 b' from .utils import ('
31 urlerr = util.urlerr
31 urlerr = util.urlerr
32 urlreq = util.urlreq
32 urlreq = util.urlreq
33
33
34 if pycompat.ispy3:
35 long = int
36
37 # filters are callables like:
34 # filters are callables like:
38 # fn(obj)
35 # fn(obj)
39 # with:
36 # with:
@@ -329,7 +326,7 b' def json(obj, paranoid=True):'
329 return b'false'
326 return b'false'
330 elif obj is True:
327 elif obj is True:
331 return b'true'
328 return b'true'
332 elif isinstance(obj, (int, long, float)):
329 elif isinstance(obj, (int, pycompat.long, float)):
333 return pycompat.bytestr(obj)
330 return pycompat.bytestr(obj)
334 elif isinstance(obj, bytes):
331 elif isinstance(obj, bytes):
335 return b'"%s"' % encoding.jsonescape(obj, paranoid=paranoid)
332 return b'"%s"' % encoding.jsonescape(obj, paranoid=paranoid)
@@ -1564,6 +1564,7 b' class ui(object):'
1564 # - http://bugs.python.org/issue12833
1564 # - http://bugs.python.org/issue12833
1565 with self.timeblockedsection(b'stdio'):
1565 with self.timeblockedsection(b'stdio'):
1566 if usereadline:
1566 if usereadline:
1567 self.flush()
1567 prompt = encoding.strfromlocal(prompt)
1568 prompt = encoding.strfromlocal(prompt)
1568 line = encoding.strtolocal(pycompat.rawinput(prompt))
1569 line = encoding.strtolocal(pycompat.rawinput(prompt))
1569 # When stdin is in binary mode on Windows, it can cause
1570 # When stdin is in binary mode on Windows, it can cause
@@ -6,32 +6,27 b''
6
6
7 import os
7 import os
8
8
9 supportedpy = '~= 2.7'
9 # Mercurial will never work on Python 3 before 3.5 due to a lack
10 if os.environ.get('HGALLOWPYTHON3', ''):
10 # of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1
11 # Mercurial will never work on Python 3 before 3.5 due to a lack
11 # due to a bug in % formatting in bytestrings.
12 # of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1
12 # We cannot support Python 3.5.0, 3.5.1, 3.5.2 because of bug in
13 # due to a bug in % formatting in bytestrings.
13 # codecs.escape_encode() where it raises SystemError on empty bytestring
14 # We cannot support Python 3.5.0, 3.5.1, 3.5.2 because of bug in
14 # bug link: https://bugs.python.org/issue25270
15 # codecs.escape_encode() where it raises SystemError on empty bytestring
15 supportedpy = ','.join(
16 # bug link: https://bugs.python.org/issue25270
16 [
17 #
17 '>=2.7',
18 # TODO: when we actually work on Python 3, use this string as the
18 '!=3.0.*',
19 # actual supportedpy string.
19 '!=3.1.*',
20 supportedpy = ','.join(
20 '!=3.2.*',
21 [
21 '!=3.3.*',
22 '>=2.7',
22 '!=3.4.*',
23 '!=3.0.*',
23 '!=3.5.0',
24 '!=3.1.*',
24 '!=3.5.1',
25 '!=3.2.*',
25 '!=3.5.2',
26 '!=3.3.*',
26 '!=3.6.0',
27 '!=3.4.*',
27 '!=3.6.1',
28 '!=3.5.0',
28 ]
29 '!=3.5.1',
29 )
30 '!=3.5.2',
31 '!=3.6.0',
32 '!=3.6.1',
33 ]
34 )
35
30
36 import sys, platform
31 import sys, platform
37 import sysconfig
32 import sysconfig
@@ -89,39 +84,6 b' Python {py} detected.'
89 printf(error, file=sys.stderr)
84 printf(error, file=sys.stderr)
90 sys.exit(1)
85 sys.exit(1)
91
86
92 # We don't yet officially support Python 3. But we want to allow developers to
93 # hack on. Detect and disallow running on Python 3 by default. But provide a
94 # backdoor to enable working on Python 3.
95 if sys.version_info[0] != 2:
96 badpython = True
97
98 # Allow Python 3 from source checkouts.
99 if os.path.isdir('.hg') or 'HGPYTHON3' in os.environ:
100 badpython = False
101
102 if badpython:
103 error = """
104 Python {py} detected.
105
106 Mercurial currently has beta support for Python 3 and use of Python 2.7 is
107 recommended for the best experience.
108
109 Please re-run with Python 2.7 for a faster, less buggy experience.
110
111 If you would like to beta test Mercurial with Python 3, this error can
112 be suppressed by defining the HGPYTHON3 environment variable when invoking
113 this command. No special environment variables or configuration changes are
114 necessary to run `hg` with Python 3.
115
116 See https://www.mercurial-scm.org/wiki/Python3 for more on Mercurial's
117 Python 3 support.
118 """.format(
119 py='.'.join('%d' % x for x in sys.version_info[0:2])
120 )
121
122 printf(error, file=sys.stderr)
123 sys.exit(1)
124
125 if sys.version_info[0] >= 3:
87 if sys.version_info[0] >= 3:
126 DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX']
88 DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX']
127 else:
89 else:
@@ -98,7 +98,7 b' def request(host, path, show):'
98 if formatjson:
98 if formatjson:
99 # json.dumps() will print trailing newlines. Eliminate them
99 # json.dumps() will print trailing newlines. Eliminate them
100 # to make tests easier to write.
100 # to make tests easier to write.
101 data = json.loads(data)
101 data = pycompat.json_loads(data)
102 lines = json.dumps(data, sort_keys=True, indent=2).splitlines()
102 lines = json.dumps(data, sort_keys=True, indent=2).splitlines()
103 for line in lines:
103 for line in lines:
104 bodyfh.write(pycompat.sysbytes(line.rstrip()))
104 bodyfh.write(pycompat.sysbytes(line.rstrip()))
@@ -1,5 +1,6 b''
1 from __future__ import absolute_import, print_function
1 from __future__ import absolute_import, print_function
2
2
3 import distutils.version
3 import os
4 import os
4 import re
5 import re
5 import socket
6 import socket
@@ -828,6 +829,17 b' def has_dev_full():'
828 return os.path.exists('/dev/full')
829 return os.path.exists('/dev/full')
829
830
830
831
832 @check("ensurepip", "ensurepip module")
833 def has_ensurepip():
834 try:
835 import ensurepip
836
837 ensurepip.bootstrap
838 return True
839 except ImportError:
840 return False
841
842
831 @check("virtualenv", "Python virtualenv support")
843 @check("virtualenv", "Python virtualenv support")
832 def has_virtualenv():
844 def has_virtualenv():
833 try:
845 try:
@@ -980,12 +992,10 b' def has_emacs():'
980 return matchoutput('emacs --version', b'GNU Emacs 2(4.4|4.5|5|6|7|8|9)')
992 return matchoutput('emacs --version', b'GNU Emacs 2(4.4|4.5|5|6|7|8|9)')
981
993
982
994
983 # @check('black', 'the black formatter for python')
995 @check('black', 'the black formatter for python')
984 @check('grey', 'grey, the fork of the black formatter for python')
985 def has_black():
996 def has_black():
986 # use that to actual black as soon as possible
997 blackcmd = 'black --version'
987 # blackcmd = 'black --version'
998 version_regex = b'black, version ([0-9a-b.]+)'
988 blackcmd = 'python3 $RUNTESTDIR/../contrib/grey.py --version'
999 version = matchoutput(blackcmd, version_regex)
989 # version_regex = b'black, version \d'
1000 sv = distutils.version.StrictVersion
990 version_regex = b'grey.py, version \d'
1001 return version and sv(_strpath(version.group(1))) >= sv('19.10b0')
991 return matchoutput(blackcmd, version_regex)
@@ -1504,7 +1504,7 b' class PythonTest(Test):'
1504 py3switch = self._py3warnings and b' -3' or b''
1504 py3switch = self._py3warnings and b' -3' or b''
1505 # Quote the python(3) executable for Windows
1505 # Quote the python(3) executable for Windows
1506 cmd = b'"%s"%s "%s"' % (PYTHON, py3switch, self.path)
1506 cmd = b'"%s"%s "%s"' % (PYTHON, py3switch, self.path)
1507 vlog("# Running", cmd)
1507 vlog("# Running", cmd.decode("utf-8"))
1508 normalizenewlines = os.name == 'nt'
1508 normalizenewlines = os.name == 'nt'
1509 result = self._runcommand(cmd, env, normalizenewlines=normalizenewlines)
1509 result = self._runcommand(cmd, env, normalizenewlines=normalizenewlines)
1510 if self._aborted:
1510 if self._aborted:
@@ -1589,7 +1589,7 b' class TTest(Test):'
1589 f.write(l)
1589 f.write(l)
1590
1590
1591 cmd = b'%s "%s"' % (self._shell, fname)
1591 cmd = b'%s "%s"' % (self._shell, fname)
1592 vlog("# Running", cmd)
1592 vlog("# Running", cmd.decode("utf-8"))
1593
1593
1594 exitcode, output = self._runcommand(cmd, env)
1594 exitcode, output = self._runcommand(cmd, env)
1595
1595
@@ -1770,7 +1770,9 b' class TTest(Test):'
1770 if l.startswith(b'#require'):
1770 if l.startswith(b'#require'):
1771 lsplit = l.split()
1771 lsplit = l.split()
1772 if len(lsplit) < 2 or lsplit[0] != b'#require':
1772 if len(lsplit) < 2 or lsplit[0] != b'#require':
1773 after.setdefault(pos, []).append(' !!! invalid #require\n')
1773 after.setdefault(pos, []).append(
1774 b' !!! invalid #require\n'
1775 )
1774 if not skipping:
1776 if not skipping:
1775 haveresult, message = self._hghave(lsplit[1:])
1777 haveresult, message = self._hghave(lsplit[1:])
1776 if not haveresult:
1778 if not haveresult:
@@ -1780,19 +1782,19 b' class TTest(Test):'
1780 elif l.startswith(b'#if'):
1782 elif l.startswith(b'#if'):
1781 lsplit = l.split()
1783 lsplit = l.split()
1782 if len(lsplit) < 2 or lsplit[0] != b'#if':
1784 if len(lsplit) < 2 or lsplit[0] != b'#if':
1783 after.setdefault(pos, []).append(' !!! invalid #if\n')
1785 after.setdefault(pos, []).append(b' !!! invalid #if\n')
1784 if skipping is not None:
1786 if skipping is not None:
1785 after.setdefault(pos, []).append(' !!! nested #if\n')
1787 after.setdefault(pos, []).append(b' !!! nested #if\n')
1786 skipping = not self._iftest(lsplit[1:])
1788 skipping = not self._iftest(lsplit[1:])
1787 after.setdefault(pos, []).append(l)
1789 after.setdefault(pos, []).append(l)
1788 elif l.startswith(b'#else'):
1790 elif l.startswith(b'#else'):
1789 if skipping is None:
1791 if skipping is None:
1790 after.setdefault(pos, []).append(' !!! missing #if\n')
1792 after.setdefault(pos, []).append(b' !!! missing #if\n')
1791 skipping = not skipping
1793 skipping = not skipping
1792 after.setdefault(pos, []).append(l)
1794 after.setdefault(pos, []).append(l)
1793 elif l.startswith(b'#endif'):
1795 elif l.startswith(b'#endif'):
1794 if skipping is None:
1796 if skipping is None:
1795 after.setdefault(pos, []).append(' !!! missing #if\n')
1797 after.setdefault(pos, []).append(b' !!! missing #if\n')
1796 skipping = None
1798 skipping = None
1797 after.setdefault(pos, []).append(l)
1799 after.setdefault(pos, []).append(l)
1798 elif skipping:
1800 elif skipping:
@@ -1841,7 +1843,7 b' class TTest(Test):'
1841 if inpython:
1843 if inpython:
1842 script.append(b'EOF\n')
1844 script.append(b'EOF\n')
1843 if skipping is not None:
1845 if skipping is not None:
1844 after.setdefault(pos, []).append(' !!! missing #endif\n')
1846 after.setdefault(pos, []).append(b' !!! missing #endif\n')
1845 addsalt(n + 1, False)
1847 addsalt(n + 1, False)
1846 # Need to end any current per-command trace
1848 # Need to end any current per-command trace
1847 if activetrace:
1849 if activetrace:
@@ -3111,12 +3113,14 b' class TestRunner(object):'
3111 'extensions.logexceptions=%s' % logexceptions.decode('utf-8')
3113 'extensions.logexceptions=%s' % logexceptions.decode('utf-8')
3112 )
3114 )
3113
3115
3114 vlog("# Using TESTDIR", self._testdir)
3116 vlog("# Using TESTDIR", _strpath(self._testdir))
3115 vlog("# Using RUNTESTDIR", osenvironb[b'RUNTESTDIR'])
3117 vlog("# Using RUNTESTDIR", _strpath(osenvironb[b'RUNTESTDIR']))
3116 vlog("# Using HGTMP", self._hgtmp)
3118 vlog("# Using HGTMP", _strpath(self._hgtmp))
3117 vlog("# Using PATH", os.environ["PATH"])
3119 vlog("# Using PATH", os.environ["PATH"])
3118 vlog("# Using", IMPL_PATH, osenvironb[IMPL_PATH])
3120 vlog(
3119 vlog("# Writing to directory", self._outputdir)
3121 "# Using", _strpath(IMPL_PATH), _strpath(osenvironb[IMPL_PATH]),
3122 )
3123 vlog("# Writing to directory", _strpath(self._outputdir))
3120
3124
3121 try:
3125 try:
3122 return self._runtests(testdescs) or 0
3126 return self._runtests(testdescs) or 0
@@ -3357,7 +3361,7 b' class TestRunner(object):'
3357 if self.options.keep_tmpdir:
3361 if self.options.keep_tmpdir:
3358 return
3362 return
3359
3363
3360 vlog("# Cleaning up HGTMP", self._hgtmp)
3364 vlog("# Cleaning up HGTMP", _strpath(self._hgtmp))
3361 shutil.rmtree(self._hgtmp, True)
3365 shutil.rmtree(self._hgtmp, True)
3362 for f in self._createdfiles:
3366 for f in self._createdfiles:
3363 try:
3367 try:
@@ -3468,7 +3472,7 b' class TestRunner(object):'
3468 makedirs(self._pythondir)
3472 makedirs(self._pythondir)
3469 makedirs(self._bindir)
3473 makedirs(self._bindir)
3470
3474
3471 vlog("# Running", cmd)
3475 vlog("# Running", cmd.decode("utf-8"))
3472 if subprocess.call(_strpath(cmd), shell=True) == 0:
3476 if subprocess.call(_strpath(cmd), shell=True) == 0:
3473 if not self.options.verbose:
3477 if not self.options.verbose:
3474 try:
3478 try:
@@ -3643,13 +3647,11 b' class TestRunner(object):'
3643 if os.name == 'nt' and not p.endswith(b'.exe'):
3647 if os.name == 'nt' and not p.endswith(b'.exe'):
3644 p += b'.exe'
3648 p += b'.exe'
3645 found = self._findprogram(p)
3649 found = self._findprogram(p)
3650 p = p.decode("utf-8")
3646 if found:
3651 if found:
3647 vlog("# Found prerequisite", p, "at", found)
3652 vlog("# Found prerequisite", p, "at", _strpath(found))
3648 else:
3653 else:
3649 print(
3654 print("WARNING: Did not find prerequisite tool: %s " % p)
3650 "WARNING: Did not find prerequisite tool: %s "
3651 % p.decode("utf-8")
3652 )
3653
3655
3654
3656
3655 def aggregateexceptions(path):
3657 def aggregateexceptions(path):
@@ -1,4 +1,4 b''
1 #require py3
1 #require py37
2
2
3 $ byteify_strings () {
3 $ byteify_strings () {
4 > $PYTHON "$TESTDIR/../contrib/byteify-strings.py" "$@"
4 > $PYTHON "$TESTDIR/../contrib/byteify-strings.py" "$@"
@@ -21,7 +21,6 b' New errors are not allowed. Warnings are'
21 Skipping contrib/automation/hgautomation/try_server.py it has no-che?k-code (glob)
21 Skipping contrib/automation/hgautomation/try_server.py it has no-che?k-code (glob)
22 Skipping contrib/automation/hgautomation/windows.py it has no-che?k-code (glob)
22 Skipping contrib/automation/hgautomation/windows.py it has no-che?k-code (glob)
23 Skipping contrib/automation/hgautomation/winrm.py it has no-che?k-code (glob)
23 Skipping contrib/automation/hgautomation/winrm.py it has no-che?k-code (glob)
24 Skipping contrib/grey.py it has no-che?k-code (glob)
25 Skipping contrib/packaging/hgpackaging/downloads.py it has no-che?k-code (glob)
24 Skipping contrib/packaging/hgpackaging/downloads.py it has no-che?k-code (glob)
26 Skipping contrib/packaging/hgpackaging/inno.py it has no-che?k-code (glob)
25 Skipping contrib/packaging/hgpackaging/inno.py it has no-che?k-code (glob)
27 Skipping contrib/packaging/hgpackaging/py2exe.py it has no-che?k-code (glob)
26 Skipping contrib/packaging/hgpackaging/py2exe.py it has no-che?k-code (glob)
@@ -1,7 +1,5 b''
1 #require grey
1 #require black
2
3 (this should use the actual black as soon as possible)
4
2
5 $ cd $RUNTESTDIR/..
3 $ cd $RUNTESTDIR/..
6 $ python3 contrib/grey.py --config=black.toml --check --diff `hg files 'set:**.py - hgext/fsmonitor/pywatchman/** - mercurial/thirdparty/** - "contrib/python-zstandard/**" - contrib/grey.py'`
4 $ black --config=black.toml --check --diff `hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"'`
7
5
@@ -20,7 +20,6 b' outputs, which should be fixed later.'
20 > -X setup.py \
20 > -X setup.py \
21 > -X contrib/automation/ \
21 > -X contrib/automation/ \
22 > -X contrib/debugshell.py \
22 > -X contrib/debugshell.py \
23 > -X contrib/grey.py \
24 > -X contrib/hgweb.fcgi \
23 > -X contrib/hgweb.fcgi \
25 > -X contrib/packaging/hg-docker \
24 > -X contrib/packaging/hg-docker \
26 > -X contrib/packaging/hgpackaging/ \
25 > -X contrib/packaging/hgpackaging/ \
@@ -6,7 +6,6 b''
6 #if no-py3
6 #if no-py3
7 $ testrepohg files 'set:(**.py)' \
7 $ testrepohg files 'set:(**.py)' \
8 > -X contrib/automation/ \
8 > -X contrib/automation/ \
9 > -X contrib/grey.py \
10 > -X contrib/packaging/hgpackaging/ \
9 > -X contrib/packaging/hgpackaging/ \
11 > -X contrib/packaging/inno/ \
10 > -X contrib/packaging/inno/ \
12 > -X contrib/packaging/wix/ \
11 > -X contrib/packaging/wix/ \
@@ -87,6 +87,172 b' Test case sensitive configuration'
87 }
87 }
88 ]
88 ]
89
89
90 Test config default of various types:
91
92 {"defaultvalue": ""} for -T'json(defaultvalue)' looks weird, but that's
93 how the templater works. Unknown keywords are evaluated to "".
94
95 dynamicdefault
96
97 $ hg config --config alias.foo= alias -Tjson
98 [
99 {
100 "name": "alias.foo",
101 "source": "--config",
102 "value": ""
103 }
104 ]
105 $ hg config --config alias.foo= alias -T'json(defaultvalue)'
106 [
107 {"defaultvalue": ""}
108 ]
109 $ hg config --config alias.foo= alias -T'{defaultvalue}\n'
110
111
112 null
113
114 $ hg config --config auth.cookiefile= auth -Tjson
115 [
116 {
117 "defaultvalue": null,
118 "name": "auth.cookiefile",
119 "source": "--config",
120 "value": ""
121 }
122 ]
123 $ hg config --config auth.cookiefile= auth -T'json(defaultvalue)'
124 [
125 {"defaultvalue": null}
126 ]
127 $ hg config --config auth.cookiefile= auth -T'{defaultvalue}\n'
128
129
130 false
131
132 $ hg config --config commands.commit.post-status= commands -Tjson
133 [
134 {
135 "defaultvalue": false,
136 "name": "commands.commit.post-status",
137 "source": "--config",
138 "value": ""
139 }
140 ]
141 $ hg config --config commands.commit.post-status= commands -T'json(defaultvalue)'
142 [
143 {"defaultvalue": false}
144 ]
145 $ hg config --config commands.commit.post-status= commands -T'{defaultvalue}\n'
146 False
147
148 true
149
150 $ hg config --config format.dotencode= format -Tjson
151 [
152 {
153 "defaultvalue": true,
154 "name": "format.dotencode",
155 "source": "--config",
156 "value": ""
157 }
158 ]
159 $ hg config --config format.dotencode= format -T'json(defaultvalue)'
160 [
161 {"defaultvalue": true}
162 ]
163 $ hg config --config format.dotencode= format -T'{defaultvalue}\n'
164 True
165
166 bytes
167
168 $ hg config --config commands.resolve.mark-check= commands -Tjson
169 [
170 {
171 "defaultvalue": "none",
172 "name": "commands.resolve.mark-check",
173 "source": "--config",
174 "value": ""
175 }
176 ]
177 $ hg config --config commands.resolve.mark-check= commands -T'json(defaultvalue)'
178 [
179 {"defaultvalue": "none"}
180 ]
181 $ hg config --config commands.resolve.mark-check= commands -T'{defaultvalue}\n'
182 none
183
184 empty list
185
186 $ hg config --config commands.show.aliasprefix= commands -Tjson
187 [
188 {
189 "defaultvalue": [],
190 "name": "commands.show.aliasprefix",
191 "source": "--config",
192 "value": ""
193 }
194 ]
195 $ hg config --config commands.show.aliasprefix= commands -T'json(defaultvalue)'
196 [
197 {"defaultvalue": []}
198 ]
199 $ hg config --config commands.show.aliasprefix= commands -T'{defaultvalue}\n'
200
201
202 nonempty list
203
204 $ hg config --config progress.format= progress -Tjson
205 [
206 {
207 "defaultvalue": ["topic", "bar", "number", "estimate"],
208 "name": "progress.format",
209 "source": "--config",
210 "value": ""
211 }
212 ]
213 $ hg config --config progress.format= progress -T'json(defaultvalue)'
214 [
215 {"defaultvalue": ["topic", "bar", "number", "estimate"]}
216 ]
217 $ hg config --config progress.format= progress -T'{defaultvalue}\n'
218 topic bar number estimate
219
220 int
221
222 $ hg config --config profiling.freq= profiling -Tjson
223 [
224 {
225 "defaultvalue": 1000,
226 "name": "profiling.freq",
227 "source": "--config",
228 "value": ""
229 }
230 ]
231 $ hg config --config profiling.freq= profiling -T'json(defaultvalue)'
232 [
233 {"defaultvalue": 1000}
234 ]
235 $ hg config --config profiling.freq= profiling -T'{defaultvalue}\n'
236 1000
237
238 float
239
240 $ hg config --config profiling.showmax= profiling -Tjson
241 [
242 {
243 "defaultvalue": 0.999,
244 "name": "profiling.showmax",
245 "source": "--config",
246 "value": ""
247 }
248 ]
249 $ hg config --config profiling.showmax= profiling -T'json(defaultvalue)'
250 [
251 {"defaultvalue": 0.999}
252 ]
253 $ hg config --config profiling.showmax= profiling -T'{defaultvalue}\n'
254 0.999
255
90 Test empty config source:
256 Test empty config source:
91
257
92 $ cat <<EOF > emptysource.py
258 $ cat <<EOF > emptysource.py
@@ -13,18 +13,16 b" Ensure debuild doesn't run the testsuite"
13 $ make deb > $OUTPUTDIR/build.log 2>&1
13 $ make deb > $OUTPUTDIR/build.log 2>&1
14 $ cd $OUTPUTDIR
14 $ cd $OUTPUTDIR
15 $ ls *.deb | grep -v 'dbg'
15 $ ls *.deb | grep -v 'dbg'
16 mercurial-common_*.deb (glob)
17 mercurial_*.deb (glob)
16 mercurial_*.deb (glob)
18 main deb should have .so but no .py
17 should have .so and .py
19 $ dpkg --contents mercurial_*.deb | egrep '(localrepo|parsers)'
18 $ dpkg --contents mercurial_*.deb | egrep '(localrepo|parsers)'
20 * ./usr/lib/python2.7/dist-packages/mercurial/cext/parsers*.so (glob)
19 * ./usr/lib/python3/dist-packages/mercurial/cext/parsers*.so (glob)
21 mercurial-common should have py but no .so or pyc
20 * ./usr/lib/python3/dist-packages/mercurial/localrepo.py (glob)
22 $ dpkg --contents mercurial-common_*.deb | egrep '(localrepo|parsers.*so)'
21 * ./usr/lib/python3/dist-packages/mercurial/pure/parsers.py (glob)
23 * ./usr/lib/python2.7/dist-packages/mercurial/localrepo.py (glob)
22 should have zsh completions
24 zsh completions should be in the common package
23 $ dpkg --contents mercurial_*.deb | egrep 'zsh.*[^/]$'
25 $ dpkg --contents mercurial-common_*.deb | egrep 'zsh.*[^/]$'
26 * ./usr/share/zsh/vendor-completions/_hg (glob)
24 * ./usr/share/zsh/vendor-completions/_hg (glob)
27 chg should be installed alongside hg, in the 'mercurial' package
25 should have chg
28 $ dpkg --contents mercurial_*.deb | egrep 'chg$'
26 $ dpkg --contents mercurial_*.deb | egrep 'chg$'
29 * ./usr/bin/chg (glob)
27 * ./usr/bin/chg (glob)
30 chg should come with a man page
28 chg should come with a man page
@@ -209,12 +209,12 b' Ensure the data got to the server OK'
209 insertflagprocessor(flag, processor, flagprocessors)
209 insertflagprocessor(flag, processor, flagprocessors)
210 File "*/mercurial/revlogutils/flagutil.py", line *, in insertflagprocessor (glob)
210 File "*/mercurial/revlogutils/flagutil.py", line *, in insertflagprocessor (glob)
211 raise error.Abort(msg)
211 raise error.Abort(msg)
212 mercurial.error.Abort: b"cannot register multiple processors on flag '0x8'." (py3 !)
212 mercurial.error.Abort: cannot register multiple processors on flag '0x8'. (py3 !)
213 Abort: cannot register multiple processors on flag '0x8'. (no-py3 !)
213 Abort: cannot register multiple processors on flag '0x8'. (no-py3 !)
214 *** failed to set up extension duplicate: cannot register multiple processors on flag '0x8'.
214 *** failed to set up extension duplicate: cannot register multiple processors on flag '0x8'.
215 $ hg st 2>&1 | egrep 'cannot register multiple processors|flagprocessorext'
215 $ hg st 2>&1 | egrep 'cannot register multiple processors|flagprocessorext'
216 File "*/tests/flagprocessorext.py", line *, in extsetup (glob)
216 File "*/tests/flagprocessorext.py", line *, in extsetup (glob)
217 mercurial.error.Abort: b"cannot register multiple processors on flag '0x8'." (py3 !)
217 mercurial.error.Abort: cannot register multiple processors on flag '0x8'. (py3 !)
218 Abort: cannot register multiple processors on flag '0x8'. (no-py3 !)
218 Abort: cannot register multiple processors on flag '0x8'. (no-py3 !)
219 *** failed to set up extension duplicate: cannot register multiple processors on flag '0x8'.
219 *** failed to set up extension duplicate: cannot register multiple processors on flag '0x8'.
220 File "*/tests/flagprocessorext.py", line *, in b64decode (glob)
220 File "*/tests/flagprocessorext.py", line *, in b64decode (glob)
@@ -966,7 +966,9 b' errors encountered'
966 $ cd ..
966 $ cd ..
967 $ hg init eucjp
967 $ hg init eucjp
968 $ cd eucjp
968 $ cd eucjp
969 $ "$PYTHON" -c 'print("\265\376")' >> eucjp.txt # Japanese kanji "Kyo"
969 >>> with open('eucjp.txt', 'wb') as fh:
970 ... # Japanese kanji "Kyo"
971 ... fh.write(u'\265\376'.encode('utf-8')) and None
970 $ hg ci -Ama
972 $ hg ci -Ama
971 adding eucjp.txt
973 adding eucjp.txt
972 $ hgserveget () {
974 $ hgserveget () {
@@ -988,7 +988,7 b' test python hooks'
988 ModuleNotFoundError: No module named 'hgext_syntaxerror' (py36 !)
988 ModuleNotFoundError: No module named 'hgext_syntaxerror' (py36 !)
989 Traceback (most recent call last): (py3 !)
989 Traceback (most recent call last): (py3 !)
990 HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed (no-py3 !)
990 HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed (no-py3 !)
991 mercurial.error.HookLoadError: b'preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed' (py3 !)
991 mercurial.error.HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed (py3 !)
992 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
992 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
993
993
994 $ echo '[hooks]' > ../a/.hg/hgrc
994 $ echo '[hooks]' > ../a/.hg/hgrc
@@ -1161,7 +1161,7 b' make sure --traceback works on hook impo'
1161 ModuleNotFoundError: No module named 'hgext_importfail' (py36 !)
1161 ModuleNotFoundError: No module named 'hgext_importfail' (py36 !)
1162 Traceback (most recent call last):
1162 Traceback (most recent call last):
1163 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed (no-py3 !)
1163 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed (no-py3 !)
1164 mercurial.error.HookLoadError: b'precommit.importfail hook is invalid: import of "importfail" failed' (py3 !)
1164 mercurial.error.HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed (py3 !)
1165 abort: precommit.importfail hook is invalid: import of "importfail" failed
1165 abort: precommit.importfail hook is invalid: import of "importfail" failed
1166
1166
1167 Issue1827: Hooks Update & Commit not completely post operation
1167 Issue1827: Hooks Update & Commit not completely post operation
@@ -236,25 +236,56 b' Verify the json works too:'
236
236
237 #endif
237 #endif
238
238
239 #if py3
240 $ HGALLOWPYTHON3=1
241 $ export HGALLOWPYTHON3
242 #endif
243
244 #if virtualenv
245
246 Verify that Mercurial is installable with pip. Note that this MUST be
239 Verify that Mercurial is installable with pip. Note that this MUST be
247 the last test in this file, because we do some nasty things to the
240 the last test in this file, because we do some nasty things to the
248 shell environment in order to make the virtualenv work reliably.
241 shell environment in order to make the virtualenv work reliably.
249
242
243 On Python 3, we use the venv module, which is part of the standard library.
244 But some Linux distros strip out this module's functionality involving pip,
245 so we have to look for the ensurepip module, which these distros strip out
246 completely.
247 On Python 2, we use the 3rd party virtualenv module, if available.
248
250 $ cd $TESTTMP
249 $ cd $TESTTMP
250 $ unset PYTHONPATH
251
252 #if py3 ensurepip
253 $ "$PYTHON" -m venv installenv >> pip.log
254
255 Note: we use this weird path to run pip and hg to avoid platform differences,
256 since it's bin on most platforms but Scripts on Windows.
257 $ ./installenv/*/pip install --no-index $TESTDIR/.. >> pip.log
258 $ ./installenv/*/hg debuginstall || cat pip.log
259 checking encoding (ascii)...
260 checking Python executable (*) (glob)
261 checking Python version (3.*) (glob)
262 checking Python lib (*)... (glob)
263 checking Python security support (*) (glob)
264 checking Mercurial version (*) (glob)
265 checking Mercurial custom build (*) (glob)
266 checking module policy (*) (glob)
267 checking installed modules (*/mercurial)... (glob)
268 checking registered compression engines (*) (glob)
269 checking available compression engines (*) (glob)
270 checking available compression engines for wire protocol (*) (glob)
271 checking "re2" regexp engine \((available|missing)\) (re)
272 checking templates ($TESTTMP/installenv/*/site-packages/mercurial/templates)... (glob)
273 checking default template ($TESTTMP/installenv/*/site-packages/mercurial/templates/map-cmdline.default) (glob)
274 checking commit editor... (*) (glob)
275 checking username (test)
276 no problems detected
277 #endif
278
279 #if no-py3 virtualenv
280
251 Note: --no-site-packages is deprecated, but some places have an
281 Note: --no-site-packages is deprecated, but some places have an
252 ancient virtualenv from their linux distro or similar and it's not yet
282 ancient virtualenv from their linux distro or similar and it's not yet
253 the default for them.
283 the default for them.
254 $ unset PYTHONPATH
284
255 $ "$PYTHON" -m virtualenv --no-site-packages --never-download installenv >> pip.log
285 $ "$PYTHON" -m virtualenv --no-site-packages --never-download installenv >> pip.log
256 DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. (?)
286 DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. (?)
257 DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support (?)
287 DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support (?)
288
258 Note: we use this weird path to run pip and hg to avoid platform differences,
289 Note: we use this weird path to run pip and hg to avoid platform differences,
259 since it's bin on most platforms but Scripts on Windows.
290 since it's bin on most platforms but Scripts on Windows.
260 $ ./installenv/*/pip install --no-index $TESTDIR/.. >> pip.log
291 $ ./installenv/*/pip install --no-index $TESTDIR/.. >> pip.log
@@ -263,8 +294,7 b" since it's bin on most platforms but Scr"
263 $ ./installenv/*/hg debuginstall || cat pip.log
294 $ ./installenv/*/hg debuginstall || cat pip.log
264 checking encoding (ascii)...
295 checking encoding (ascii)...
265 checking Python executable (*) (glob)
296 checking Python executable (*) (glob)
266 checking Python version (2.*) (glob) (no-py3 !)
297 checking Python version (2.*) (glob)
267 checking Python version (3.*) (glob) (py3 !)
268 checking Python lib (*)... (glob)
298 checking Python lib (*)... (glob)
269 checking Python security support (*) (glob)
299 checking Python security support (*) (glob)
270 TLS 1.2 not supported by Python install; network connections lack modern security (?)
300 TLS 1.2 not supported by Python install; network connections lack modern security (?)
@@ -256,7 +256,8 b' ie. if patch.diff wrapper acts as it sho'
256
256
257 Pull from bundle and trigger notify
257 Pull from bundle and trigger notify
258
258
259 $ hg pull -u ../kw.hg
259 $ hg pull -u ../kw.hg | \
260 > "$PYTHON" $TESTDIR/unwrap-message-id.py
260 pulling from ../kw.hg
261 pulling from ../kw.hg
261 requesting all changes
262 requesting all changes
262 adding changesets
263 adding changesets
@@ -354,7 +354,8 b' Test a checksum failure during the proce'
354 $LOCALIP - - [$ERRDATE$] HG error: localstore.download(oid, req.bodyfh) (glob)
354 $LOCALIP - - [$ERRDATE$] HG error: localstore.download(oid, req.bodyfh) (glob)
355 $LOCALIP - - [$ERRDATE$] HG error: super(badstore, self).download(oid, src) (glob)
355 $LOCALIP - - [$ERRDATE$] HG error: super(badstore, self).download(oid, src) (glob)
356 $LOCALIP - - [$ERRDATE$] HG error: _(b'corrupt remote lfs object: %s') % oid (glob)
356 $LOCALIP - - [$ERRDATE$] HG error: _(b'corrupt remote lfs object: %s') % oid (glob)
357 $LOCALIP - - [$ERRDATE$] HG error: LfsCorruptionError: corrupt remote lfs object: b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c (glob)
357 $LOCALIP - - [$ERRDATE$] HG error: LfsCorruptionError: corrupt remote lfs object: b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c (no-py3 !)
358 $LOCALIP - - [$ERRDATE$] HG error: hgext.lfs.blobstore.LfsCorruptionError: corrupt remote lfs object: b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c (py3 !)
358 $LOCALIP - - [$ERRDATE$] HG error: (glob)
359 $LOCALIP - - [$ERRDATE$] HG error: (glob)
359 $LOCALIP - - [$ERRDATE$] Exception happened during processing request '/.hg/lfs/objects/276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d': (glob)
360 $LOCALIP - - [$ERRDATE$] Exception happened during processing request '/.hg/lfs/objects/276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d': (glob)
360 Traceback (most recent call last):
361 Traceback (most recent call last):
@@ -376,7 +377,8 b' Test a checksum failure during the proce'
376 $LOCALIP - - [$ERRDATE$] HG error: blob = self._read(self.vfs, oid, verify) (glob)
377 $LOCALIP - - [$ERRDATE$] HG error: blob = self._read(self.vfs, oid, verify) (glob)
377 $LOCALIP - - [$ERRDATE$] HG error: blobstore._verify(oid, b'dummy content') (glob)
378 $LOCALIP - - [$ERRDATE$] HG error: blobstore._verify(oid, b'dummy content') (glob)
378 $LOCALIP - - [$ERRDATE$] HG error: hint=_(b'run hg verify'), (glob)
379 $LOCALIP - - [$ERRDATE$] HG error: hint=_(b'run hg verify'), (glob)
379 $LOCALIP - - [$ERRDATE$] HG error: LfsCorruptionError: detected corrupt lfs object: 276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d (glob)
380 $LOCALIP - - [$ERRDATE$] HG error: LfsCorruptionError: detected corrupt lfs object: 276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d (no-py3 !)
381 $LOCALIP - - [$ERRDATE$] HG error: hgext.lfs.blobstore.LfsCorruptionError: detected corrupt lfs object: 276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d (py3 !)
380 $LOCALIP - - [$ERRDATE$] HG error: (glob)
382 $LOCALIP - - [$ERRDATE$] HG error: (glob)
381
383
382 Basic Authorization headers are returned by the Batch API, and sent back with
384 Basic Authorization headers are returned by the Batch API, and sent back with
@@ -2,6 +2,7 b' from __future__ import absolute_import'
2
2
3 import unittest
3 import unittest
4 from mercurial import error, mdiff
4 from mercurial import error, mdiff
5 from mercurial.utils import stringutil
5
6
6 # for readability, line numbers are 0-origin
7 # for readability, line numbers are 0-origin
7 text1 = b'''
8 text1 = b'''
@@ -228,7 +229,10 b' class blocksinrangetests(unittest.TestCa'
228 try:
229 try:
229 mdiff.blocksinrange(self.blocks, linerange2)
230 mdiff.blocksinrange(self.blocks, linerange2)
230 except exctype as exc:
231 except exctype as exc:
231 self.assertTrue('line range exceeds file size' in str(exc))
232 self.assertTrue(
233 b'line range exceeds file size'
234 in stringutil.forcebytestr(exc)
235 )
232 else:
236 else:
233 self.fail('%s not raised' % exctype.__name__)
237 self.fail('%s not raised' % exctype.__name__)
234
238
@@ -316,7 +316,7 b' class DifferenceMatcherTests(unittest.Te'
316
316
317 # We're using includematcher instead of patterns because it behaves slightly
317 # We're using includematcher instead of patterns because it behaves slightly
318 # better (giving narrower results) than patternmatcher.
318 # better (giving narrower results) than patternmatcher.
319 def testVisitdirIncludeIncludfe(self):
319 def testVisitdirIncludeInclude(self):
320 m1 = matchmod.match(b'', b'', include=[b'path:dir/subdir'])
320 m1 = matchmod.match(b'', b'', include=[b'path:dir/subdir'])
321 m2 = matchmod.match(b'', b'', include=[b'rootfilesin:dir'])
321 m2 = matchmod.match(b'', b'', include=[b'rootfilesin:dir'])
322 dm = matchmod.differencematcher(m1, m2)
322 dm = matchmod.differencematcher(m1, m2)
@@ -430,7 +430,7 b' class IntersectionMatcherTests(unittest.'
430
430
431 # We're using includematcher instead of patterns because it behaves slightly
431 # We're using includematcher instead of patterns because it behaves slightly
432 # better (giving narrower results) than patternmatcher.
432 # better (giving narrower results) than patternmatcher.
433 def testVisitdirIncludeIncludfe(self):
433 def testVisitdirIncludeInclude(self):
434 m1 = matchmod.match(b'', b'', include=[b'path:dir/subdir'])
434 m1 = matchmod.match(b'', b'', include=[b'path:dir/subdir'])
435 m2 = matchmod.match(b'', b'', include=[b'rootfilesin:dir'])
435 m2 = matchmod.match(b'', b'', include=[b'rootfilesin:dir'])
436 im = matchmod.intersectmatchers(m1, m2)
436 im = matchmod.intersectmatchers(m1, m2)
@@ -644,7 +644,7 b' class UnionMatcherTests(unittest.TestCas'
644
644
645 # We're using includematcher instead of patterns because it behaves slightly
645 # We're using includematcher instead of patterns because it behaves slightly
646 # better (giving narrower results) than patternmatcher.
646 # better (giving narrower results) than patternmatcher.
647 def testVisitdirIncludeIncludfe(self):
647 def testVisitdirIncludeInclude(self):
648 m1 = matchmod.match(b'', b'', include=[b'path:dir/subdir'])
648 m1 = matchmod.match(b'', b'', include=[b'path:dir/subdir'])
649 m2 = matchmod.match(b'', b'', include=[b'rootfilesin:dir'])
649 m2 = matchmod.match(b'', b'', include=[b'rootfilesin:dir'])
650 um = matchmod.unionmatcher([m1, m2])
650 um = matchmod.unionmatcher([m1, m2])
@@ -39,6 +39,7 b' commit'
39 push
39 push
40
40
41 $ hg --traceback --cwd b push ../a 2>&1 |
41 $ hg --traceback --cwd b push ../a 2>&1 |
42 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
42 > "$PYTHON" -c 'from __future__ import print_function ; import sys,re; print(re.sub("\n\t", " ", sys.stdin.read()), end="")'
43 > "$PYTHON" -c 'from __future__ import print_function ; import sys,re; print(re.sub("\n\t", " ", sys.stdin.read()), end="")'
43 pushing to ../a
44 pushing to ../a
44 searching for changes
45 searching for changes
@@ -93,6 +94,7 b' unbundle with unrelated source'
93 unbundle with correct source
94 unbundle with correct source
94
95
95 $ hg --config notify.sources=unbundle --cwd a unbundle ../test.hg 2>&1 |
96 $ hg --config notify.sources=unbundle --cwd a unbundle ../test.hg 2>&1 |
97 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
96 > "$PYTHON" -c 'from __future__ import print_function ; import sys,re; print(re.sub("\n\t", " ", sys.stdin.read()), end="")'
98 > "$PYTHON" -c 'from __future__ import print_function ; import sys,re; print(re.sub("\n\t", " ", sys.stdin.read()), end="")'
97 adding changesets
99 adding changesets
98 adding manifests
100 adding manifests
@@ -169,6 +171,7 b' merge as a different user'
169 push
171 push
170
172
171 $ hg --traceback --cwd b --config notify.fromauthor=True push ../a 2>&1 |
173 $ hg --traceback --cwd b --config notify.fromauthor=True push ../a 2>&1 |
174 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
172 > "$PYTHON" -c 'from __future__ import print_function ; import sys,re; print(re.sub("\n\t", " ", sys.stdin.read()), end="")'
175 > "$PYTHON" -c 'from __future__ import print_function ; import sys,re; print(re.sub("\n\t", " ", sys.stdin.read()), end="")'
173 pushing to ../a
176 pushing to ../a
174 searching for changes
177 searching for changes
@@ -196,7 +196,9 b' the python call below wraps continuation'
196 of the very long subject line
196 of the very long subject line
197 pull (minimal config)
197 pull (minimal config)
198
198
199 $ hg --traceback --cwd b --config notify.domain=example.com --config notify.messageidseed=example pull ../a | "$PYTHON" $TESTTMP/filter.py
199 $ hg --traceback --cwd b --config notify.domain=example.com --config notify.messageidseed=example pull ../a | \
200 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
201 > "$PYTHON" $TESTTMP/filter.py
200 pulling from ../a
202 pulling from ../a
201 searching for changes
203 searching for changes
202 adding changesets
204 adding changesets
@@ -255,7 +257,9 b' pull'
255
257
256 $ hg --cwd b rollback
258 $ hg --cwd b rollback
257 repository tip rolled back to revision 0 (undo pull)
259 repository tip rolled back to revision 0 (undo pull)
258 $ hg --traceback --cwd b pull ../a | "$PYTHON" $TESTTMP/filter.py
260 $ hg --traceback --cwd b pull ../a | \
261 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
262 > "$PYTHON" $TESTTMP/filter.py
259 pulling from ../a
263 pulling from ../a
260 searching for changes
264 searching for changes
261 adding changesets
265 adding changesets
@@ -303,7 +307,9 b' pull'
303
307
304 $ hg --cwd b rollback
308 $ hg --cwd b rollback
305 repository tip rolled back to revision 0 (undo pull)
309 repository tip rolled back to revision 0 (undo pull)
306 $ hg --traceback --config notify.maxdiffstat=1 --cwd b pull ../a | "$PYTHON" $TESTTMP/filter.py
310 $ hg --traceback --config notify.maxdiffstat=1 --cwd b pull ../a | \
311 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
312 > "$PYTHON" $TESTTMP/filter.py
307 pulling from ../a
313 pulling from ../a
308 searching for changes
314 searching for changes
309 adding changesets
315 adding changesets
@@ -354,7 +360,9 b' test merge'
354 (branch merge, don't forget to commit)
360 (branch merge, don't forget to commit)
355 $ hg ci -m merge -d '3 0'
361 $ hg ci -m merge -d '3 0'
356 $ cd ..
362 $ cd ..
357 $ hg --traceback --cwd b pull ../a | "$PYTHON" $TESTTMP/filter.py
363 $ hg --traceback --cwd b pull ../a | \
364 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
365 > "$PYTHON" $TESTTMP/filter.py
358 pulling from ../a
366 pulling from ../a
359 searching for changes
367 searching for changes
360 adding changesets
368 adding changesets
@@ -418,8 +426,9 b' non-ascii content and truncation of mult'
418 > EOF
426 > EOF
419 $ echo a >> a/a
427 $ echo a >> a/a
420 $ hg --cwd a --encoding utf-8 commit -A -d '0 0' \
428 $ hg --cwd a --encoding utf-8 commit -A -d '0 0' \
421 > -m `"$PYTHON" -c 'print("\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4")'`
429 > -m `"$PYTHON" -c 'import sys; getattr(sys.stdout, "buffer", sys.stdout).write(b"\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4")'`
422 $ hg --traceback --cwd b --encoding utf-8 pull ../a | \
430 $ hg --traceback --cwd b --encoding utf-8 pull ../a | \
431 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
423 > "$PYTHON" $TESTTMP/filter.py
432 > "$PYTHON" $TESTTMP/filter.py
424 pulling from ../a
433 pulling from ../a
425 searching for changes
434 searching for changes
@@ -433,7 +442,8 b' non-ascii content and truncation of mult'
433 Content-Transfer-Encoding: 8bit
442 Content-Transfer-Encoding: 8bit
434 X-Test: foo
443 X-Test: foo
435 Date: * (glob)
444 Date: * (glob)
436 Subject: \xc3\xa0... (esc)
445 Subject: \xc3\xa0... (esc) (no-py3 !)
446 Subject: =?utf-8?b?w6AuLi4=?= (py3 !)
437 From: test@test.com
447 From: test@test.com
438 X-Hg-Notification: changeset 0f25f9c22b4c
448 X-Hg-Notification: changeset 0f25f9c22b4c
439 Message-Id: <*> (glob)
449 Message-Id: <*> (glob)
@@ -473,7 +483,7 b' long lines'
473 new changesets a846b5f6ebb7
483 new changesets a846b5f6ebb7
474 notify: sending 2 subscribers 1 changes
484 notify: sending 2 subscribers 1 changes
475 (run 'hg update' to get a working copy)
485 (run 'hg update' to get a working copy)
476 $ "$PYTHON" $TESTTMP/filter.py < b/mbox
486 $ cat b/mbox | "$PYTHON" $TESTDIR/unwrap-message-id.py | "$PYTHON" $TESTTMP/filter.py
477 From test@test.com ... ... .. ..:..:.. .... (re)
487 From test@test.com ... ... .. ..:..:.. .... (re)
478 MIME-Version: 1.0
488 MIME-Version: 1.0
479 Content-Type: text/plain; charset="*" (glob)
489 Content-Type: text/plain; charset="*" (glob)
@@ -533,7 +543,9 b' long lines'
533 (branches are permanent and global, did you want a bookmark?)
543 (branches are permanent and global, did you want a bookmark?)
534 $ echo a >> a/a
544 $ echo a >> a/a
535 $ hg --cwd a ci -m test -d '1 0'
545 $ hg --cwd a ci -m test -d '1 0'
536 $ hg --traceback --cwd b pull ../a | "$PYTHON" $TESTTMP/filter.py
546 $ hg --traceback --cwd b pull ../a | \
547 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
548 > "$PYTHON" $TESTTMP/filter.py
537 pulling from ../a
549 pulling from ../a
538 searching for changes
550 searching for changes
539 adding changesets
551 adding changesets
@@ -563,7 +575,9 b' from different branch'
563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
575 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
564 $ echo a >> a/a
576 $ echo a >> a/a
565 $ hg --cwd a ci -m test -d '1 0'
577 $ hg --cwd a ci -m test -d '1 0'
566 $ hg --traceback --cwd b pull ../a | "$PYTHON" $TESTTMP/filter.py
578 $ hg --traceback --cwd b pull ../a | \
579 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
580 > "$PYTHON" $TESTTMP/filter.py
567 pulling from ../a
581 pulling from ../a
568 searching for changes
582 searching for changes
569 adding changesets
583 adding changesets
@@ -592,7 +606,9 b' default template:'
592 $ mv "$HGRCPATH.new" $HGRCPATH
606 $ mv "$HGRCPATH.new" $HGRCPATH
593 $ echo a >> a/a
607 $ echo a >> a/a
594 $ hg --cwd a commit -m 'default template'
608 $ hg --cwd a commit -m 'default template'
595 $ hg --cwd b pull ../a -q | "$PYTHON" $TESTTMP/filter.py
609 $ hg --cwd b pull ../a -q | \
610 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
611 > "$PYTHON" $TESTTMP/filter.py
596 MIME-Version: 1.0
612 MIME-Version: 1.0
597 Content-Type: text/plain; charset="us-ascii"
613 Content-Type: text/plain; charset="us-ascii"
598 Content-Transfer-Encoding: 7bit
614 Content-Transfer-Encoding: 7bit
@@ -621,7 +637,9 b' with style:'
621 > EOF
637 > EOF
622 $ echo a >> a/a
638 $ echo a >> a/a
623 $ hg --cwd a commit -m 'with style'
639 $ hg --cwd a commit -m 'with style'
624 $ hg --cwd b pull ../a -q | "$PYTHON" $TESTTMP/filter.py
640 $ hg --cwd b pull ../a -q | \
641 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
642 > "$PYTHON" $TESTTMP/filter.py
625 MIME-Version: 1.0
643 MIME-Version: 1.0
626 Content-Type: text/plain; charset="us-ascii"
644 Content-Type: text/plain; charset="us-ascii"
627 Content-Transfer-Encoding: 7bit
645 Content-Transfer-Encoding: 7bit
@@ -644,7 +662,9 b' with template (overrides style):'
644 > EOF
662 > EOF
645 $ echo a >> a/a
663 $ echo a >> a/a
646 $ hg --cwd a commit -m 'with template'
664 $ hg --cwd a commit -m 'with template'
647 $ hg --cwd b pull ../a -q | "$PYTHON" $TESTTMP/filter.py
665 $ hg --cwd b pull ../a -q | \
666 > "$PYTHON" $TESTDIR/unwrap-message-id.py | \
667 > "$PYTHON" $TESTTMP/filter.py
648 MIME-Version: 1.0
668 MIME-Version: 1.0
649 Content-Type: text/plain; charset="us-ascii"
669 Content-Type: text/plain; charset="us-ascii"
650 Content-Transfer-Encoding: 7bit
670 Content-Transfer-Encoding: 7bit
@@ -675,7 +695,8 b' showfunc diff'
675 > EOF
695 > EOF
676 $ hg commit -Am addfunction
696 $ hg commit -Am addfunction
677 adding f1
697 adding f1
678 $ hg --cwd ../b pull ../a
698 $ hg --cwd ../b pull ../a | \
699 > "$PYTHON" $TESTDIR/unwrap-message-id.py
679 pulling from ../a
700 pulling from ../a
680 searching for changes
701 searching for changes
681 adding changesets
702 adding changesets
@@ -718,7 +739,8 b' showfunc diff'
718 > }
739 > }
719 > EOF
740 > EOF
720 $ hg commit -m changefunction
741 $ hg commit -m changefunction
721 $ hg --cwd ../b --config notify.showfunc=True pull ../a
742 $ hg --cwd ../b --config notify.showfunc=True pull ../a | \
743 > "$PYTHON" $TESTDIR/unwrap-message-id.py
722 pulling from ../a
744 pulling from ../a
723 searching for changes
745 searching for changes
724 adding changesets
746 adding changesets
@@ -445,7 +445,9 b' with a specific bundle type'
445
445
446 utf-8 patch:
446 utf-8 patch:
447 $ "$PYTHON" -c 'fp = open("utf", "wb"); fp.write(b"h\xC3\xB6mma!\n"); fp.close();'
447 $ "$PYTHON" -c 'fp = open("utf", "wb"); fp.write(b"h\xC3\xB6mma!\n"); fp.close();'
448 $ hg commit -A -d '4 0' -m 'utf-8 content'
448 $ hg commit -A -d '4 0' \
449 > --encoding "utf-8" \
450 > -m `"$PYTHON" -c 'import sys; getattr(sys.stdout, "buffer", sys.stdout).write(b"\xc3\xa7a")'`
449 adding description
451 adding description
450 adding utf
452 adding utf
451
453
@@ -454,16 +456,16 b' no mime encoding for email --test:'
454 this patch series consists of 1 patches.
456 this patch series consists of 1 patches.
455
457
456
458
457 displaying [PATCH] utf-8 content ...
459 displaying [PATCH] ?a ...
458 MIME-Version: 1.0
460 MIME-Version: 1.0
459 Content-Type: text/plain; charset="iso-8859-1"
461 Content-Type: text/plain; charset="iso-8859-1"
460 Content-Transfer-Encoding: quoted-printable
462 Content-Transfer-Encoding: quoted-printable
461 Subject: [PATCH] utf-8 content
463 Subject: [PATCH] ?a
462 X-Mercurial-Node: 909a00e13e9d78b575aeee23dddbada46d5a143f
464 X-Mercurial-Node: f81ef97829467e868fc405fccbcfa66217e4d3e6
463 X-Mercurial-Series-Index: 1
465 X-Mercurial-Series-Index: 1
464 X-Mercurial-Series-Total: 1
466 X-Mercurial-Series-Total: 1
465 Message-Id: <909a00e13e9d78b575ae.240@test-hostname>
467 Message-Id: <f81ef97829467e868fc4.240@test-hostname>
466 X-Mercurial-Series-Id: <909a00e13e9d78b575ae.240@test-hostname>
468 X-Mercurial-Series-Id: <f81ef97829467e868fc4.240@test-hostname>
467 User-Agent: Mercurial-patchbomb/* (glob)
469 User-Agent: Mercurial-patchbomb/* (glob)
468 Date: Thu, 01 Jan 1970 00:04:00 +0000
470 Date: Thu, 01 Jan 1970 00:04:00 +0000
469 From: quux
471 From: quux
@@ -474,18 +476,18 b' no mime encoding for email --test:'
474 # User test
476 # User test
475 # Date 4 0
477 # Date 4 0
476 # Thu Jan 01 00:00:04 1970 +0000
478 # Thu Jan 01 00:00:04 1970 +0000
477 # Node ID 909a00e13e9d78b575aeee23dddbada46d5a143f
479 # Node ID f81ef97829467e868fc405fccbcfa66217e4d3e6
478 # Parent ff2c9fa2018b15fa74b33363bda9527323e2a99f
480 # Parent ff2c9fa2018b15fa74b33363bda9527323e2a99f
479 utf-8 content
481 ?a
480
482
481 diff -r ff2c9fa2018b -r 909a00e13e9d description
483 diff -r ff2c9fa2018b -r f81ef9782946 description
482 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
484 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
483 +++ b/description Thu Jan 01 00:00:04 1970 +0000
485 +++ b/description Thu Jan 01 00:00:04 1970 +0000
484 @@ -0,0 +1,3 @@
486 @@ -0,0 +1,3 @@
485 +a multiline
487 +a multiline
486 +
488 +
487 +description
489 +description
488 diff -r ff2c9fa2018b -r 909a00e13e9d utf
490 diff -r ff2c9fa2018b -r f81ef9782946 utf
489 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
491 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
490 +++ b/utf Thu Jan 01 00:00:04 1970 +0000
492 +++ b/utf Thu Jan 01 00:00:04 1970 +0000
491 @@ -0,0 +1,1 @@
493 @@ -0,0 +1,1 @@
@@ -497,35 +499,36 b' mime encoded mbox (base64):'
497 this patch series consists of 1 patches.
499 this patch series consists of 1 patches.
498
500
499
501
500 sending [PATCH] utf-8 content ...
502 sending [PATCH] ?a ...
501
503
502 $ cat mbox
504 $ cat mbox
503 From quux ... ... .. ..:..:.. .... (re)
505 From quux ... ... .. ..:..:.. .... (re)
504 MIME-Version: 1.0
506 MIME-Version: 1.0
505 Content-Type: text/plain; charset="utf-8"
507 Content-Type: text/plain; charset="utf-8"
506 Content-Transfer-Encoding: base64
508 Content-Transfer-Encoding: base64
507 Subject: [PATCH] utf-8 content
509 Subject: [PATCH] ?a
508 X-Mercurial-Node: 909a00e13e9d78b575aeee23dddbada46d5a143f
510 X-Mercurial-Node: f81ef97829467e868fc405fccbcfa66217e4d3e6
509 X-Mercurial-Series-Index: 1
511 X-Mercurial-Series-Index: 1
510 X-Mercurial-Series-Total: 1
512 X-Mercurial-Series-Total: 1
511 Message-Id: <909a00e13e9d78b575ae.240@test-hostname>
513 Message-Id: <f81ef97829467e868fc4.240@test-hostname>
512 X-Mercurial-Series-Id: <909a00e13e9d78b575ae.240@test-hostname>
514 X-Mercurial-Series-Id: <f81ef97829467e868fc4.240@test-hostname>
513 User-Agent: Mercurial-patchbomb/* (glob)
515 User-Agent: Mercurial-patchbomb/* (glob)
514 Date: Thu, 01 Jan 1970 00:04:00 +0000
516 Date: Thu, 01 Jan 1970 00:04:00 +0000
515 From: Q <quux>
517 From: Q <quux> (no-py3 !)
518 From: =?iso-8859-1?q?Q?= <quux> (py3 !)
516 To: foo
519 To: foo
517 Cc: bar
520 Cc: bar
518
521
519 IyBIRyBjaGFuZ2VzZXQgcGF0Y2gKIyBVc2VyIHRlc3QKIyBEYXRlIDQgMAojICAgICAgVGh1IEph
522 IyBIRyBjaGFuZ2VzZXQgcGF0Y2gKIyBVc2VyIHRlc3QKIyBEYXRlIDQgMAojICAgICAgVGh1IEph
520 biAwMSAwMDowMDowNCAxOTcwICswMDAwCiMgTm9kZSBJRCA5MDlhMDBlMTNlOWQ3OGI1NzVhZWVl
523 biAwMSAwMDowMDowNCAxOTcwICswMDAwCiMgTm9kZSBJRCBmODFlZjk3ODI5NDY3ZTg2OGZjNDA1
521 MjNkZGRiYWRhNDZkNWExNDNmCiMgUGFyZW50ICBmZjJjOWZhMjAxOGIxNWZhNzRiMzMzNjNiZGE5
524 ZmNjYmNmYTY2MjE3ZTRkM2U2CiMgUGFyZW50ICBmZjJjOWZhMjAxOGIxNWZhNzRiMzMzNjNiZGE5
522 NTI3MzIzZTJhOTlmCnV0Zi04IGNvbnRlbnQKCmRpZmYgLXIgZmYyYzlmYTIwMThiIC1yIDkwOWEw
525 NTI3MzIzZTJhOTlmCj9hCgpkaWZmIC1yIGZmMmM5ZmEyMDE4YiAtciBmODFlZjk3ODI5NDYgZGVz
523 MGUxM2U5ZCBkZXNjcmlwdGlvbgotLS0gL2Rldi9udWxsCVRodSBKYW4gMDEgMDA6MDA6MDAgMTk3
526 Y3JpcHRpb24KLS0tIC9kZXYvbnVsbAlUaHUgSmFuIDAxIDAwOjAwOjAwIDE5NzAgKzAwMDAKKysr
524 MCArMDAwMAorKysgYi9kZXNjcmlwdGlvbglUaHUgSmFuIDAxIDAwOjAwOjA0IDE5NzAgKzAwMDAK
527 IGIvZGVzY3JpcHRpb24JVGh1IEphbiAwMSAwMDowMDowNCAxOTcwICswMDAwCkBAIC0wLDAgKzEs
525 QEAgLTAsMCArMSwzIEBACithIG11bHRpbGluZQorCitkZXNjcmlwdGlvbgpkaWZmIC1yIGZmMmM5
528 MyBAQAorYSBtdWx0aWxpbmUKKworZGVzY3JpcHRpb24KZGlmZiAtciBmZjJjOWZhMjAxOGIgLXIg
526 ZmEyMDE4YiAtciA5MDlhMDBlMTNlOWQgdXRmCi0tLSAvZGV2L251bGwJVGh1IEphbiAwMSAwMDow
529 ZjgxZWY5NzgyOTQ2IHV0ZgotLS0gL2Rldi9udWxsCVRodSBKYW4gMDEgMDA6MDA6MDAgMTk3MCAr
527 MDowMCAxOTcwICswMDAwCisrKyBiL3V0ZglUaHUgSmFuIDAxIDAwOjAwOjA0IDE5NzAgKzAwMDAK
530 MDAwMAorKysgYi91dGYJVGh1IEphbiAwMSAwMDowMDowNCAxOTcwICswMDAwCkBAIC0wLDAgKzEs
528 QEAgLTAsMCArMSwxIEBACitow7ZtbWEhCg==
531 MSBAQAoraMO2bW1hIQo=
529
532
530
533
531 >>> import base64
534 >>> import base64
@@ -540,18 +543,18 b' mime encoded mbox (base64):'
540 # User test
543 # User test
541 # Date 4 0
544 # Date 4 0
542 # Thu Jan 01 00:00:04 1970 +0000
545 # Thu Jan 01 00:00:04 1970 +0000
543 # Node ID 909a00e13e9d78b575aeee23dddbada46d5a143f
546 # Node ID f81ef97829467e868fc405fccbcfa66217e4d3e6
544 # Parent ff2c9fa2018b15fa74b33363bda9527323e2a99f
547 # Parent ff2c9fa2018b15fa74b33363bda9527323e2a99f
545 utf-8 content
548 ?a
546
549
547 diff -r ff2c9fa2018b -r 909a00e13e9d description
550 diff -r ff2c9fa2018b -r f81ef9782946 description
548 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
551 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
549 +++ b/description Thu Jan 01 00:00:04 1970 +0000
552 +++ b/description Thu Jan 01 00:00:04 1970 +0000
550 @@ -0,0 +1,3 @@
553 @@ -0,0 +1,3 @@
551 +a multiline
554 +a multiline
552 +
555 +
553 +description
556 +description
554 diff -r ff2c9fa2018b -r 909a00e13e9d utf
557 diff -r ff2c9fa2018b -r f81ef9782946 utf
555 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
558 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
556 +++ b/utf Thu Jan 01 00:00:04 1970 +0000
559 +++ b/utf Thu Jan 01 00:00:04 1970 +0000
557 @@ -0,0 +1,1 @@
560 @@ -0,0 +1,1 @@
@@ -574,11 +577,11 b' no mime encoding for email --test:'
574 Content-Type: text/plain; charset="us-ascii"
577 Content-Type: text/plain; charset="us-ascii"
575 Content-Transfer-Encoding: quoted-printable
578 Content-Transfer-Encoding: quoted-printable
576 Subject: [PATCH] long line
579 Subject: [PATCH] long line
577 X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
580 X-Mercurial-Node: 0c7b871cb86b61a1c07e244393603c361e4a178d
578 X-Mercurial-Series-Index: 1
581 X-Mercurial-Series-Index: 1
579 X-Mercurial-Series-Total: 1
582 X-Mercurial-Series-Total: 1
580 Message-Id: <a2ea8fc83dd8b93cfd86.240@test-hostname>
583 Message-Id: <0c7b871cb86b61a1c07e.240@test-hostname>
581 X-Mercurial-Series-Id: <a2ea8fc83dd8b93cfd86.240@test-hostname>
584 X-Mercurial-Series-Id: <0c7b871cb86b61a1c07e.240@test-hostname>
582 User-Agent: Mercurial-patchbomb/* (glob)
585 User-Agent: Mercurial-patchbomb/* (glob)
583 Date: Thu, 01 Jan 1970 00:04:00 +0000
586 Date: Thu, 01 Jan 1970 00:04:00 +0000
584 From: quux
587 From: quux
@@ -589,11 +592,11 b' no mime encoding for email --test:'
589 # User test
592 # User test
590 # Date 4 0
593 # Date 4 0
591 # Thu Jan 01 00:00:04 1970 +0000
594 # Thu Jan 01 00:00:04 1970 +0000
592 # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
595 # Node ID 0c7b871cb86b61a1c07e244393603c361e4a178d
593 # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
596 # Parent f81ef97829467e868fc405fccbcfa66217e4d3e6
594 long line
597 long line
595
598
596 diff -r 909a00e13e9d -r a2ea8fc83dd8 long
599 diff -r f81ef9782946 -r 0c7b871cb86b long
597 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
600 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
598 +++ b/long Thu Jan 01 00:00:04 1970 +0000
601 +++ b/long Thu Jan 01 00:00:04 1970 +0000
599 @@ -0,0 +1,4 @@
602 @@ -0,0 +1,4 @@
@@ -628,11 +631,11 b' mime encoded mbox (quoted-printable):'
628 Content-Type: text/plain; charset="us-ascii"
631 Content-Type: text/plain; charset="us-ascii"
629 Content-Transfer-Encoding: quoted-printable
632 Content-Transfer-Encoding: quoted-printable
630 Subject: [PATCH] long line
633 Subject: [PATCH] long line
631 X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
634 X-Mercurial-Node: 0c7b871cb86b61a1c07e244393603c361e4a178d
632 X-Mercurial-Series-Index: 1
635 X-Mercurial-Series-Index: 1
633 X-Mercurial-Series-Total: 1
636 X-Mercurial-Series-Total: 1
634 Message-Id: <a2ea8fc83dd8b93cfd86.240@test-hostname>
637 Message-Id: <0c7b871cb86b61a1c07e.240@test-hostname>
635 X-Mercurial-Series-Id: <a2ea8fc83dd8b93cfd86.240@test-hostname>
638 X-Mercurial-Series-Id: <0c7b871cb86b61a1c07e.240@test-hostname>
636 User-Agent: Mercurial-patchbomb/* (glob)
639 User-Agent: Mercurial-patchbomb/* (glob)
637 Date: Thu, 01 Jan 1970 00:04:00 +0000
640 Date: Thu, 01 Jan 1970 00:04:00 +0000
638 From: quux
641 From: quux
@@ -643,11 +646,11 b' mime encoded mbox (quoted-printable):'
643 # User test
646 # User test
644 # Date 4 0
647 # Date 4 0
645 # Thu Jan 01 00:00:04 1970 +0000
648 # Thu Jan 01 00:00:04 1970 +0000
646 # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
649 # Node ID 0c7b871cb86b61a1c07e244393603c361e4a178d
647 # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
650 # Parent f81ef97829467e868fc405fccbcfa66217e4d3e6
648 long line
651 long line
649
652
650 diff -r 909a00e13e9d -r a2ea8fc83dd8 long
653 diff -r f81ef9782946 -r 0c7b871cb86b long
651 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
654 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
652 +++ b/long Thu Jan 01 00:00:04 1970 +0000
655 +++ b/long Thu Jan 01 00:00:04 1970 +0000
653 @@ -0,0 +1,4 @@
656 @@ -0,0 +1,4 @@
@@ -690,11 +693,11 b' iso-8859-1 mbox:'
690 Content-Type: text/plain; charset="iso-8859-1"
693 Content-Type: text/plain; charset="iso-8859-1"
691 Content-Transfer-Encoding: quoted-printable
694 Content-Transfer-Encoding: quoted-printable
692 Subject: [PATCH] isolatin 8-bit encoding
695 Subject: [PATCH] isolatin 8-bit encoding
693 X-Mercurial-Node: 240fb913fc1b7ff15ddb9f33e73d82bf5277c720
696 X-Mercurial-Node: 4d6f44f466c96d89f2e7e865a70ff41d8b6eee37
694 X-Mercurial-Series-Index: 1
697 X-Mercurial-Series-Index: 1
695 X-Mercurial-Series-Total: 1
698 X-Mercurial-Series-Total: 1
696 Message-Id: <240fb913fc1b7ff15ddb.300@test-hostname>
699 Message-Id: <4d6f44f466c96d89f2e7.300@test-hostname>
697 X-Mercurial-Series-Id: <240fb913fc1b7ff15ddb.300@test-hostname>
700 X-Mercurial-Series-Id: <4d6f44f466c96d89f2e7.300@test-hostname>
698 User-Agent: Mercurial-patchbomb/* (glob)
701 User-Agent: Mercurial-patchbomb/* (glob)
699 Date: Thu, 01 Jan 1970 00:05:00 +0000
702 Date: Thu, 01 Jan 1970 00:05:00 +0000
700 From: quux
703 From: quux
@@ -705,11 +708,11 b' iso-8859-1 mbox:'
705 # User test
708 # User test
706 # Date 5 0
709 # Date 5 0
707 # Thu Jan 01 00:00:05 1970 +0000
710 # Thu Jan 01 00:00:05 1970 +0000
708 # Node ID 240fb913fc1b7ff15ddb9f33e73d82bf5277c720
711 # Node ID 4d6f44f466c96d89f2e7e865a70ff41d8b6eee37
709 # Parent a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
712 # Parent 0c7b871cb86b61a1c07e244393603c361e4a178d
710 isolatin 8-bit encoding
713 isolatin 8-bit encoding
711
714
712 diff -r a2ea8fc83dd8 -r 240fb913fc1b isolatin
715 diff -r 0c7b871cb86b -r 4d6f44f466c9 isolatin
713 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
716 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
714 +++ b/isolatin Thu Jan 01 00:00:05 1970 +0000
717 +++ b/isolatin Thu Jan 01 00:00:05 1970 +0000
715 @@ -0,0 +1,1 @@
718 @@ -0,0 +1,1 @@
@@ -937,11 +940,11 b' test inline for single patch (quoted-pri'
937 Content-Type: multipart/mixed; boundary="===*==" (glob)
940 Content-Type: multipart/mixed; boundary="===*==" (glob)
938 MIME-Version: 1.0
941 MIME-Version: 1.0
939 Subject: [PATCH] test
942 Subject: [PATCH] test
940 X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
943 X-Mercurial-Node: 0c7b871cb86b61a1c07e244393603c361e4a178d
941 X-Mercurial-Series-Index: 1
944 X-Mercurial-Series-Index: 1
942 X-Mercurial-Series-Total: 1
945 X-Mercurial-Series-Total: 1
943 Message-Id: <a2ea8fc83dd8b93cfd86.60@test-hostname>
946 Message-Id: <0c7b871cb86b61a1c07e.60@test-hostname>
944 X-Mercurial-Series-Id: <a2ea8fc83dd8b93cfd86.60@test-hostname>
947 X-Mercurial-Series-Id: <0c7b871cb86b61a1c07e.60@test-hostname>
945 User-Agent: Mercurial-patchbomb/* (glob)
948 User-Agent: Mercurial-patchbomb/* (glob)
946 Date: Thu, 01 Jan 1970 00:01:00 +0000
949 Date: Thu, 01 Jan 1970 00:01:00 +0000
947 From: quux
950 From: quux
@@ -958,11 +961,11 b' test inline for single patch (quoted-pri'
958 # User test
961 # User test
959 # Date 4 0
962 # Date 4 0
960 # Thu Jan 01 00:00:04 1970 +0000
963 # Thu Jan 01 00:00:04 1970 +0000
961 # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
964 # Node ID 0c7b871cb86b61a1c07e244393603c361e4a178d
962 # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
965 # Parent f81ef97829467e868fc405fccbcfa66217e4d3e6
963 long line
966 long line
964
967
965 diff -r 909a00e13e9d -r a2ea8fc83dd8 long
968 diff -r f81ef9782946 -r 0c7b871cb86b long
966 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
969 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
967 +++ b/long Thu Jan 01 00:00:04 1970 +0000
970 +++ b/long Thu Jan 01 00:00:04 1970 +0000
968 @@ -0,0 +1,4 @@
971 @@ -0,0 +1,4 @@
@@ -1088,10 +1091,10 b' test inline for multiple patches:'
1088 Content-Type: multipart/mixed; boundary="===*==" (glob)
1091 Content-Type: multipart/mixed; boundary="===*==" (glob)
1089 MIME-Version: 1.0
1092 MIME-Version: 1.0
1090 Subject: [PATCH 3 of 3] long line
1093 Subject: [PATCH 3 of 3] long line
1091 X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
1094 X-Mercurial-Node: 0c7b871cb86b61a1c07e244393603c361e4a178d
1092 X-Mercurial-Series-Index: 3
1095 X-Mercurial-Series-Index: 3
1093 X-Mercurial-Series-Total: 3
1096 X-Mercurial-Series-Total: 3
1094 Message-Id: <a2ea8fc83dd8b93cfd86.63@test-hostname>
1097 Message-Id: <0c7b871cb86b61a1c07e.63@test-hostname>
1095 X-Mercurial-Series-Id: <8580ff50825a50c8f716.61@test-hostname>
1098 X-Mercurial-Series-Id: <8580ff50825a50c8f716.61@test-hostname>
1096 In-Reply-To: <patchbomb.60@test-hostname>
1099 In-Reply-To: <patchbomb.60@test-hostname>
1097 References: <patchbomb.60@test-hostname>
1100 References: <patchbomb.60@test-hostname>
@@ -1111,11 +1114,11 b' test inline for multiple patches:'
1111 # User test
1114 # User test
1112 # Date 4 0
1115 # Date 4 0
1113 # Thu Jan 01 00:00:04 1970 +0000
1116 # Thu Jan 01 00:00:04 1970 +0000
1114 # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
1117 # Node ID 0c7b871cb86b61a1c07e244393603c361e4a178d
1115 # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
1118 # Parent f81ef97829467e868fc405fccbcfa66217e4d3e6
1116 long line
1119 long line
1117
1120
1118 diff -r 909a00e13e9d -r a2ea8fc83dd8 long
1121 diff -r f81ef9782946 -r 0c7b871cb86b long
1119 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1122 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1120 +++ b/long Thu Jan 01 00:00:04 1970 +0000
1123 +++ b/long Thu Jan 01 00:00:04 1970 +0000
1121 @@ -0,0 +1,4 @@
1124 @@ -0,0 +1,4 @@
@@ -1199,11 +1202,11 b' test attach for single patch (quoted-pri'
1199 Content-Type: multipart/mixed; boundary="===*==" (glob)
1202 Content-Type: multipart/mixed; boundary="===*==" (glob)
1200 MIME-Version: 1.0
1203 MIME-Version: 1.0
1201 Subject: [PATCH] test
1204 Subject: [PATCH] test
1202 X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
1205 X-Mercurial-Node: 0c7b871cb86b61a1c07e244393603c361e4a178d
1203 X-Mercurial-Series-Index: 1
1206 X-Mercurial-Series-Index: 1
1204 X-Mercurial-Series-Total: 1
1207 X-Mercurial-Series-Total: 1
1205 Message-Id: <a2ea8fc83dd8b93cfd86.60@test-hostname>
1208 Message-Id: <0c7b871cb86b61a1c07e.60@test-hostname>
1206 X-Mercurial-Series-Id: <a2ea8fc83dd8b93cfd86.60@test-hostname>
1209 X-Mercurial-Series-Id: <0c7b871cb86b61a1c07e.60@test-hostname>
1207 User-Agent: Mercurial-patchbomb/* (glob)
1210 User-Agent: Mercurial-patchbomb/* (glob)
1208 Date: Thu, 01 Jan 1970 00:01:00 +0000
1211 Date: Thu, 01 Jan 1970 00:01:00 +0000
1209 From: quux
1212 From: quux
@@ -1229,11 +1232,11 b' test attach for single patch (quoted-pri'
1229 # User test
1232 # User test
1230 # Date 4 0
1233 # Date 4 0
1231 # Thu Jan 01 00:00:04 1970 +0000
1234 # Thu Jan 01 00:00:04 1970 +0000
1232 # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
1235 # Node ID 0c7b871cb86b61a1c07e244393603c361e4a178d
1233 # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
1236 # Parent f81ef97829467e868fc405fccbcfa66217e4d3e6
1234 long line
1237 long line
1235
1238
1236 diff -r 909a00e13e9d -r a2ea8fc83dd8 long
1239 diff -r f81ef9782946 -r 0c7b871cb86b long
1237 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1240 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1238 +++ b/long Thu Jan 01 00:00:04 1970 +0000
1241 +++ b/long Thu Jan 01 00:00:04 1970 +0000
1239 @@ -0,0 +1,4 @@
1242 @@ -0,0 +1,4 @@
@@ -1438,10 +1441,10 b' test attach for multiple patches:'
1438 Content-Type: multipart/mixed; boundary="===*==" (glob)
1441 Content-Type: multipart/mixed; boundary="===*==" (glob)
1439 MIME-Version: 1.0
1442 MIME-Version: 1.0
1440 Subject: [PATCH 3 of 3] long line
1443 Subject: [PATCH 3 of 3] long line
1441 X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
1444 X-Mercurial-Node: 0c7b871cb86b61a1c07e244393603c361e4a178d
1442 X-Mercurial-Series-Index: 3
1445 X-Mercurial-Series-Index: 3
1443 X-Mercurial-Series-Total: 3
1446 X-Mercurial-Series-Total: 3
1444 Message-Id: <a2ea8fc83dd8b93cfd86.63@test-hostname>
1447 Message-Id: <0c7b871cb86b61a1c07e.63@test-hostname>
1445 X-Mercurial-Series-Id: <8580ff50825a50c8f716.61@test-hostname>
1448 X-Mercurial-Series-Id: <8580ff50825a50c8f716.61@test-hostname>
1446 In-Reply-To: <patchbomb.60@test-hostname>
1449 In-Reply-To: <patchbomb.60@test-hostname>
1447 References: <patchbomb.60@test-hostname>
1450 References: <patchbomb.60@test-hostname>
@@ -1470,11 +1473,11 b' test attach for multiple patches:'
1470 # User test
1473 # User test
1471 # Date 4 0
1474 # Date 4 0
1472 # Thu Jan 01 00:00:04 1970 +0000
1475 # Thu Jan 01 00:00:04 1970 +0000
1473 # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
1476 # Node ID 0c7b871cb86b61a1c07e244393603c361e4a178d
1474 # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
1477 # Parent f81ef97829467e868fc405fccbcfa66217e4d3e6
1475 long line
1478 long line
1476
1479
1477 diff -r 909a00e13e9d -r a2ea8fc83dd8 long
1480 diff -r f81ef9782946 -r 0c7b871cb86b long
1478 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1481 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1479 +++ b/long Thu Jan 01 00:00:04 1970 +0000
1482 +++ b/long Thu Jan 01 00:00:04 1970 +0000
1480 @@ -0,0 +1,4 @@
1483 @@ -0,0 +1,4 @@
@@ -1929,11 +1932,11 b' test inreplyto:'
1929 Content-Type: text/plain; charset="us-ascii"
1932 Content-Type: text/plain; charset="us-ascii"
1930 Content-Transfer-Encoding: 7bit
1933 Content-Transfer-Encoding: 7bit
1931 Subject: [PATCH] Added tag two, two.diff for changeset ff2c9fa2018b
1934 Subject: [PATCH] Added tag two, two.diff for changeset ff2c9fa2018b
1932 X-Mercurial-Node: 7aead2484924c445ad8ce2613df91f52f9e502ed
1935 X-Mercurial-Node: 9cea7492c36bdda2c72e7dd5f35f7fc367adeb2c
1933 X-Mercurial-Series-Index: 1
1936 X-Mercurial-Series-Index: 1
1934 X-Mercurial-Series-Total: 1
1937 X-Mercurial-Series-Total: 1
1935 Message-Id: <7aead2484924c445ad8c.60@test-hostname>
1938 Message-Id: <9cea7492c36bdda2c72e.60@test-hostname>
1936 X-Mercurial-Series-Id: <7aead2484924c445ad8c.60@test-hostname>
1939 X-Mercurial-Series-Id: <9cea7492c36bdda2c72e.60@test-hostname>
1937 In-Reply-To: <baz>
1940 In-Reply-To: <baz>
1938 References: <baz>
1941 References: <baz>
1939 User-Agent: Mercurial-patchbomb/* (glob)
1942 User-Agent: Mercurial-patchbomb/* (glob)
@@ -1946,11 +1949,11 b' test inreplyto:'
1946 # User test
1949 # User test
1947 # Date 0 0
1950 # Date 0 0
1948 # Thu Jan 01 00:00:00 1970 +0000
1951 # Thu Jan 01 00:00:00 1970 +0000
1949 # Node ID 7aead2484924c445ad8ce2613df91f52f9e502ed
1952 # Node ID 9cea7492c36bdda2c72e7dd5f35f7fc367adeb2c
1950 # Parent 045ca29b1ea20e4940411e695e20e521f2f0f98e
1953 # Parent 3b775b32716d9b54291ccddf0a36ceea45449bfb
1951 Added tag two, two.diff for changeset ff2c9fa2018b
1954 Added tag two, two.diff for changeset ff2c9fa2018b
1952
1955
1953 diff -r 045ca29b1ea2 -r 7aead2484924 .hgtags
1956 diff -r 3b775b32716d -r 9cea7492c36b .hgtags
1954 --- a/.hgtags Thu Jan 01 00:00:00 1970 +0000
1957 --- a/.hgtags Thu Jan 01 00:00:00 1970 +0000
1955 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1958 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1956 @@ -2,3 +2,5 @@
1959 @@ -2,3 +2,5 @@
@@ -2397,9 +2400,12 b' test multi-address parsing:'
2397 User-Agent: Mercurial-patchbomb/* (glob)
2400 User-Agent: Mercurial-patchbomb/* (glob)
2398 Date: Tue, 01 Jan 1980 00:01:00 +0000
2401 Date: Tue, 01 Jan 1980 00:01:00 +0000
2399 From: quux
2402 From: quux
2400 To: spam <spam>, eggs, toast
2403 To: spam <spam>, eggs, toast (no-py3 !)
2401 Cc: foo, bar@example.com, "A, B <>" <a@example.com>
2404 Cc: foo, bar@example.com, "A, B <>" <a@example.com> (no-py3 !)
2402 Bcc: "Quux, A." <quux>
2405 Bcc: "Quux, A." <quux> (no-py3 !)
2406 To: =?iso-8859-1?q?spam?= <spam>, eggs, toast (py3 !)
2407 Cc: foo, bar@example.com, =?iso-8859-1?q?A=2C_B_=3C=3E?= <a@example.com> (py3 !)
2408 Bcc: =?iso-8859-1?q?Quux=2C_A=2E?= <quux> (py3 !)
2403
2409
2404 # HG changeset patch
2410 # HG changeset patch
2405 # User test
2411 # User test
@@ -2601,17 +2607,17 b' test outgoing:'
2601 |
2607 |
2602 o 9:2f9fa9b998c5 d
2608 o 9:2f9fa9b998c5 d
2603 |
2609 |
2604 | o 8:7aead2484924 Added tag two, two.diff for changeset ff2c9fa2018b
2610 | o 8:9cea7492c36b Added tag two, two.diff for changeset ff2c9fa2018b
2605 | |
2611 | |
2606 | o 7:045ca29b1ea2 Added tag one, one.patch for changeset 97d72e5f12c7
2612 | o 7:3b775b32716d Added tag one, one.patch for changeset 97d72e5f12c7
2607 | |
2613 | |
2608 | o 6:5d5ef15dfe5e Added tag zero, zero.foo for changeset 8580ff50825a
2614 | o 6:c41d7353114c Added tag zero, zero.foo for changeset 8580ff50825a
2609 | |
2615 | |
2610 | o 5:240fb913fc1b isolatin 8-bit encoding
2616 | o 5:4d6f44f466c9 isolatin 8-bit encoding
2611 | |
2617 | |
2612 | o 4:a2ea8fc83dd8 long line
2618 | o 4:0c7b871cb86b long line
2613 | |
2619 | |
2614 | o 3:909a00e13e9d utf-8 content
2620 | o 3:f81ef9782946 \xe7a (esc)
2615 | |
2621 | |
2616 | o 2:ff2c9fa2018b c
2622 | o 2:ff2c9fa2018b c
2617 |/
2623 |/
@@ -2673,15 +2679,16 b' test outgoing:'
2673 @@ -0,0 +1,1 @@
2679 @@ -0,0 +1,1 @@
2674 +c
2680 +c
2675
2681
2676 displaying [PATCH 2 of 6] utf-8 content ...
2682 displaying [PATCH 2 of 6] \xe7a ... (esc)
2677 MIME-Version: 1.0
2683 MIME-Version: 1.0
2678 Content-Type: text/plain; charset="iso-8859-1"
2684 Content-Type: text/plain; charset="iso-8859-1"
2679 Content-Transfer-Encoding: quoted-printable
2685 Content-Transfer-Encoding: quoted-printable
2680 Subject: [PATCH 2 of 6] utf-8 content
2686 Subject: [PATCH 2 of 6] \xe7a (esc) (no-py3 !)
2681 X-Mercurial-Node: 909a00e13e9d78b575aeee23dddbada46d5a143f
2687 Subject: =?utf-8?b?W1BBVENIIDIgb2YgNl0gw6dh?= (py3 !)
2688 X-Mercurial-Node: f81ef97829467e868fc405fccbcfa66217e4d3e6
2682 X-Mercurial-Series-Index: 2
2689 X-Mercurial-Series-Index: 2
2683 X-Mercurial-Series-Total: 6
2690 X-Mercurial-Series-Total: 6
2684 Message-Id: <909a00e13e9d78b575ae.315532862@test-hostname>
2691 Message-Id: <f81ef97829467e868fc4.315532862@test-hostname>
2685 X-Mercurial-Series-Id: <ff2c9fa2018b15fa74b3.315532861@test-hostname>
2692 X-Mercurial-Series-Id: <ff2c9fa2018b15fa74b3.315532861@test-hostname>
2686 In-Reply-To: <patchbomb.315532860@test-hostname>
2693 In-Reply-To: <patchbomb.315532860@test-hostname>
2687 References: <patchbomb.315532860@test-hostname>
2694 References: <patchbomb.315532860@test-hostname>
@@ -2694,18 +2701,18 b' test outgoing:'
2694 # User test
2701 # User test
2695 # Date 4 0
2702 # Date 4 0
2696 # Thu Jan 01 00:00:04 1970 +0000
2703 # Thu Jan 01 00:00:04 1970 +0000
2697 # Node ID 909a00e13e9d78b575aeee23dddbada46d5a143f
2704 # Node ID f81ef97829467e868fc405fccbcfa66217e4d3e6
2698 # Parent ff2c9fa2018b15fa74b33363bda9527323e2a99f
2705 # Parent ff2c9fa2018b15fa74b33363bda9527323e2a99f
2699 utf-8 content
2706 =E7a
2700
2707
2701 diff -r ff2c9fa2018b -r 909a00e13e9d description
2708 diff -r ff2c9fa2018b -r f81ef9782946 description
2702 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2709 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2703 +++ b/description Thu Jan 01 00:00:04 1970 +0000
2710 +++ b/description Thu Jan 01 00:00:04 1970 +0000
2704 @@ -0,0 +1,3 @@
2711 @@ -0,0 +1,3 @@
2705 +a multiline
2712 +a multiline
2706 +
2713 +
2707 +description
2714 +description
2708 diff -r ff2c9fa2018b -r 909a00e13e9d utf
2715 diff -r ff2c9fa2018b -r f81ef9782946 utf
2709 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2716 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2710 +++ b/utf Thu Jan 01 00:00:04 1970 +0000
2717 +++ b/utf Thu Jan 01 00:00:04 1970 +0000
2711 @@ -0,0 +1,1 @@
2718 @@ -0,0 +1,1 @@
@@ -2716,10 +2723,10 b' test outgoing:'
2716 Content-Type: text/plain; charset="us-ascii"
2723 Content-Type: text/plain; charset="us-ascii"
2717 Content-Transfer-Encoding: quoted-printable
2724 Content-Transfer-Encoding: quoted-printable
2718 Subject: [PATCH 3 of 6] long line
2725 Subject: [PATCH 3 of 6] long line
2719 X-Mercurial-Node: a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
2726 X-Mercurial-Node: 0c7b871cb86b61a1c07e244393603c361e4a178d
2720 X-Mercurial-Series-Index: 3
2727 X-Mercurial-Series-Index: 3
2721 X-Mercurial-Series-Total: 6
2728 X-Mercurial-Series-Total: 6
2722 Message-Id: <a2ea8fc83dd8b93cfd86.315532863@test-hostname>
2729 Message-Id: <0c7b871cb86b61a1c07e.315532863@test-hostname>
2723 X-Mercurial-Series-Id: <ff2c9fa2018b15fa74b3.315532861@test-hostname>
2730 X-Mercurial-Series-Id: <ff2c9fa2018b15fa74b3.315532861@test-hostname>
2724 In-Reply-To: <patchbomb.315532860@test-hostname>
2731 In-Reply-To: <patchbomb.315532860@test-hostname>
2725 References: <patchbomb.315532860@test-hostname>
2732 References: <patchbomb.315532860@test-hostname>
@@ -2732,11 +2739,11 b' test outgoing:'
2732 # User test
2739 # User test
2733 # Date 4 0
2740 # Date 4 0
2734 # Thu Jan 01 00:00:04 1970 +0000
2741 # Thu Jan 01 00:00:04 1970 +0000
2735 # Node ID a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
2742 # Node ID 0c7b871cb86b61a1c07e244393603c361e4a178d
2736 # Parent 909a00e13e9d78b575aeee23dddbada46d5a143f
2743 # Parent f81ef97829467e868fc405fccbcfa66217e4d3e6
2737 long line
2744 long line
2738
2745
2739 diff -r 909a00e13e9d -r a2ea8fc83dd8 long
2746 diff -r f81ef9782946 -r 0c7b871cb86b long
2740 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2747 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2741 +++ b/long Thu Jan 01 00:00:04 1970 +0000
2748 +++ b/long Thu Jan 01 00:00:04 1970 +0000
2742 @@ -0,0 +1,4 @@
2749 @@ -0,0 +1,4 @@
@@ -2763,10 +2770,10 b' test outgoing:'
2763 Content-Type: text/plain; charset="iso-8859-1"
2770 Content-Type: text/plain; charset="iso-8859-1"
2764 Content-Transfer-Encoding: quoted-printable
2771 Content-Transfer-Encoding: quoted-printable
2765 Subject: [PATCH 4 of 6] isolatin 8-bit encoding
2772 Subject: [PATCH 4 of 6] isolatin 8-bit encoding
2766 X-Mercurial-Node: 240fb913fc1b7ff15ddb9f33e73d82bf5277c720
2773 X-Mercurial-Node: 4d6f44f466c96d89f2e7e865a70ff41d8b6eee37
2767 X-Mercurial-Series-Index: 4
2774 X-Mercurial-Series-Index: 4
2768 X-Mercurial-Series-Total: 6
2775 X-Mercurial-Series-Total: 6
2769 Message-Id: <240fb913fc1b7ff15ddb.315532864@test-hostname>
2776 Message-Id: <4d6f44f466c96d89f2e7.315532864@test-hostname>
2770 X-Mercurial-Series-Id: <ff2c9fa2018b15fa74b3.315532861@test-hostname>
2777 X-Mercurial-Series-Id: <ff2c9fa2018b15fa74b3.315532861@test-hostname>
2771 In-Reply-To: <patchbomb.315532860@test-hostname>
2778 In-Reply-To: <patchbomb.315532860@test-hostname>
2772 References: <patchbomb.315532860@test-hostname>
2779 References: <patchbomb.315532860@test-hostname>
@@ -2779,11 +2786,11 b' test outgoing:'
2779 # User test
2786 # User test
2780 # Date 5 0
2787 # Date 5 0
2781 # Thu Jan 01 00:00:05 1970 +0000
2788 # Thu Jan 01 00:00:05 1970 +0000
2782 # Node ID 240fb913fc1b7ff15ddb9f33e73d82bf5277c720
2789 # Node ID 4d6f44f466c96d89f2e7e865a70ff41d8b6eee37
2783 # Parent a2ea8fc83dd8b93cfd86ac97b28287204ab806e1
2790 # Parent 0c7b871cb86b61a1c07e244393603c361e4a178d
2784 isolatin 8-bit encoding
2791 isolatin 8-bit encoding
2785
2792
2786 diff -r a2ea8fc83dd8 -r 240fb913fc1b isolatin
2793 diff -r 0c7b871cb86b -r 4d6f44f466c9 isolatin
2787 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2794 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2788 +++ b/isolatin Thu Jan 01 00:00:05 1970 +0000
2795 +++ b/isolatin Thu Jan 01 00:00:05 1970 +0000
2789 @@ -0,0 +1,1 @@
2796 @@ -0,0 +1,1 @@
@@ -2794,10 +2801,10 b' test outgoing:'
2794 Content-Type: text/plain; charset="us-ascii"
2801 Content-Type: text/plain; charset="us-ascii"
2795 Content-Transfer-Encoding: 7bit
2802 Content-Transfer-Encoding: 7bit
2796 Subject: [PATCH 5 of 6] Added tag zero, zero.foo for changeset 8580ff50825a
2803 Subject: [PATCH 5 of 6] Added tag zero, zero.foo for changeset 8580ff50825a
2797 X-Mercurial-Node: 5d5ef15dfe5e7bd3a4ee154b5fff76c7945ec433
2804 X-Mercurial-Node: c41d7353114ccb07a50a822ad5ddf47051c88ec2
2798 X-Mercurial-Series-Index: 5
2805 X-Mercurial-Series-Index: 5
2799 X-Mercurial-Series-Total: 6
2806 X-Mercurial-Series-Total: 6
2800 Message-Id: <5d5ef15dfe5e7bd3a4ee.315532865@test-hostname>
2807 Message-Id: <c41d7353114ccb07a50a.315532865@test-hostname>
2801 X-Mercurial-Series-Id: <ff2c9fa2018b15fa74b3.315532861@test-hostname>
2808 X-Mercurial-Series-Id: <ff2c9fa2018b15fa74b3.315532861@test-hostname>
2802 In-Reply-To: <patchbomb.315532860@test-hostname>
2809 In-Reply-To: <patchbomb.315532860@test-hostname>
2803 References: <patchbomb.315532860@test-hostname>
2810 References: <patchbomb.315532860@test-hostname>
@@ -2810,11 +2817,11 b' test outgoing:'
2810 # User test
2817 # User test
2811 # Date 0 0
2818 # Date 0 0
2812 # Thu Jan 01 00:00:00 1970 +0000
2819 # Thu Jan 01 00:00:00 1970 +0000
2813 # Node ID 5d5ef15dfe5e7bd3a4ee154b5fff76c7945ec433
2820 # Node ID c41d7353114ccb07a50a822ad5ddf47051c88ec2
2814 # Parent 240fb913fc1b7ff15ddb9f33e73d82bf5277c720
2821 # Parent 4d6f44f466c96d89f2e7e865a70ff41d8b6eee37
2815 Added tag zero, zero.foo for changeset 8580ff50825a
2822 Added tag zero, zero.foo for changeset 8580ff50825a
2816
2823
2817 diff -r 240fb913fc1b -r 5d5ef15dfe5e .hgtags
2824 diff -r 4d6f44f466c9 -r c41d7353114c .hgtags
2818 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2825 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2819 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2826 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
2820 @@ -0,0 +1,2 @@
2827 @@ -0,0 +1,2 @@
@@ -85,7 +85,7 b' Known exception should be caught, but pr'
85 $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=8' \
85 $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=8' \
86 > test 100000.0 abort --traceback 2>&1 | egrep '(SystemExit|Abort)'
86 > test 100000.0 abort --traceback 2>&1 | egrep '(SystemExit|Abort)'
87 raise error.Abort(b'known exception')
87 raise error.Abort(b'known exception')
88 mercurial.error.Abort: b'known exception' (py3 !)
88 mercurial.error.Abort: known exception (py3 !)
89 Abort: known exception (no-py3 !)
89 Abort: known exception (no-py3 !)
90 SystemExit: 255
90 SystemExit: 255
91
91
1 NO CONTENT: file was removed
NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (4094 lines changed) Show them Hide them
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now