##// END OF EJS Templates
branching: merge stable into default
Raphaël Gomès -
r51829:6408777c merge default
parent child Browse files
Show More
@@ -1,251 +1,252 b''
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
79 335a558f81dc73afeab4d7be63617392b130117f 0 iQIVAwUAUiZrIyBXgaxoKi1yAQK2iw//cquNqqSkc8Re5/TZT9I6NH+lh6DbOKjJP0Xl1Wqq0K+KSIUgZG4G32ovaEb2l5X0uY+3unRPiZ0ebl0YSw4Fb2ZiPIADXLBTOYRrY2Wwd3tpJeGI6wEgZt3SfcITV/g7NJrCjT3FlYoSOIayrExM80InSdcEM0Q3Rx6HKzY2acyxzgZeAtAW5ohFvHilSvY6p5Gcm4+QptMxvw45GPdreUmjeXZxNXNXZ8P+MjMz/QJbai/N7PjmK8lqnhkBsT48Ng/KhhmOkGntNJ2/ImBWLFGcWngSvJ7sfWwnyhndvGhe0Hq1NcCf7I8TjNDxU5TR+m+uW7xjXdLoDbUjBdX4sKXnh8ZjbYiODKBOrrDq25cf8nA/tnpKyE/qsVy60kOk6loY4XKiYmn1V49Ta0emmDx0hqo3HgxHHsHX0NDnGdWGol7cPRET0RzVobKq1A0jnrhPooWidvLh9bPzLonrWDo+ib+DuySoRkuYUK4pgZJ2mbg6daFOBEZygkSyRB8bo1UQUP7EgQDrWe4khb/5GHEfDkrQz3qu/sXvc0Ir1mOUWBFPHC2DjjCn/oMJuUkG1SwM8l2Bfv7h67ssES6YQ2+RjOix4yid7EXS/Ogl45PzCIPSI5+BbNs10JhE0w5uErBHlF53EDTe/TSLc+GU6DB6PP6dH912Njdr3jpNSUQ=
79 335a558f81dc73afeab4d7be63617392b130117f 0 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
@@ -1,267 +1,268 b''
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
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
201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
208 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1
208 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1
209 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2
209 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2
210 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0
210 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0
211 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4
211 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4
212 065704cbdbdbb05dcd6bb814eb9bbdd982211b28 5.4.1
212 065704cbdbdbb05dcd6bb814eb9bbdd982211b28 5.4.1
213 0ea9c86fac8974cd74dc12ea681c8986eb6da6c4 5.4.2
213 0ea9c86fac8974cd74dc12ea681c8986eb6da6c4 5.4.2
214 28163c5de797e5416f9b588940f4608269b4d50a 5.5rc0
214 28163c5de797e5416f9b588940f4608269b4d50a 5.5rc0
215 7fc3c5fbc65f6fe85d70ea63923b8767dda4f2e0 5.5
215 7fc3c5fbc65f6fe85d70ea63923b8767dda4f2e0 5.5
216 f62bb5d07848ca598aa860a517394130b61bf2ee 5.5.1
216 f62bb5d07848ca598aa860a517394130b61bf2ee 5.5.1
217 07731064ac41dacdf0ec869ebd05c2e848c14fbf 5.5.2
217 07731064ac41dacdf0ec869ebd05c2e848c14fbf 5.5.2
218 0e06a7ab9e0d5c65af4e511aee1e0342998799df 5.6rc0
218 0e06a7ab9e0d5c65af4e511aee1e0342998799df 5.6rc0
219 18c17d63fdabd009e70bf994e5efb7db422f4f7f 5.6
219 18c17d63fdabd009e70bf994e5efb7db422f4f7f 5.6
220 1d5189a57405ceca5aa244052c9f948977f4699b 5.6.1
220 1d5189a57405ceca5aa244052c9f948977f4699b 5.6.1
221 9da65e3cf3706ff41e08b311381c588440c27baf 5.7rc0
221 9da65e3cf3706ff41e08b311381c588440c27baf 5.7rc0
222 0e2e7300f4302b02412b0b734717697049494c4c 5.7
222 0e2e7300f4302b02412b0b734717697049494c4c 5.7
223 d5d9177c0045d206db575bae6daa98e2cb2fe5bc 5.7.1
223 d5d9177c0045d206db575bae6daa98e2cb2fe5bc 5.7.1
224 f67b8946bb1b6cfa8328dbf8d6a9128b69ccdcb4 5.8rc0
224 f67b8946bb1b6cfa8328dbf8d6a9128b69ccdcb4 5.8rc0
225 8d2b62d716b095507effaa8d56f87cd27ba659ab 5.8rc1
225 8d2b62d716b095507effaa8d56f87cd27ba659ab 5.8rc1
226 067f2c53fb24506c9e9fb4639871b13b19a85f8a 5.8
226 067f2c53fb24506c9e9fb4639871b13b19a85f8a 5.8
227 411dc27fd9fd076d6a031a08fcaace659afe2fe3 5.8.1
227 411dc27fd9fd076d6a031a08fcaace659afe2fe3 5.8.1
228 d7515d29761d5ada7d9c765f517db67db75dea9a 5.9rc0
228 d7515d29761d5ada7d9c765f517db67db75dea9a 5.9rc0
229 2813d406b03607cdb8c06cb04c44efcc9a79d9a2 5.9rc1
229 2813d406b03607cdb8c06cb04c44efcc9a79d9a2 5.9rc1
230 53221078e0de65d1a821ce5311dec45a7a978301 5.9
230 53221078e0de65d1a821ce5311dec45a7a978301 5.9
231 86a60679cf619e14cee9442f865fcf31b142cb9f 5.9.1
231 86a60679cf619e14cee9442f865fcf31b142cb9f 5.9.1
232 750920b18aaaddd654756be40dec59d90f2643be 5.9.2
232 750920b18aaaddd654756be40dec59d90f2643be 5.9.2
233 6ee0244fc1cf889ae543d2ce0ec45201ae0be6e1 5.9.3
233 6ee0244fc1cf889ae543d2ce0ec45201ae0be6e1 5.9.3
234 a44bb185f6bdbecc754996d8386722e2f0123b0a 6.0rc0
234 a44bb185f6bdbecc754996d8386722e2f0123b0a 6.0rc0
235 5d08b289e2e526259d7d5ea32b70fe76d5b327d7 6.0
235 5d08b289e2e526259d7d5ea32b70fe76d5b327d7 6.0
236 799fdf4cca80cb9ae40537a90995e6bd163ebc0b 6.0.1
236 799fdf4cca80cb9ae40537a90995e6bd163ebc0b 6.0.1
237 75676122c2bf7594ac732b7388db4c74c648b365 6.0.2
237 75676122c2bf7594ac732b7388db4c74c648b365 6.0.2
238 dcec16e799ddb6d33fcd11b04af530250a417a58 6.0.3
238 dcec16e799ddb6d33fcd11b04af530250a417a58 6.0.3
239 c00d3ce4e94bb0ee8d809e25e1dcb2a5fab84e2c 6.1rc0
239 c00d3ce4e94bb0ee8d809e25e1dcb2a5fab84e2c 6.1rc0
240 d4486810a1795fba9521449b8885ced034f3a6dd 6.1
240 d4486810a1795fba9521449b8885ced034f3a6dd 6.1
241 5bd6bcd31dd1ebb63b8914b00064f96297267af7 6.1.1
241 5bd6bcd31dd1ebb63b8914b00064f96297267af7 6.1.1
242 0ddd5e1f5f67438af85d12e4ce6c39021dde9916 6.1.2
242 0ddd5e1f5f67438af85d12e4ce6c39021dde9916 6.1.2
243 6b10151b962108f65bfa12b3918b1021ca334f73 6.1.3
243 6b10151b962108f65bfa12b3918b1021ca334f73 6.1.3
244 0cc5f74ff7f0f4ac2427096bddbe102dbc2453ae 6.1.4
244 0cc5f74ff7f0f4ac2427096bddbe102dbc2453ae 6.1.4
245 288de6f5d724bba7bf1669e2838f196962bb7528 6.2rc0
245 288de6f5d724bba7bf1669e2838f196962bb7528 6.2rc0
246 094a5fa3cf52f936e0de3f1e507c818bee5ece6b 6.2
246 094a5fa3cf52f936e0de3f1e507c818bee5ece6b 6.2
247 f69bffd00abe3a1b94d1032eb2c92e611d16a192 6.2.1
247 f69bffd00abe3a1b94d1032eb2c92e611d16a192 6.2.1
248 b5c8524827d20fe2e0ca8fb1234a0fe35a1a36c7 6.2.2
248 b5c8524827d20fe2e0ca8fb1234a0fe35a1a36c7 6.2.2
249 dbdee8ac3e3fcdda1fa55b90c0a235125b7f8e6f 6.2.3
249 dbdee8ac3e3fcdda1fa55b90c0a235125b7f8e6f 6.2.3
250 a3356ab610fc50000cf0ba55c424a4d96da11db7 6.3rc0
250 a3356ab610fc50000cf0ba55c424a4d96da11db7 6.3rc0
251 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
251 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
252 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3
252 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3
253 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
253 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
254 0000000000000000000000000000000000000000 6.3.0
254 0000000000000000000000000000000000000000 6.3.0
255 c890d8b8bc59b18e5febf60caada629df5356ee2 6.3.1
255 c890d8b8bc59b18e5febf60caada629df5356ee2 6.3.1
256 59466b13a3ae0e29a5d4f485393e516cfbb057d0 6.3.2
256 59466b13a3ae0e29a5d4f485393e516cfbb057d0 6.3.2
257 8830004967ad865ead89c28a410405a6e71e0796 6.3.3
257 8830004967ad865ead89c28a410405a6e71e0796 6.3.3
258 05de4896508e8ec387b33eb30d8aab78d1c8e9e4 6.4rc0
258 05de4896508e8ec387b33eb30d8aab78d1c8e9e4 6.4rc0
259 f14864fffdcab725d9eac6d4f4c07be05a35f59a 6.4
259 f14864fffdcab725d9eac6d4f4c07be05a35f59a 6.4
260 83ea6ce48b4fd09fb79c4e34cc5750c805699a53 6.4.1
260 83ea6ce48b4fd09fb79c4e34cc5750c805699a53 6.4.1
261 f952be90b0514a576dcc8bbe758ce3847faba9bb 6.4.2
261 f952be90b0514a576dcc8bbe758ce3847faba9bb 6.4.2
262 fc445f8abcf90b33db7c463816a1b3560681767f 6.4.3
262 fc445f8abcf90b33db7c463816a1b3560681767f 6.4.3
263 da372c745e0f053bb7a64e74cccd15810d96341d 6.4.4
263 da372c745e0f053bb7a64e74cccd15810d96341d 6.4.4
264 271a4ab29605ffa0bae5d3208eaa21a95427ff92 6.4.5
264 271a4ab29605ffa0bae5d3208eaa21a95427ff92 6.4.5
265 bb42988c7e156931b0ff1e93732b98173ebbcb7f 6.5rc0
265 bb42988c7e156931b0ff1e93732b98173ebbcb7f 6.5rc0
266 3ffc7209bbae5804a53084c9dc2d41139e88c867 6.5
266 3ffc7209bbae5804a53084c9dc2d41139e88c867 6.5
267 787af4e0e8b787e1b77a8059926b123730a4cd01 6.5.1
267 787af4e0e8b787e1b77a8059926b123730a4cd01 6.5.1
268 5a8b5420103937fca97c584c5162178eed828ada 6.5.2
@@ -1,965 +1,966 b''
1 # transaction.py - simple journaling scheme for mercurial
1 # transaction.py - simple journaling scheme for mercurial
2 #
2 #
3 # This transaction scheme is intended to gracefully handle program
3 # This transaction scheme is intended to gracefully handle program
4 # errors and interruptions. More serious failures like system crashes
4 # errors and interruptions. More serious failures like system crashes
5 # can be recovered with an fsck-like tool. As the whole repository is
5 # can be recovered with an fsck-like tool. As the whole repository is
6 # effectively log-structured, this should amount to simply truncating
6 # effectively log-structured, this should amount to simply truncating
7 # anything that isn't referenced in the changelog.
7 # anything that isn't referenced in the changelog.
8 #
8 #
9 # Copyright 2005, 2006 Olivia Mackall <olivia@selenic.com>
9 # Copyright 2005, 2006 Olivia Mackall <olivia@selenic.com>
10 #
10 #
11 # This software may be used and distributed according to the terms of the
11 # This software may be used and distributed according to the terms of the
12 # GNU General Public License version 2 or any later version.
12 # GNU General Public License version 2 or any later version.
13
13
14 import errno
14 import errno
15 import os
15 import os
16
16
17 from .i18n import _
17 from .i18n import _
18 from . import (
18 from . import (
19 encoding,
19 error,
20 error,
20 pycompat,
21 pycompat,
21 util,
22 util,
22 )
23 )
23 from .utils import stringutil
24 from .utils import stringutil
24
25
25 version = 2
26 version = 2
26
27
27 GEN_GROUP_ALL = b'all'
28 GEN_GROUP_ALL = b'all'
28 GEN_GROUP_PRE_FINALIZE = b'prefinalize'
29 GEN_GROUP_PRE_FINALIZE = b'prefinalize'
29 GEN_GROUP_POST_FINALIZE = b'postfinalize'
30 GEN_GROUP_POST_FINALIZE = b'postfinalize'
30
31
31
32
32 def active(func):
33 def active(func):
33 def _active(self, *args, **kwds):
34 def _active(self, *args, **kwds):
34 if self._count == 0:
35 if self._count == 0:
35 raise error.ProgrammingError(
36 raise error.ProgrammingError(
36 b'cannot use transaction when it is already committed/aborted'
37 b'cannot use transaction when it is already committed/aborted'
37 )
38 )
38 return func(self, *args, **kwds)
39 return func(self, *args, **kwds)
39
40
40 return _active
41 return _active
41
42
42
43
43 UNDO_BACKUP = b'%s.backupfiles'
44 UNDO_BACKUP = b'%s.backupfiles'
44
45
45 UNDO_FILES_MAY_NEED_CLEANUP = [
46 UNDO_FILES_MAY_NEED_CLEANUP = [
46 # legacy entries that might exists on disk from previous version:
47 # legacy entries that might exists on disk from previous version:
47 (b'store', b'%s.narrowspec'),
48 (b'store', b'%s.narrowspec'),
48 (b'plain', b'%s.narrowspec.dirstate'),
49 (b'plain', b'%s.narrowspec.dirstate'),
49 (b'plain', b'%s.branch'),
50 (b'plain', b'%s.branch'),
50 (b'plain', b'%s.bookmarks'),
51 (b'plain', b'%s.bookmarks'),
51 (b'store', b'%s.phaseroots'),
52 (b'store', b'%s.phaseroots'),
52 (b'plain', b'%s.dirstate'),
53 (b'plain', b'%s.dirstate'),
53 # files actually in uses today:
54 # files actually in uses today:
54 (b'plain', b'%s.desc'),
55 (b'plain', b'%s.desc'),
55 # Always delete undo last to make sure we detect that a clean up is needed if
56 # Always delete undo last to make sure we detect that a clean up is needed if
56 # the process is interrupted.
57 # the process is interrupted.
57 (b'store', b'%s'),
58 (b'store', b'%s'),
58 ]
59 ]
59
60
60
61
61 def cleanup_undo_files(report, vfsmap, undo_prefix=b'undo'):
62 def cleanup_undo_files(report, vfsmap, undo_prefix=b'undo'):
62 """remove "undo" files used by the rollback logic
63 """remove "undo" files used by the rollback logic
63
64
64 This is useful to prevent rollback running in situation were it does not
65 This is useful to prevent rollback running in situation were it does not
65 make sense. For example after a strip.
66 make sense. For example after a strip.
66 """
67 """
67 backup_listing = UNDO_BACKUP % undo_prefix
68 backup_listing = UNDO_BACKUP % undo_prefix
68
69
69 backup_entries = []
70 backup_entries = []
70 undo_files = []
71 undo_files = []
71 svfs = vfsmap[b'store']
72 svfs = vfsmap[b'store']
72 try:
73 try:
73 with svfs(backup_listing) as f:
74 with svfs(backup_listing) as f:
74 backup_entries = read_backup_files(report, f)
75 backup_entries = read_backup_files(report, f)
75 except OSError as e:
76 except OSError as e:
76 if e.errno != errno.ENOENT:
77 if e.errno != errno.ENOENT:
77 msg = _(b'could not read %s: %s\n')
78 msg = _(b'could not read %s: %s\n')
78 msg %= (svfs.join(backup_listing), stringutil.forcebytestr(e))
79 msg %= (svfs.join(backup_listing), stringutil.forcebytestr(e))
79 report(msg)
80 report(msg)
80
81
81 for location, f, backup_path, c in backup_entries:
82 for location, f, backup_path, c in backup_entries:
82 if location in vfsmap and backup_path:
83 if location in vfsmap and backup_path:
83 undo_files.append((vfsmap[location], backup_path))
84 undo_files.append((vfsmap[location], backup_path))
84
85
85 undo_files.append((svfs, backup_listing))
86 undo_files.append((svfs, backup_listing))
86 for location, undo_path in UNDO_FILES_MAY_NEED_CLEANUP:
87 for location, undo_path in UNDO_FILES_MAY_NEED_CLEANUP:
87 undo_files.append((vfsmap[location], undo_path % undo_prefix))
88 undo_files.append((vfsmap[location], undo_path % undo_prefix))
88 for undovfs, undofile in undo_files:
89 for undovfs, undofile in undo_files:
89 try:
90 try:
90 undovfs.unlink(undofile)
91 undovfs.unlink(undofile)
91 except OSError as e:
92 except OSError as e:
92 if e.errno != errno.ENOENT:
93 if e.errno != errno.ENOENT:
93 msg = _(b'error removing %s: %s\n')
94 msg = _(b'error removing %s: %s\n')
94 msg %= (undovfs.join(undofile), stringutil.forcebytestr(e))
95 msg %= (undovfs.join(undofile), stringutil.forcebytestr(e))
95 report(msg)
96 report(msg)
96
97
97
98
98 def _playback(
99 def _playback(
99 journal,
100 journal,
100 report,
101 report,
101 opener,
102 opener,
102 vfsmap,
103 vfsmap,
103 entries,
104 entries,
104 backupentries,
105 backupentries,
105 unlink=True,
106 unlink=True,
106 checkambigfiles=None,
107 checkambigfiles=None,
107 ):
108 ):
108 """rollback a transaction :
109 """rollback a transaction :
109 - truncate files that have been appended to
110 - truncate files that have been appended to
110 - restore file backups
111 - restore file backups
111 - delete temporary files
112 - delete temporary files
112 """
113 """
113 backupfiles = []
114 backupfiles = []
114
115
115 def restore_one_backup(vfs, f, b, checkambig):
116 def restore_one_backup(vfs, f, b, checkambig):
116 filepath = vfs.join(f)
117 filepath = vfs.join(f)
117 backuppath = vfs.join(b)
118 backuppath = vfs.join(b)
118 try:
119 try:
119 util.copyfile(backuppath, filepath, checkambig=checkambig)
120 util.copyfile(backuppath, filepath, checkambig=checkambig)
120 backupfiles.append((vfs, b))
121 backupfiles.append((vfs, b))
121 except IOError as exc:
122 except IOError as exc:
122 e_msg = stringutil.forcebytestr(exc)
123 e_msg = stringutil.forcebytestr(exc)
123 report(_(b"failed to recover %s (%s)\n") % (f, e_msg))
124 report(_(b"failed to recover %s (%s)\n") % (f, e_msg))
124 raise
125 raise
125
126
126 # gather all backup files that impact the store
127 # gather all backup files that impact the store
127 # (we need this to detect files that are both backed up and truncated)
128 # (we need this to detect files that are both backed up and truncated)
128 store_backup = {}
129 store_backup = {}
129 for entry in backupentries:
130 for entry in backupentries:
130 location, file_path, backup_path, cache = entry
131 location, file_path, backup_path, cache = entry
131 vfs = vfsmap[location]
132 vfs = vfsmap[location]
132 is_store = vfs.join(b'') == opener.join(b'')
133 is_store = vfs.join(b'') == opener.join(b'')
133 if is_store and file_path and backup_path:
134 if is_store and file_path and backup_path:
134 store_backup[file_path] = entry
135 store_backup[file_path] = entry
135 copy_done = set()
136 copy_done = set()
136
137
137 # truncate all file `f` to offset `o`
138 # truncate all file `f` to offset `o`
138 for f, o in sorted(dict(entries).items()):
139 for f, o in sorted(dict(entries).items()):
139 # if we have a backup for `f`, we should restore it first and truncate
140 # if we have a backup for `f`, we should restore it first and truncate
140 # the restored file
141 # the restored file
141 bck_entry = store_backup.get(f)
142 bck_entry = store_backup.get(f)
142 if bck_entry is not None:
143 if bck_entry is not None:
143 location, file_path, backup_path, cache = bck_entry
144 location, file_path, backup_path, cache = bck_entry
144 checkambig = False
145 checkambig = False
145 if checkambigfiles:
146 if checkambigfiles:
146 checkambig = (file_path, location) in checkambigfiles
147 checkambig = (file_path, location) in checkambigfiles
147 restore_one_backup(opener, file_path, backup_path, checkambig)
148 restore_one_backup(opener, file_path, backup_path, checkambig)
148 copy_done.add(bck_entry)
149 copy_done.add(bck_entry)
149 # truncate the file to its pre-transaction size
150 # truncate the file to its pre-transaction size
150 if o or not unlink:
151 if o or not unlink:
151 checkambig = checkambigfiles and (f, b'') in checkambigfiles
152 checkambig = checkambigfiles and (f, b'') in checkambigfiles
152 try:
153 try:
153 fp = opener(f, b'a', checkambig=checkambig)
154 fp = opener(f, b'a', checkambig=checkambig)
154 if fp.tell() < o:
155 if fp.tell() < o:
155 raise error.Abort(
156 raise error.Abort(
156 _(
157 _(
157 b"attempted to truncate %s to %d bytes, but it was "
158 b"attempted to truncate %s to %d bytes, but it was "
158 b"already %d bytes\n"
159 b"already %d bytes\n"
159 )
160 )
160 % (f, o, fp.tell())
161 % (f, o, fp.tell())
161 )
162 )
162 fp.truncate(o)
163 fp.truncate(o)
163 fp.close()
164 fp.close()
164 except IOError:
165 except IOError:
165 report(_(b"failed to truncate %s\n") % f)
166 report(_(b"failed to truncate %s\n") % f)
166 raise
167 raise
167 else:
168 else:
168 # delete empty file
169 # delete empty file
169 try:
170 try:
170 opener.unlink(f)
171 opener.unlink(f)
171 except FileNotFoundError:
172 except FileNotFoundError:
172 pass
173 pass
173 # restore backed up files and clean up temporary files
174 # restore backed up files and clean up temporary files
174 for entry in backupentries:
175 for entry in backupentries:
175 if entry in copy_done:
176 if entry in copy_done:
176 continue
177 continue
177 l, f, b, c = entry
178 l, f, b, c = entry
178 if l not in vfsmap and c:
179 if l not in vfsmap and c:
179 report(b"couldn't handle %s: unknown cache location %s\n" % (b, l))
180 report(b"couldn't handle %s: unknown cache location %s\n" % (b, l))
180 vfs = vfsmap[l]
181 vfs = vfsmap[l]
181 try:
182 try:
182 checkambig = checkambigfiles and (f, l) in checkambigfiles
183 checkambig = checkambigfiles and (f, l) in checkambigfiles
183 if f and b:
184 if f and b:
184 restore_one_backup(vfs, f, b, checkambig)
185 restore_one_backup(vfs, f, b, checkambig)
185 else:
186 else:
186 target = f or b
187 target = f or b
187 try:
188 try:
188 vfs.unlink(target)
189 vfs.unlink(target)
189 except FileNotFoundError:
190 except FileNotFoundError:
190 # This is fine because
191 # This is fine because
191 #
192 #
192 # either we are trying to delete the main file, and it is
193 # either we are trying to delete the main file, and it is
193 # already deleted.
194 # already deleted.
194 #
195 #
195 # or we are trying to delete a temporary file and it is
196 # or we are trying to delete a temporary file and it is
196 # already deleted.
197 # already deleted.
197 #
198 #
198 # in both case, our target result (delete the file) is
199 # in both case, our target result (delete the file) is
199 # already achieved.
200 # already achieved.
200 pass
201 pass
201 except (IOError, OSError, error.Abort):
202 except (IOError, OSError, error.Abort):
202 if not c:
203 if not c:
203 raise
204 raise
204
205
205 # cleanup transaction state file and the backups file
206 # cleanup transaction state file and the backups file
206 backuppath = b"%s.backupfiles" % journal
207 backuppath = b"%s.backupfiles" % journal
207 if opener.exists(backuppath):
208 if opener.exists(backuppath):
208 opener.unlink(backuppath)
209 opener.unlink(backuppath)
209 opener.unlink(journal)
210 opener.unlink(journal)
210 try:
211 try:
211 for vfs, f in backupfiles:
212 for vfs, f in backupfiles:
212 if vfs.exists(f):
213 if vfs.exists(f):
213 vfs.unlink(f)
214 vfs.unlink(f)
214 except (IOError, OSError, error.Abort):
215 except (IOError, OSError, error.Abort):
215 # only pure backup file remains, it is sage to ignore any error
216 # only pure backup file remains, it is sage to ignore any error
216 pass
217 pass
217
218
218
219
219 class transaction(util.transactional):
220 class transaction(util.transactional):
220 def __init__(
221 def __init__(
221 self,
222 self,
222 report,
223 report,
223 opener,
224 opener,
224 vfsmap,
225 vfsmap,
225 journalname,
226 journalname,
226 undoname=None,
227 undoname=None,
227 after=None,
228 after=None,
228 createmode=None,
229 createmode=None,
229 validator=None,
230 validator=None,
230 releasefn=None,
231 releasefn=None,
231 checkambigfiles=None,
232 checkambigfiles=None,
232 name='<unnamed>',
233 name=b'<unnamed>',
233 ):
234 ):
234 """Begin a new transaction
235 """Begin a new transaction
235
236
236 Begins a new transaction that allows rolling back writes in the event of
237 Begins a new transaction that allows rolling back writes in the event of
237 an exception.
238 an exception.
238
239
239 * `after`: called after the transaction has been committed
240 * `after`: called after the transaction has been committed
240 * `createmode`: the mode of the journal file that will be created
241 * `createmode`: the mode of the journal file that will be created
241 * `releasefn`: called after releasing (with transaction and result)
242 * `releasefn`: called after releasing (with transaction and result)
242
243
243 `checkambigfiles` is a set of (path, vfs-location) tuples,
244 `checkambigfiles` is a set of (path, vfs-location) tuples,
244 which determine whether file stat ambiguity should be avoided
245 which determine whether file stat ambiguity should be avoided
245 for corresponded files.
246 for corresponded files.
246 """
247 """
247 self._count = 1
248 self._count = 1
248 self._usages = 1
249 self._usages = 1
249 self._report = report
250 self._report = report
250 # a vfs to the store content
251 # a vfs to the store content
251 self._opener = opener
252 self._opener = opener
252 # a map to access file in various {location -> vfs}
253 # a map to access file in various {location -> vfs}
253 vfsmap = vfsmap.copy()
254 vfsmap = vfsmap.copy()
254 vfsmap[b''] = opener # set default value
255 vfsmap[b''] = opener # set default value
255 self._vfsmap = vfsmap
256 self._vfsmap = vfsmap
256 self._after = after
257 self._after = after
257 self._offsetmap = {}
258 self._offsetmap = {}
258 self._newfiles = set()
259 self._newfiles = set()
259 self._journal = journalname
260 self._journal = journalname
260 self._journal_files = []
261 self._journal_files = []
261 self._undoname = undoname
262 self._undoname = undoname
262 self._queue = []
263 self._queue = []
263 # A callback to do something just after releasing transaction.
264 # A callback to do something just after releasing transaction.
264 if releasefn is None:
265 if releasefn is None:
265 releasefn = lambda tr, success: None
266 releasefn = lambda tr, success: None
266 self._releasefn = releasefn
267 self._releasefn = releasefn
267
268
268 self._checkambigfiles = set()
269 self._checkambigfiles = set()
269 if checkambigfiles:
270 if checkambigfiles:
270 self._checkambigfiles.update(checkambigfiles)
271 self._checkambigfiles.update(checkambigfiles)
271
272
272 self._names = [name]
273 self._names = [name]
273
274
274 # A dict dedicated to precisely tracking the changes introduced in the
275 # A dict dedicated to precisely tracking the changes introduced in the
275 # transaction.
276 # transaction.
276 self.changes = {}
277 self.changes = {}
277
278
278 # a dict of arguments to be passed to hooks
279 # a dict of arguments to be passed to hooks
279 self.hookargs = {}
280 self.hookargs = {}
280 self._file = opener.open(self._journal, b"w+")
281 self._file = opener.open(self._journal, b"w+")
281
282
282 # a list of ('location', 'path', 'backuppath', cache) entries.
283 # a list of ('location', 'path', 'backuppath', cache) entries.
283 # - if 'backuppath' is empty, no file existed at backup time
284 # - if 'backuppath' is empty, no file existed at backup time
284 # - if 'path' is empty, this is a temporary transaction file
285 # - if 'path' is empty, this is a temporary transaction file
285 # - if 'location' is not empty, the path is outside main opener reach.
286 # - if 'location' is not empty, the path is outside main opener reach.
286 # use 'location' value as a key in a vfsmap to find the right 'vfs'
287 # use 'location' value as a key in a vfsmap to find the right 'vfs'
287 # (cache is currently unused)
288 # (cache is currently unused)
288 self._backupentries = []
289 self._backupentries = []
289 self._backupmap = {}
290 self._backupmap = {}
290 self._backupjournal = b"%s.backupfiles" % self._journal
291 self._backupjournal = b"%s.backupfiles" % self._journal
291 self._backupsfile = opener.open(self._backupjournal, b'w')
292 self._backupsfile = opener.open(self._backupjournal, b'w')
292 self._backupsfile.write(b'%d\n' % version)
293 self._backupsfile.write(b'%d\n' % version)
293 # the set of temporary files
294 # the set of temporary files
294 self._tmp_files = set()
295 self._tmp_files = set()
295
296
296 if createmode is not None:
297 if createmode is not None:
297 opener.chmod(self._journal, createmode & 0o666)
298 opener.chmod(self._journal, createmode & 0o666)
298 opener.chmod(self._backupjournal, createmode & 0o666)
299 opener.chmod(self._backupjournal, createmode & 0o666)
299
300
300 # hold file generations to be performed on commit
301 # hold file generations to be performed on commit
301 self._filegenerators = {}
302 self._filegenerators = {}
302 # hold callback to write pending data for hooks
303 # hold callback to write pending data for hooks
303 self._pendingcallback = {}
304 self._pendingcallback = {}
304 # True is any pending data have been written ever
305 # True is any pending data have been written ever
305 self._anypending = False
306 self._anypending = False
306 # holds callback to call when writing the transaction
307 # holds callback to call when writing the transaction
307 self._finalizecallback = {}
308 self._finalizecallback = {}
308 # holds callback to call when validating the transaction
309 # holds callback to call when validating the transaction
309 # should raise exception if anything is wrong
310 # should raise exception if anything is wrong
310 self._validatecallback = {}
311 self._validatecallback = {}
311 if validator is not None:
312 if validator is not None:
312 self._validatecallback[b'001-userhooks'] = validator
313 self._validatecallback[b'001-userhooks'] = validator
313 # hold callback for post transaction close
314 # hold callback for post transaction close
314 self._postclosecallback = {}
315 self._postclosecallback = {}
315 # holds callbacks to call during abort
316 # holds callbacks to call during abort
316 self._abortcallback = {}
317 self._abortcallback = {}
317
318
318 def __repr__(self):
319 def __repr__(self):
319 name = b'/'.join(self._names)
320 name = b'/'.join(self._names)
320 return '<transaction name=%s, count=%d, usages=%d>' % (
321 return '<transaction name=%s, count=%d, usages=%d>' % (
321 name,
322 encoding.strfromlocal(name),
322 self._count,
323 self._count,
323 self._usages,
324 self._usages,
324 )
325 )
325
326
326 def __del__(self):
327 def __del__(self):
327 if self._journal:
328 if self._journal:
328 self._abort()
329 self._abort()
329
330
330 @property
331 @property
331 def finalized(self):
332 def finalized(self):
332 return self._finalizecallback is None
333 return self._finalizecallback is None
333
334
334 @active
335 @active
335 def startgroup(self):
336 def startgroup(self):
336 """delay registration of file entry
337 """delay registration of file entry
337
338
338 This is used by strip to delay vision of strip offset. The transaction
339 This is used by strip to delay vision of strip offset. The transaction
339 sees either none or all of the strip actions to be done."""
340 sees either none or all of the strip actions to be done."""
340 self._queue.append([])
341 self._queue.append([])
341
342
342 @active
343 @active
343 def endgroup(self):
344 def endgroup(self):
344 """apply delayed registration of file entry.
345 """apply delayed registration of file entry.
345
346
346 This is used by strip to delay vision of strip offset. The transaction
347 This is used by strip to delay vision of strip offset. The transaction
347 sees either none or all of the strip actions to be done."""
348 sees either none or all of the strip actions to be done."""
348 q = self._queue.pop()
349 q = self._queue.pop()
349 for f, o in q:
350 for f, o in q:
350 self._addentry(f, o)
351 self._addentry(f, o)
351
352
352 @active
353 @active
353 def add(self, file, offset):
354 def add(self, file, offset):
354 """record the state of an append-only file before update"""
355 """record the state of an append-only file before update"""
355 if (
356 if (
356 file in self._newfiles
357 file in self._newfiles
357 or file in self._offsetmap
358 or file in self._offsetmap
358 or file in self._backupmap
359 or file in self._backupmap
359 or file in self._tmp_files
360 or file in self._tmp_files
360 ):
361 ):
361 return
362 return
362 if self._queue:
363 if self._queue:
363 self._queue[-1].append((file, offset))
364 self._queue[-1].append((file, offset))
364 return
365 return
365
366
366 self._addentry(file, offset)
367 self._addentry(file, offset)
367
368
368 def _addentry(self, file, offset):
369 def _addentry(self, file, offset):
369 """add a append-only entry to memory and on-disk state"""
370 """add a append-only entry to memory and on-disk state"""
370 if (
371 if (
371 file in self._newfiles
372 file in self._newfiles
372 or file in self._offsetmap
373 or file in self._offsetmap
373 or file in self._backupmap
374 or file in self._backupmap
374 or file in self._tmp_files
375 or file in self._tmp_files
375 ):
376 ):
376 return
377 return
377 if offset:
378 if offset:
378 self._offsetmap[file] = offset
379 self._offsetmap[file] = offset
379 else:
380 else:
380 self._newfiles.add(file)
381 self._newfiles.add(file)
381 # add enough data to the journal to do the truncate
382 # add enough data to the journal to do the truncate
382 self._file.write(b"%s\0%d\n" % (file, offset))
383 self._file.write(b"%s\0%d\n" % (file, offset))
383 self._file.flush()
384 self._file.flush()
384
385
385 @active
386 @active
386 def addbackup(self, file, hardlink=True, location=b'', for_offset=False):
387 def addbackup(self, file, hardlink=True, location=b'', for_offset=False):
387 """Adds a backup of the file to the transaction
388 """Adds a backup of the file to the transaction
388
389
389 Calling addbackup() creates a hardlink backup of the specified file
390 Calling addbackup() creates a hardlink backup of the specified file
390 that is used to recover the file in the event of the transaction
391 that is used to recover the file in the event of the transaction
391 aborting.
392 aborting.
392
393
393 * `file`: the file path, relative to .hg/store
394 * `file`: the file path, relative to .hg/store
394 * `hardlink`: use a hardlink to quickly create the backup
395 * `hardlink`: use a hardlink to quickly create the backup
395
396
396 If `for_offset` is set, we expect a offset for this file to have been previously recorded
397 If `for_offset` is set, we expect a offset for this file to have been previously recorded
397 """
398 """
398 if self._queue:
399 if self._queue:
399 msg = b'cannot use transaction.addbackup inside "group"'
400 msg = b'cannot use transaction.addbackup inside "group"'
400 raise error.ProgrammingError(msg)
401 raise error.ProgrammingError(msg)
401
402
402 if file in self._newfiles or file in self._backupmap:
403 if file in self._newfiles or file in self._backupmap:
403 return
404 return
404 elif file in self._offsetmap and not for_offset:
405 elif file in self._offsetmap and not for_offset:
405 return
406 return
406 elif for_offset and file not in self._offsetmap:
407 elif for_offset and file not in self._offsetmap:
407 msg = (
408 msg = (
408 'calling `addbackup` with `for_offmap=True`, '
409 'calling `addbackup` with `for_offmap=True`, '
409 'but no offset recorded: [%r] %r'
410 'but no offset recorded: [%r] %r'
410 )
411 )
411 msg %= (location, file)
412 msg %= (location, file)
412 raise error.ProgrammingError(msg)
413 raise error.ProgrammingError(msg)
413
414
414 vfs = self._vfsmap[location]
415 vfs = self._vfsmap[location]
415 dirname, filename = vfs.split(file)
416 dirname, filename = vfs.split(file)
416 backupfilename = b"%s.backup.%s.bck" % (self._journal, filename)
417 backupfilename = b"%s.backup.%s.bck" % (self._journal, filename)
417 backupfile = vfs.reljoin(dirname, backupfilename)
418 backupfile = vfs.reljoin(dirname, backupfilename)
418 if vfs.exists(file):
419 if vfs.exists(file):
419 filepath = vfs.join(file)
420 filepath = vfs.join(file)
420 backuppath = vfs.join(backupfile)
421 backuppath = vfs.join(backupfile)
421 # store encoding may result in different directory here.
422 # store encoding may result in different directory here.
422 # so we have to ensure the destination directory exist
423 # so we have to ensure the destination directory exist
423 final_dir_name = os.path.dirname(backuppath)
424 final_dir_name = os.path.dirname(backuppath)
424 util.makedirs(final_dir_name, mode=vfs.createmode, notindexed=True)
425 util.makedirs(final_dir_name, mode=vfs.createmode, notindexed=True)
425 # then we can copy the backup
426 # then we can copy the backup
426 util.copyfile(filepath, backuppath, hardlink=hardlink)
427 util.copyfile(filepath, backuppath, hardlink=hardlink)
427 else:
428 else:
428 backupfile = b''
429 backupfile = b''
429
430
430 self._addbackupentry((location, file, backupfile, False))
431 self._addbackupentry((location, file, backupfile, False))
431
432
432 def _addbackupentry(self, entry):
433 def _addbackupentry(self, entry):
433 """register a new backup entry and write it to disk"""
434 """register a new backup entry and write it to disk"""
434 self._backupentries.append(entry)
435 self._backupentries.append(entry)
435 self._backupmap[entry[1]] = len(self._backupentries) - 1
436 self._backupmap[entry[1]] = len(self._backupentries) - 1
436 self._backupsfile.write(b"%s\0%s\0%s\0%d\n" % entry)
437 self._backupsfile.write(b"%s\0%s\0%s\0%d\n" % entry)
437 self._backupsfile.flush()
438 self._backupsfile.flush()
438
439
439 @active
440 @active
440 def registertmp(self, tmpfile, location=b''):
441 def registertmp(self, tmpfile, location=b''):
441 """register a temporary transaction file
442 """register a temporary transaction file
442
443
443 Such files will be deleted when the transaction exits (on both
444 Such files will be deleted when the transaction exits (on both
444 failure and success).
445 failure and success).
445 """
446 """
446 self._tmp_files.add(tmpfile)
447 self._tmp_files.add(tmpfile)
447 self._addbackupentry((location, b'', tmpfile, False))
448 self._addbackupentry((location, b'', tmpfile, False))
448
449
449 @active
450 @active
450 def addfilegenerator(
451 def addfilegenerator(
451 self,
452 self,
452 genid,
453 genid,
453 filenames,
454 filenames,
454 genfunc,
455 genfunc,
455 order=0,
456 order=0,
456 location=b'',
457 location=b'',
457 post_finalize=False,
458 post_finalize=False,
458 ):
459 ):
459 """add a function to generates some files at transaction commit
460 """add a function to generates some files at transaction commit
460
461
461 The `genfunc` argument is a function capable of generating proper
462 The `genfunc` argument is a function capable of generating proper
462 content of each entry in the `filename` tuple.
463 content of each entry in the `filename` tuple.
463
464
464 At transaction close time, `genfunc` will be called with one file
465 At transaction close time, `genfunc` will be called with one file
465 object argument per entries in `filenames`.
466 object argument per entries in `filenames`.
466
467
467 The transaction itself is responsible for the backup, creation and
468 The transaction itself is responsible for the backup, creation and
468 final write of such file.
469 final write of such file.
469
470
470 The `genid` argument is used to ensure the same set of file is only
471 The `genid` argument is used to ensure the same set of file is only
471 generated once. Call to `addfilegenerator` for a `genid` already
472 generated once. Call to `addfilegenerator` for a `genid` already
472 present will overwrite the old entry.
473 present will overwrite the old entry.
473
474
474 The `order` argument may be used to control the order in which multiple
475 The `order` argument may be used to control the order in which multiple
475 generator will be executed.
476 generator will be executed.
476
477
477 The `location` arguments may be used to indicate the files are located
478 The `location` arguments may be used to indicate the files are located
478 outside of the the standard directory for transaction. It should match
479 outside of the the standard directory for transaction. It should match
479 one of the key of the `transaction.vfsmap` dictionary.
480 one of the key of the `transaction.vfsmap` dictionary.
480
481
481 The `post_finalize` argument can be set to `True` for file generation
482 The `post_finalize` argument can be set to `True` for file generation
482 that must be run after the transaction has been finalized.
483 that must be run after the transaction has been finalized.
483 """
484 """
484 # For now, we are unable to do proper backup and restore of custom vfs
485 # For now, we are unable to do proper backup and restore of custom vfs
485 # but for bookmarks that are handled outside this mechanism.
486 # but for bookmarks that are handled outside this mechanism.
486 entry = (order, filenames, genfunc, location, post_finalize)
487 entry = (order, filenames, genfunc, location, post_finalize)
487 self._filegenerators[genid] = entry
488 self._filegenerators[genid] = entry
488
489
489 @active
490 @active
490 def removefilegenerator(self, genid):
491 def removefilegenerator(self, genid):
491 """reverse of addfilegenerator, remove a file generator function"""
492 """reverse of addfilegenerator, remove a file generator function"""
492 if genid in self._filegenerators:
493 if genid in self._filegenerators:
493 del self._filegenerators[genid]
494 del self._filegenerators[genid]
494
495
495 def _generatefiles(self, suffix=b'', group=GEN_GROUP_ALL):
496 def _generatefiles(self, suffix=b'', group=GEN_GROUP_ALL):
496 # write files registered for generation
497 # write files registered for generation
497 any = False
498 any = False
498
499
499 if group == GEN_GROUP_ALL:
500 if group == GEN_GROUP_ALL:
500 skip_post = skip_pre = False
501 skip_post = skip_pre = False
501 else:
502 else:
502 skip_pre = group == GEN_GROUP_POST_FINALIZE
503 skip_pre = group == GEN_GROUP_POST_FINALIZE
503 skip_post = group == GEN_GROUP_PRE_FINALIZE
504 skip_post = group == GEN_GROUP_PRE_FINALIZE
504
505
505 for id, entry in sorted(self._filegenerators.items()):
506 for id, entry in sorted(self._filegenerators.items()):
506 any = True
507 any = True
507 order, filenames, genfunc, location, post_finalize = entry
508 order, filenames, genfunc, location, post_finalize = entry
508
509
509 # for generation at closing, check if it's before or after finalize
510 # for generation at closing, check if it's before or after finalize
510 if skip_post and post_finalize:
511 if skip_post and post_finalize:
511 continue
512 continue
512 elif skip_pre and not post_finalize:
513 elif skip_pre and not post_finalize:
513 continue
514 continue
514
515
515 vfs = self._vfsmap[location]
516 vfs = self._vfsmap[location]
516 files = []
517 files = []
517 try:
518 try:
518 for name in filenames:
519 for name in filenames:
519 name += suffix
520 name += suffix
520 if suffix:
521 if suffix:
521 self.registertmp(name, location=location)
522 self.registertmp(name, location=location)
522 checkambig = False
523 checkambig = False
523 else:
524 else:
524 self.addbackup(name, location=location)
525 self.addbackup(name, location=location)
525 checkambig = (name, location) in self._checkambigfiles
526 checkambig = (name, location) in self._checkambigfiles
526 files.append(
527 files.append(
527 vfs(name, b'w', atomictemp=True, checkambig=checkambig)
528 vfs(name, b'w', atomictemp=True, checkambig=checkambig)
528 )
529 )
529 genfunc(*files)
530 genfunc(*files)
530 for f in files:
531 for f in files:
531 f.close()
532 f.close()
532 # skip discard() loop since we're sure no open file remains
533 # skip discard() loop since we're sure no open file remains
533 del files[:]
534 del files[:]
534 finally:
535 finally:
535 for f in files:
536 for f in files:
536 f.discard()
537 f.discard()
537 return any
538 return any
538
539
539 @active
540 @active
540 def findoffset(self, file):
541 def findoffset(self, file):
541 if file in self._newfiles:
542 if file in self._newfiles:
542 return 0
543 return 0
543 return self._offsetmap.get(file)
544 return self._offsetmap.get(file)
544
545
545 @active
546 @active
546 def readjournal(self):
547 def readjournal(self):
547 self._file.seek(0)
548 self._file.seek(0)
548 entries = []
549 entries = []
549 for l in self._file.readlines():
550 for l in self._file.readlines():
550 file, troffset = l.split(b'\0')
551 file, troffset = l.split(b'\0')
551 entries.append((file, int(troffset)))
552 entries.append((file, int(troffset)))
552 return entries
553 return entries
553
554
554 @active
555 @active
555 def replace(self, file, offset):
556 def replace(self, file, offset):
556 """
557 """
557 replace can only replace already committed entries
558 replace can only replace already committed entries
558 that are not pending in the queue
559 that are not pending in the queue
559 """
560 """
560 if file in self._newfiles:
561 if file in self._newfiles:
561 if not offset:
562 if not offset:
562 return
563 return
563 self._newfiles.remove(file)
564 self._newfiles.remove(file)
564 self._offsetmap[file] = offset
565 self._offsetmap[file] = offset
565 elif file in self._offsetmap:
566 elif file in self._offsetmap:
566 if not offset:
567 if not offset:
567 del self._offsetmap[file]
568 del self._offsetmap[file]
568 self._newfiles.add(file)
569 self._newfiles.add(file)
569 else:
570 else:
570 self._offsetmap[file] = offset
571 self._offsetmap[file] = offset
571 else:
572 else:
572 raise KeyError(file)
573 raise KeyError(file)
573 self._file.write(b"%s\0%d\n" % (file, offset))
574 self._file.write(b"%s\0%d\n" % (file, offset))
574 self._file.flush()
575 self._file.flush()
575
576
576 @active
577 @active
577 def nest(self, name='<unnamed>'):
578 def nest(self, name=b'<unnamed>'):
578 self._count += 1
579 self._count += 1
579 self._usages += 1
580 self._usages += 1
580 self._names.append(name)
581 self._names.append(name)
581 return self
582 return self
582
583
583 def release(self):
584 def release(self):
584 if self._count > 0:
585 if self._count > 0:
585 self._usages -= 1
586 self._usages -= 1
586 if self._names:
587 if self._names:
587 self._names.pop()
588 self._names.pop()
588 # if the transaction scopes are left without being closed, fail
589 # if the transaction scopes are left without being closed, fail
589 if self._count > 0 and self._usages == 0:
590 if self._count > 0 and self._usages == 0:
590 self._abort()
591 self._abort()
591
592
592 def running(self):
593 def running(self):
593 return self._count > 0
594 return self._count > 0
594
595
595 def addpending(self, category, callback):
596 def addpending(self, category, callback):
596 """add a callback to be called when the transaction is pending
597 """add a callback to be called when the transaction is pending
597
598
598 The transaction will be given as callback's first argument.
599 The transaction will be given as callback's first argument.
599
600
600 Category is a unique identifier to allow overwriting an old callback
601 Category is a unique identifier to allow overwriting an old callback
601 with a newer callback.
602 with a newer callback.
602 """
603 """
603 self._pendingcallback[category] = callback
604 self._pendingcallback[category] = callback
604
605
605 @active
606 @active
606 def writepending(self):
607 def writepending(self):
607 """write pending file to temporary version
608 """write pending file to temporary version
608
609
609 This is used to allow hooks to view a transaction before commit"""
610 This is used to allow hooks to view a transaction before commit"""
610 categories = sorted(self._pendingcallback)
611 categories = sorted(self._pendingcallback)
611 for cat in categories:
612 for cat in categories:
612 # remove callback since the data will have been flushed
613 # remove callback since the data will have been flushed
613 any = self._pendingcallback.pop(cat)(self)
614 any = self._pendingcallback.pop(cat)(self)
614 self._anypending = self._anypending or any
615 self._anypending = self._anypending or any
615 self._anypending |= self._generatefiles(suffix=b'.pending')
616 self._anypending |= self._generatefiles(suffix=b'.pending')
616 return self._anypending
617 return self._anypending
617
618
618 @active
619 @active
619 def hasfinalize(self, category):
620 def hasfinalize(self, category):
620 """check is a callback already exist for a category"""
621 """check is a callback already exist for a category"""
621 return category in self._finalizecallback
622 return category in self._finalizecallback
622
623
623 @active
624 @active
624 def addfinalize(self, category, callback):
625 def addfinalize(self, category, callback):
625 """add a callback to be called when the transaction is closed
626 """add a callback to be called when the transaction is closed
626
627
627 The transaction will be given as callback's first argument.
628 The transaction will be given as callback's first argument.
628
629
629 Category is a unique identifier to allow overwriting old callbacks with
630 Category is a unique identifier to allow overwriting old callbacks with
630 newer callbacks.
631 newer callbacks.
631 """
632 """
632 self._finalizecallback[category] = callback
633 self._finalizecallback[category] = callback
633
634
634 @active
635 @active
635 def addpostclose(self, category, callback):
636 def addpostclose(self, category, callback):
636 """add or replace a callback to be called after the transaction closed
637 """add or replace a callback to be called after the transaction closed
637
638
638 The transaction will be given as callback's first argument.
639 The transaction will be given as callback's first argument.
639
640
640 Category is a unique identifier to allow overwriting an old callback
641 Category is a unique identifier to allow overwriting an old callback
641 with a newer callback.
642 with a newer callback.
642 """
643 """
643 self._postclosecallback[category] = callback
644 self._postclosecallback[category] = callback
644
645
645 @active
646 @active
646 def getpostclose(self, category):
647 def getpostclose(self, category):
647 """return a postclose callback added before, or None"""
648 """return a postclose callback added before, or None"""
648 return self._postclosecallback.get(category, None)
649 return self._postclosecallback.get(category, None)
649
650
650 @active
651 @active
651 def addabort(self, category, callback):
652 def addabort(self, category, callback):
652 """add a callback to be called when the transaction is aborted.
653 """add a callback to be called when the transaction is aborted.
653
654
654 The transaction will be given as the first argument to the callback.
655 The transaction will be given as the first argument to the callback.
655
656
656 Category is a unique identifier to allow overwriting an old callback
657 Category is a unique identifier to allow overwriting an old callback
657 with a newer callback.
658 with a newer callback.
658 """
659 """
659 self._abortcallback[category] = callback
660 self._abortcallback[category] = callback
660
661
661 @active
662 @active
662 def addvalidator(self, category, callback):
663 def addvalidator(self, category, callback):
663 """adds a callback to be called when validating the transaction.
664 """adds a callback to be called when validating the transaction.
664
665
665 The transaction will be given as the first argument to the callback.
666 The transaction will be given as the first argument to the callback.
666
667
667 callback should raise exception if to abort transaction"""
668 callback should raise exception if to abort transaction"""
668 self._validatecallback[category] = callback
669 self._validatecallback[category] = callback
669
670
670 @active
671 @active
671 def close(self):
672 def close(self):
672 '''commit the transaction'''
673 '''commit the transaction'''
673 if self._count == 1:
674 if self._count == 1:
674 for category in sorted(self._validatecallback):
675 for category in sorted(self._validatecallback):
675 self._validatecallback[category](self)
676 self._validatecallback[category](self)
676 self._validatecallback = None # Help prevent cycles.
677 self._validatecallback = None # Help prevent cycles.
677 self._generatefiles(group=GEN_GROUP_PRE_FINALIZE)
678 self._generatefiles(group=GEN_GROUP_PRE_FINALIZE)
678 while self._finalizecallback:
679 while self._finalizecallback:
679 callbacks = self._finalizecallback
680 callbacks = self._finalizecallback
680 self._finalizecallback = {}
681 self._finalizecallback = {}
681 categories = sorted(callbacks)
682 categories = sorted(callbacks)
682 for cat in categories:
683 for cat in categories:
683 callbacks[cat](self)
684 callbacks[cat](self)
684 # Prevent double usage and help clear cycles.
685 # Prevent double usage and help clear cycles.
685 self._finalizecallback = None
686 self._finalizecallback = None
686 self._generatefiles(group=GEN_GROUP_POST_FINALIZE)
687 self._generatefiles(group=GEN_GROUP_POST_FINALIZE)
687
688
688 self._count -= 1
689 self._count -= 1
689 if self._count != 0:
690 if self._count != 0:
690 return
691 return
691 self._file.close()
692 self._file.close()
692 self._backupsfile.close()
693 self._backupsfile.close()
693 # cleanup temporary files
694 # cleanup temporary files
694 for l, f, b, c in self._backupentries:
695 for l, f, b, c in self._backupentries:
695 if l not in self._vfsmap and c:
696 if l not in self._vfsmap and c:
696 self._report(
697 self._report(
697 b"couldn't remove %s: unknown cache location %s\n" % (b, l)
698 b"couldn't remove %s: unknown cache location %s\n" % (b, l)
698 )
699 )
699 continue
700 continue
700 vfs = self._vfsmap[l]
701 vfs = self._vfsmap[l]
701 if not f and b and vfs.exists(b):
702 if not f and b and vfs.exists(b):
702 try:
703 try:
703 vfs.unlink(b)
704 vfs.unlink(b)
704 except (IOError, OSError, error.Abort) as inst:
705 except (IOError, OSError, error.Abort) as inst:
705 if not c:
706 if not c:
706 raise
707 raise
707 # Abort may be raise by read only opener
708 # Abort may be raise by read only opener
708 self._report(
709 self._report(
709 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
710 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
710 )
711 )
711 self._offsetmap = {}
712 self._offsetmap = {}
712 self._newfiles = set()
713 self._newfiles = set()
713 self._writeundo()
714 self._writeundo()
714 if self._after:
715 if self._after:
715 self._after()
716 self._after()
716 self._after = None # Help prevent cycles.
717 self._after = None # Help prevent cycles.
717 if self._opener.isfile(self._backupjournal):
718 if self._opener.isfile(self._backupjournal):
718 self._opener.unlink(self._backupjournal)
719 self._opener.unlink(self._backupjournal)
719 if self._opener.isfile(self._journal):
720 if self._opener.isfile(self._journal):
720 self._opener.unlink(self._journal)
721 self._opener.unlink(self._journal)
721 for l, _f, b, c in self._backupentries:
722 for l, _f, b, c in self._backupentries:
722 if l not in self._vfsmap and c:
723 if l not in self._vfsmap and c:
723 self._report(
724 self._report(
724 b"couldn't remove %s: unknown cache location"
725 b"couldn't remove %s: unknown cache location"
725 b"%s\n" % (b, l)
726 b"%s\n" % (b, l)
726 )
727 )
727 continue
728 continue
728 vfs = self._vfsmap[l]
729 vfs = self._vfsmap[l]
729 if b and vfs.exists(b):
730 if b and vfs.exists(b):
730 try:
731 try:
731 vfs.unlink(b)
732 vfs.unlink(b)
732 except (IOError, OSError, error.Abort) as inst:
733 except (IOError, OSError, error.Abort) as inst:
733 if not c:
734 if not c:
734 raise
735 raise
735 # Abort may be raise by read only opener
736 # Abort may be raise by read only opener
736 self._report(
737 self._report(
737 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
738 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
738 )
739 )
739 self._backupentries = []
740 self._backupentries = []
740 self._journal = None
741 self._journal = None
741
742
742 self._releasefn(self, True) # notify success of closing transaction
743 self._releasefn(self, True) # notify success of closing transaction
743 self._releasefn = None # Help prevent cycles.
744 self._releasefn = None # Help prevent cycles.
744
745
745 # run post close action
746 # run post close action
746 categories = sorted(self._postclosecallback)
747 categories = sorted(self._postclosecallback)
747 for cat in categories:
748 for cat in categories:
748 self._postclosecallback[cat](self)
749 self._postclosecallback[cat](self)
749 # Prevent double usage and help clear cycles.
750 # Prevent double usage and help clear cycles.
750 self._postclosecallback = None
751 self._postclosecallback = None
751
752
752 @active
753 @active
753 def abort(self):
754 def abort(self):
754 """abort the transaction (generally called on error, or when the
755 """abort the transaction (generally called on error, or when the
755 transaction is not explicitly committed before going out of
756 transaction is not explicitly committed before going out of
756 scope)"""
757 scope)"""
757 self._abort()
758 self._abort()
758
759
759 @active
760 @active
760 def add_journal(self, vfs_id, path):
761 def add_journal(self, vfs_id, path):
761 self._journal_files.append((vfs_id, path))
762 self._journal_files.append((vfs_id, path))
762
763
763 def _writeundo(self):
764 def _writeundo(self):
764 """write transaction data for possible future undo call"""
765 """write transaction data for possible future undo call"""
765 if self._undoname is None:
766 if self._undoname is None:
766 return
767 return
767 cleanup_undo_files(
768 cleanup_undo_files(
768 self._report,
769 self._report,
769 self._vfsmap,
770 self._vfsmap,
770 undo_prefix=self._undoname,
771 undo_prefix=self._undoname,
771 )
772 )
772
773
773 def undoname(fn: bytes) -> bytes:
774 def undoname(fn: bytes) -> bytes:
774 base, name = os.path.split(fn)
775 base, name = os.path.split(fn)
775 assert name.startswith(self._journal)
776 assert name.startswith(self._journal)
776 new_name = name.replace(self._journal, self._undoname, 1)
777 new_name = name.replace(self._journal, self._undoname, 1)
777 return os.path.join(base, new_name)
778 return os.path.join(base, new_name)
778
779
779 undo_backup_path = b"%s.backupfiles" % self._undoname
780 undo_backup_path = b"%s.backupfiles" % self._undoname
780 undobackupfile = self._opener.open(undo_backup_path, b'w')
781 undobackupfile = self._opener.open(undo_backup_path, b'w')
781 undobackupfile.write(b'%d\n' % version)
782 undobackupfile.write(b'%d\n' % version)
782 for l, f, b, c in self._backupentries:
783 for l, f, b, c in self._backupentries:
783 if not f: # temporary file
784 if not f: # temporary file
784 continue
785 continue
785 if not b:
786 if not b:
786 u = b''
787 u = b''
787 else:
788 else:
788 if l not in self._vfsmap and c:
789 if l not in self._vfsmap and c:
789 self._report(
790 self._report(
790 b"couldn't remove %s: unknown cache location"
791 b"couldn't remove %s: unknown cache location"
791 b"%s\n" % (b, l)
792 b"%s\n" % (b, l)
792 )
793 )
793 continue
794 continue
794 vfs = self._vfsmap[l]
795 vfs = self._vfsmap[l]
795 u = undoname(b)
796 u = undoname(b)
796 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True)
797 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True)
797 undobackupfile.write(b"%s\0%s\0%s\0%d\n" % (l, f, u, c))
798 undobackupfile.write(b"%s\0%s\0%s\0%d\n" % (l, f, u, c))
798 undobackupfile.close()
799 undobackupfile.close()
799 for vfs, src in self._journal_files:
800 for vfs, src in self._journal_files:
800 dest = undoname(src)
801 dest = undoname(src)
801 # if src and dest refer to a same file, vfs.rename is a no-op,
802 # if src and dest refer to a same file, vfs.rename is a no-op,
802 # leaving both src and dest on disk. delete dest to make sure
803 # leaving both src and dest on disk. delete dest to make sure
803 # the rename couldn't be such a no-op.
804 # the rename couldn't be such a no-op.
804 vfs.tryunlink(dest)
805 vfs.tryunlink(dest)
805 try:
806 try:
806 vfs.rename(src, dest)
807 vfs.rename(src, dest)
807 except FileNotFoundError: # journal file does not yet exist
808 except FileNotFoundError: # journal file does not yet exist
808 pass
809 pass
809
810
810 def _abort(self):
811 def _abort(self):
811 entries = self.readjournal()
812 entries = self.readjournal()
812 self._count = 0
813 self._count = 0
813 self._usages = 0
814 self._usages = 0
814 self._file.close()
815 self._file.close()
815 self._backupsfile.close()
816 self._backupsfile.close()
816
817
817 quick = self._can_quick_abort(entries)
818 quick = self._can_quick_abort(entries)
818 try:
819 try:
819 if not quick:
820 if not quick:
820 self._report(_(b"transaction abort!\n"))
821 self._report(_(b"transaction abort!\n"))
821 for cat in sorted(self._abortcallback):
822 for cat in sorted(self._abortcallback):
822 self._abortcallback[cat](self)
823 self._abortcallback[cat](self)
823 # Prevent double usage and help clear cycles.
824 # Prevent double usage and help clear cycles.
824 self._abortcallback = None
825 self._abortcallback = None
825 if quick:
826 if quick:
826 self._do_quick_abort(entries)
827 self._do_quick_abort(entries)
827 else:
828 else:
828 self._do_full_abort(entries)
829 self._do_full_abort(entries)
829 finally:
830 finally:
830 self._journal = None
831 self._journal = None
831 self._releasefn(self, False) # notify failure of transaction
832 self._releasefn(self, False) # notify failure of transaction
832 self._releasefn = None # Help prevent cycles.
833 self._releasefn = None # Help prevent cycles.
833
834
834 def _can_quick_abort(self, entries):
835 def _can_quick_abort(self, entries):
835 """False if any semantic content have been written on disk
836 """False if any semantic content have been written on disk
836
837
837 True if nothing, except temporary files has been writen on disk."""
838 True if nothing, except temporary files has been writen on disk."""
838 if entries:
839 if entries:
839 return False
840 return False
840 for e in self._backupentries:
841 for e in self._backupentries:
841 if e[1]:
842 if e[1]:
842 return False
843 return False
843 return True
844 return True
844
845
845 def _do_quick_abort(self, entries):
846 def _do_quick_abort(self, entries):
846 """(Silently) do a quick cleanup (see _can_quick_abort)"""
847 """(Silently) do a quick cleanup (see _can_quick_abort)"""
847 assert self._can_quick_abort(entries)
848 assert self._can_quick_abort(entries)
848 tmp_files = [e for e in self._backupentries if not e[1]]
849 tmp_files = [e for e in self._backupentries if not e[1]]
849 for vfs_id, old_path, tmp_path, xxx in tmp_files:
850 for vfs_id, old_path, tmp_path, xxx in tmp_files:
850 vfs = self._vfsmap[vfs_id]
851 vfs = self._vfsmap[vfs_id]
851 try:
852 try:
852 vfs.unlink(tmp_path)
853 vfs.unlink(tmp_path)
853 except FileNotFoundError:
854 except FileNotFoundError:
854 pass
855 pass
855 if self._backupjournal:
856 if self._backupjournal:
856 self._opener.unlink(self._backupjournal)
857 self._opener.unlink(self._backupjournal)
857 if self._journal:
858 if self._journal:
858 self._opener.unlink(self._journal)
859 self._opener.unlink(self._journal)
859
860
860 def _do_full_abort(self, entries):
861 def _do_full_abort(self, entries):
861 """(Noisily) rollback all the change introduced by the transaction"""
862 """(Noisily) rollback all the change introduced by the transaction"""
862 try:
863 try:
863 _playback(
864 _playback(
864 self._journal,
865 self._journal,
865 self._report,
866 self._report,
866 self._opener,
867 self._opener,
867 self._vfsmap,
868 self._vfsmap,
868 entries,
869 entries,
869 self._backupentries,
870 self._backupentries,
870 unlink=True,
871 unlink=True,
871 checkambigfiles=self._checkambigfiles,
872 checkambigfiles=self._checkambigfiles,
872 )
873 )
873 self._report(_(b"rollback completed\n"))
874 self._report(_(b"rollback completed\n"))
874 except BaseException as exc:
875 except BaseException as exc:
875 self._report(_(b"rollback failed - please run hg recover\n"))
876 self._report(_(b"rollback failed - please run hg recover\n"))
876 self._report(
877 self._report(
877 _(b"(failure reason: %s)\n") % stringutil.forcebytestr(exc)
878 _(b"(failure reason: %s)\n") % stringutil.forcebytestr(exc)
878 )
879 )
879
880
880
881
881 BAD_VERSION_MSG = _(
882 BAD_VERSION_MSG = _(
882 b"journal was created by a different version of Mercurial\n"
883 b"journal was created by a different version of Mercurial\n"
883 )
884 )
884
885
885
886
886 def read_backup_files(report, fp):
887 def read_backup_files(report, fp):
887 """parse an (already open) backup file an return contained backup entries
888 """parse an (already open) backup file an return contained backup entries
888
889
889 entries are in the form: (location, file, backupfile, xxx)
890 entries are in the form: (location, file, backupfile, xxx)
890
891
891 :location: the vfs identifier (vfsmap's key)
892 :location: the vfs identifier (vfsmap's key)
892 :file: original file path (in the vfs)
893 :file: original file path (in the vfs)
893 :backupfile: path of the backup (in the vfs)
894 :backupfile: path of the backup (in the vfs)
894 :cache: a boolean currently always set to False
895 :cache: a boolean currently always set to False
895 """
896 """
896 lines = fp.readlines()
897 lines = fp.readlines()
897 backupentries = []
898 backupentries = []
898 if lines:
899 if lines:
899 ver = lines[0][:-1]
900 ver = lines[0][:-1]
900 if ver != (b'%d' % version):
901 if ver != (b'%d' % version):
901 report(BAD_VERSION_MSG)
902 report(BAD_VERSION_MSG)
902 else:
903 else:
903 for line in lines[1:]:
904 for line in lines[1:]:
904 if line:
905 if line:
905 # Shave off the trailing newline
906 # Shave off the trailing newline
906 line = line[:-1]
907 line = line[:-1]
907 l, f, b, c = line.split(b'\0')
908 l, f, b, c = line.split(b'\0')
908 backupentries.append((l, f, b, bool(c)))
909 backupentries.append((l, f, b, bool(c)))
909 return backupentries
910 return backupentries
910
911
911
912
912 def rollback(
913 def rollback(
913 opener,
914 opener,
914 vfsmap,
915 vfsmap,
915 file,
916 file,
916 report,
917 report,
917 checkambigfiles=None,
918 checkambigfiles=None,
918 skip_journal_pattern=None,
919 skip_journal_pattern=None,
919 ):
920 ):
920 """Rolls back the transaction contained in the given file
921 """Rolls back the transaction contained in the given file
921
922
922 Reads the entries in the specified file, and the corresponding
923 Reads the entries in the specified file, and the corresponding
923 '*.backupfiles' file, to recover from an incomplete transaction.
924 '*.backupfiles' file, to recover from an incomplete transaction.
924
925
925 * `file`: a file containing a list of entries, specifying where
926 * `file`: a file containing a list of entries, specifying where
926 to truncate each file. The file should contain a list of
927 to truncate each file. The file should contain a list of
927 file\0offset pairs, delimited by newlines. The corresponding
928 file\0offset pairs, delimited by newlines. The corresponding
928 '*.backupfiles' file should contain a list of file\0backupfile
929 '*.backupfiles' file should contain a list of file\0backupfile
929 pairs, delimited by \0.
930 pairs, delimited by \0.
930
931
931 `checkambigfiles` is a set of (path, vfs-location) tuples,
932 `checkambigfiles` is a set of (path, vfs-location) tuples,
932 which determine whether file stat ambiguity should be avoided at
933 which determine whether file stat ambiguity should be avoided at
933 restoring corresponded files.
934 restoring corresponded files.
934 """
935 """
935 entries = []
936 entries = []
936 backupentries = []
937 backupentries = []
937
938
938 with opener.open(file) as fp:
939 with opener.open(file) as fp:
939 lines = fp.readlines()
940 lines = fp.readlines()
940 for l in lines:
941 for l in lines:
941 try:
942 try:
942 f, o = l.split(b'\0')
943 f, o = l.split(b'\0')
943 entries.append((f, int(o)))
944 entries.append((f, int(o)))
944 except ValueError:
945 except ValueError:
945 report(
946 report(
946 _(b"couldn't read journal entry %r!\n") % pycompat.bytestr(l)
947 _(b"couldn't read journal entry %r!\n") % pycompat.bytestr(l)
947 )
948 )
948
949
949 backupjournal = b"%s.backupfiles" % file
950 backupjournal = b"%s.backupfiles" % file
950 if opener.exists(backupjournal):
951 if opener.exists(backupjournal):
951 with opener.open(backupjournal) as fp:
952 with opener.open(backupjournal) as fp:
952 backupentries = read_backup_files(report, fp)
953 backupentries = read_backup_files(report, fp)
953 if skip_journal_pattern is not None:
954 if skip_journal_pattern is not None:
954 keep = lambda x: not skip_journal_pattern.match(x[1])
955 keep = lambda x: not skip_journal_pattern.match(x[1])
955 backupentries = [x for x in backupentries if keep(x)]
956 backupentries = [x for x in backupentries if keep(x)]
956
957
957 _playback(
958 _playback(
958 file,
959 file,
959 report,
960 report,
960 opener,
961 opener,
961 vfsmap,
962 vfsmap,
962 entries,
963 entries,
963 backupentries,
964 backupentries,
964 checkambigfiles=checkambigfiles,
965 checkambigfiles=checkambigfiles,
965 )
966 )
@@ -1,99 +1,109 b''
1 = Mercurial 6.5.2 =
2
3 * hgweb: encode WSGI environment using the ISO-8859-1 codec
4 * rhg: fix the bug where sparse config is interpreted as relglob instead of glob
5 * gpg: fix an UnboundLocalError whenever using --force
6 * transaction: fix __repr__() and make the default name bytes
7 * setup: make the error "Unable to find a working hg binary" more informative
8 * tests: avoid test environment affecting setup.py
9 * run-tests: detect HGWITHRUSTEXT value
10
1 = Mercurial 6.5.1 =
11 = Mercurial 6.5.1 =
2
12
3 * A bunch of improvements to Python 3.12 compatibility
13 * A bunch of improvements to Python 3.12 compatibility
4 * repoview: fix the filter created by `extrafilter`
14 * repoview: fix the filter created by `extrafilter`
5 * Improve portability of the test suite
15 * Improve portability of the test suite
6 * fncache: fix a bug that corrupts the fncache after transaction rollback
16 * fncache: fix a bug that corrupts the fncache after transaction rollback
7 * revlog: fix the naming scheme use by split temporary file
17 * revlog: fix the naming scheme use by split temporary file
8 * perf: fix perf::tags
18 * perf: fix perf::tags
9
19
10 = Mercurial 6.5 =
20 = Mercurial 6.5 =
11
21
12 As usual, a lot of patches don't make it to this list since they're more internal.
22 As usual, a lot of patches don't make it to this list since they're more internal.
13
23
14 == New Features ==
24 == New Features ==
15
25
16 * Improved Python 3.12 compatiblity
26 * Improved Python 3.12 compatiblity
17 * configitems: enable changegroup3 by default (unless using infinitepush)
27 * configitems: enable changegroup3 by default (unless using infinitepush)
18 * extras: expose 'retained_extras' for extensions to extend
28 * extras: expose 'retained_extras' for extensions to extend
19 * stabletailgraph: implement stable-tail sort
29 * stabletailgraph: implement stable-tail sort
20 * stabletailgraph: naive version of leap computation
30 * stabletailgraph: naive version of leap computation
21 * bundle: introduce a "v3" spec
31 * bundle: introduce a "v3" spec
22 * clone-bundles: add a basic first version of automatic bundle generation
32 * clone-bundles: add a basic first version of automatic bundle generation
23 * clone-bundles: garbage collect older bundle when generating new ones
33 * clone-bundles: garbage collect older bundle when generating new ones
24 * clone-bundles: only regenerate the clone bundle when cached ration is low
34 * clone-bundles: only regenerate the clone bundle when cached ration is low
25 * clone-bundles: also control automation based on absolute number of revisions
35 * clone-bundles: also control automation based on absolute number of revisions
26 * clone-bundles: add a configuration to control auto-generation on changes
36 * clone-bundles: add a configuration to control auto-generation on changes
27 * clone-bundles: introduce a command to refresh bundle
37 * clone-bundles: introduce a command to refresh bundle
28 * clone-bundles: add a command to clear all bundles
38 * clone-bundles: add a command to clear all bundles
29 * clone-bundles: add an option to generate bundles in the background
39 * clone-bundles: add an option to generate bundles in the background
30 * clonebundles: add support for inline (streaming) clonebundles
40 * clonebundles: add support for inline (streaming) clonebundles
31 * clonebundles: adds a auto-generate.serve-inline option
41 * clonebundles: adds a auto-generate.serve-inline option
32 * match: add `filepath:` pattern to match an exact filepath relative to the root
42 * match: add `filepath:` pattern to match an exact filepath relative to the root
33 * hgweb: add "children" into the JSON template for a changeset
43 * hgweb: add "children" into the JSON template for a changeset
34 * hgweb: add support to explicitly access hidden changesets
44 * hgweb: add support to explicitly access hidden changesets
35 * pull: add --remote-hidden option and pass it through peer creation
45 * pull: add --remote-hidden option and pass it through peer creation
36 * hidden: add support for --remote-hidden to HTTP peer
46 * hidden: add support for --remote-hidden to HTTP peer
37 * hidden: support passing --hidden with `serve --stdio`
47 * hidden: support passing --hidden with `serve --stdio`
38 * hidden: add support to explicitly access hidden changesets with SSH peers
48 * hidden: add support to explicitly access hidden changesets with SSH peers
39 * perf: introduce a `perf::stream-locked-section` command
49 * perf: introduce a `perf::stream-locked-section` command
40 * perf: add a function to find a stream version generator
50 * perf: add a function to find a stream version generator
41 * perf: add support for stream-v3 during benchmark
51 * perf: add support for stream-v3 during benchmark
42 * perf: add a perf::stream-generate command
52 * perf: add a perf::stream-generate command
43 * perf: add a perf::stream-consume
53 * perf: add a perf::stream-consume
44 * cli: make debugnodemap capable of inspecting an arbitrary nodemap
54 * cli: make debugnodemap capable of inspecting an arbitrary nodemap
45 * rust: configure MSRV in Clippy
55 * rust: configure MSRV in Clippy
46 * rhg: make `rhg files` work if `ui.relative-files=true` is specified
56 * rhg: make `rhg files` work if `ui.relative-files=true` is specified
47 * rhg: support `rhg files` with `ui.relative-paths=false`
57 * rhg: support `rhg files` with `ui.relative-paths=false`
48 * rhg: support `status --print0`
58 * rhg: support `status --print0`
49 * tree-manifest: allow `debugupgraderepo` to run on tree manifest repo
59 * tree-manifest: allow `debugupgraderepo` to run on tree manifest repo
50 * library: enable runpy invocation on mercurial package
60 * library: enable runpy invocation on mercurial package
51 * library: incorporate demandimport into runpy invocation
61 * library: incorporate demandimport into runpy invocation
52 * exchange: allow passing no includes/excludes to `pull()`
62 * exchange: allow passing no includes/excludes to `pull()`
53
63
54 == New Experimental Features ==
64 == New Experimental Features ==
55
65
56 * stream-clone: add an experimental v3 version of the protocol
66 * stream-clone: add an experimental v3 version of the protocol
57 * stream-clone: support streamv3 on the cli [hg bundle]
67 * stream-clone: support streamv3 on the cli [hg bundle]
58
68
59 == Bug Fixes ==
69 == Bug Fixes ==
60
70
61 * mail: add a missing argument to properly override starttls
71 * mail: add a missing argument to properly override starttls
62 * bundle: include required phases when saving a bundle (issue6794)
72 * bundle: include required phases when saving a bundle (issue6794)
63 * outgoing: fix common-heads computation from `missingroots` argument
73 * outgoing: fix common-heads computation from `missingroots` argument
64 * strip: do not include internal changeset in the strip backup
74 * strip: do not include internal changeset in the strip backup
65 * bundle: abort if the user request bundling of internal changesets
75 * bundle: abort if the user request bundling of internal changesets
66 * bundle: prevent implicit bundling of internal changeset
76 * bundle: prevent implicit bundling of internal changeset
67 * encoding: avoid quadratic time complexity when json-encoding non-UTF8 strings
77 * encoding: avoid quadratic time complexity when json-encoding non-UTF8 strings
68 * sha1dc: Make sure SHA1DC_BIGENDIAN is set on Darwin/PowerPC
78 * sha1dc: Make sure SHA1DC_BIGENDIAN is set on Darwin/PowerPC
69 * zstd: hack include order to ensure that our zstd.h is found
79 * zstd: hack include order to ensure that our zstd.h is found
70 * dirstate: better error messages when dirstate is corrupted
80 * dirstate: better error messages when dirstate is corrupted
71 * stream-clone: avoid opening a revlog in case we do not need it
81 * stream-clone: avoid opening a revlog in case we do not need it
72 * treemanifest: make `updatecaches` update the nodemaps for all directories
82 * treemanifest: make `updatecaches` update the nodemaps for all directories
73 * rust-hg-core: move from `ouroboros` to `self_cell`
83 * rust-hg-core: move from `ouroboros` to `self_cell`
74 * rust-dependencies: switch from `users` to `whoami`
84 * rust-dependencies: switch from `users` to `whoami`
75 * dirstate-v2: actually fix the dirstate-v2 upgrade race
85 * dirstate-v2: actually fix the dirstate-v2 upgrade race
76 * dirstate: avoid leaking disk space in `hg debugrebuilddirstate`
86 * dirstate: avoid leaking disk space in `hg debugrebuilddirstate`
77 * clonebundles: add warning if auto-generate is enabled without formats
87 * clonebundles: add warning if auto-generate is enabled without formats
78 * win32mbcs: unbyteify some strings for py3 support
88 * win32mbcs: unbyteify some strings for py3 support
79 * rust-revlog: fix incorrect results with NULL_NODE prefixes
89 * rust-revlog: fix incorrect results with NULL_NODE prefixes
80 * rust-revlog: fix RevlogEntry.data() for NULL_REVISION
90 * rust-revlog: fix RevlogEntry.data() for NULL_REVISION
81
91
82 == Backwards Compatibility Changes ==
92 == Backwards Compatibility Changes ==
83
93
84 * infinitepush: aggressively deprecated infinite push
94 * infinitepush: aggressively deprecated infinite push
85 * narrow: indicated the default of 'Yes' when confirming auto-remove-includes
95 * narrow: indicated the default of 'Yes' when confirming auto-remove-includes
86
96
87 == Internal API Changes ==
97 == Internal API Changes ==
88
98
89 * Store walk was reworked to fix small race conditions in stream-clone and
99 * Store walk was reworked to fix small race conditions in stream-clone and
90 greatly improve its API robustness and flexibility.
100 greatly improve its API robustness and flexibility.
91
101
92 == Miscellaneous ==
102 == Miscellaneous ==
93
103
94 * Typechecking support was improved in a lot of places
104 * Typechecking support was improved in a lot of places
95 * Removed more useless compat code for now unsupported Python versions
105 * Removed more useless compat code for now unsupported Python versions
96 * Sped up zstd usage in Rust contexts
106 * Sped up zstd usage in Rust contexts
97 * revlog: add an exception hint when processing LFS flags without the extension
107 * revlog: add an exception hint when processing LFS flags without the extension
98 * ui: keep the progress bar around when writing if stdout is not a tty
108 * ui: keep the progress bar around when writing if stdout is not a tty
99 * transaction: use a ".bck" extension for all backup file
109 * transaction: use a ".bck" extension for all backup file
@@ -1,1808 +1,1824 b''
1 #
1 #
2 # This is the mercurial setup script.
2 # This is the mercurial setup script.
3 #
3 #
4 # 'python setup.py install', or
4 # 'python setup.py install', or
5 # 'python setup.py --help' for more options
5 # 'python setup.py --help' for more options
6 import os
6 import os
7
7
8 # Mercurial can't work on 3.6.0 or 3.6.1 due to a bug in % formatting
8 # Mercurial can't work on 3.6.0 or 3.6.1 due to a bug in % formatting
9 # in bytestrings.
9 # in bytestrings.
10 supportedpy = ','.join(
10 supportedpy = ','.join(
11 [
11 [
12 '>=3.6.2',
12 '>=3.6.2',
13 ]
13 ]
14 )
14 )
15
15
16 import sys, platform
16 import sys, platform
17 import sysconfig
17 import sysconfig
18
18
19
19
20 def sysstr(s):
20 def sysstr(s):
21 return s.decode('latin-1')
21 return s.decode('latin-1')
22
22
23
23
24 def eprint(*args, **kwargs):
24 def eprint(*args, **kwargs):
25 kwargs['file'] = sys.stderr
25 kwargs['file'] = sys.stderr
26 print(*args, **kwargs)
26 print(*args, **kwargs)
27
27
28
28
29 import ssl
29 import ssl
30
30
31 # ssl.HAS_TLSv1* are preferred to check support but they were added in Python
31 # ssl.HAS_TLSv1* are preferred to check support but they were added in Python
32 # 3.7. Prior to CPython commit 6e8cda91d92da72800d891b2fc2073ecbc134d98
32 # 3.7. Prior to CPython commit 6e8cda91d92da72800d891b2fc2073ecbc134d98
33 # (backported to the 3.7 branch), ssl.PROTOCOL_TLSv1_1 / ssl.PROTOCOL_TLSv1_2
33 # (backported to the 3.7 branch), ssl.PROTOCOL_TLSv1_1 / ssl.PROTOCOL_TLSv1_2
34 # were defined only if compiled against a OpenSSL version with TLS 1.1 / 1.2
34 # were defined only if compiled against a OpenSSL version with TLS 1.1 / 1.2
35 # support. At the mentioned commit, they were unconditionally defined.
35 # support. At the mentioned commit, they were unconditionally defined.
36 _notset = object()
36 _notset = object()
37 has_tlsv1_1 = getattr(ssl, 'HAS_TLSv1_1', _notset)
37 has_tlsv1_1 = getattr(ssl, 'HAS_TLSv1_1', _notset)
38 if has_tlsv1_1 is _notset:
38 if has_tlsv1_1 is _notset:
39 has_tlsv1_1 = getattr(ssl, 'PROTOCOL_TLSv1_1', _notset) is not _notset
39 has_tlsv1_1 = getattr(ssl, 'PROTOCOL_TLSv1_1', _notset) is not _notset
40 has_tlsv1_2 = getattr(ssl, 'HAS_TLSv1_2', _notset)
40 has_tlsv1_2 = getattr(ssl, 'HAS_TLSv1_2', _notset)
41 if has_tlsv1_2 is _notset:
41 if has_tlsv1_2 is _notset:
42 has_tlsv1_2 = getattr(ssl, 'PROTOCOL_TLSv1_2', _notset) is not _notset
42 has_tlsv1_2 = getattr(ssl, 'PROTOCOL_TLSv1_2', _notset) is not _notset
43 if not (has_tlsv1_1 or has_tlsv1_2):
43 if not (has_tlsv1_1 or has_tlsv1_2):
44 error = """
44 error = """
45 The `ssl` module does not advertise support for TLS 1.1 or TLS 1.2.
45 The `ssl` module does not advertise support for TLS 1.1 or TLS 1.2.
46 Please make sure that your Python installation was compiled against an OpenSSL
46 Please make sure that your Python installation was compiled against an OpenSSL
47 version enabling these features (likely this requires the OpenSSL version to
47 version enabling these features (likely this requires the OpenSSL version to
48 be at least 1.0.1).
48 be at least 1.0.1).
49 """
49 """
50 print(error, file=sys.stderr)
50 print(error, file=sys.stderr)
51 sys.exit(1)
51 sys.exit(1)
52
52
53 DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX']
53 DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX']
54
54
55 # Solaris Python packaging brain damage
55 # Solaris Python packaging brain damage
56 try:
56 try:
57 import hashlib
57 import hashlib
58
58
59 sha = hashlib.sha1()
59 sha = hashlib.sha1()
60 except ImportError:
60 except ImportError:
61 try:
61 try:
62 import sha
62 import sha
63
63
64 sha.sha # silence unused import warning
64 sha.sha # silence unused import warning
65 except ImportError:
65 except ImportError:
66 raise SystemExit(
66 raise SystemExit(
67 "Couldn't import standard hashlib (incomplete Python install)."
67 "Couldn't import standard hashlib (incomplete Python install)."
68 )
68 )
69
69
70 try:
70 try:
71 import zlib
71 import zlib
72
72
73 zlib.compressobj # silence unused import warning
73 zlib.compressobj # silence unused import warning
74 except ImportError:
74 except ImportError:
75 raise SystemExit(
75 raise SystemExit(
76 "Couldn't import standard zlib (incomplete Python install)."
76 "Couldn't import standard zlib (incomplete Python install)."
77 )
77 )
78
78
79 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
79 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
80 isironpython = False
80 isironpython = False
81 try:
81 try:
82 isironpython = (
82 isironpython = (
83 platform.python_implementation().lower().find("ironpython") != -1
83 platform.python_implementation().lower().find("ironpython") != -1
84 )
84 )
85 except AttributeError:
85 except AttributeError:
86 pass
86 pass
87
87
88 if isironpython:
88 if isironpython:
89 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
89 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
90 else:
90 else:
91 try:
91 try:
92 import bz2
92 import bz2
93
93
94 bz2.BZ2Compressor # silence unused import warning
94 bz2.BZ2Compressor # silence unused import warning
95 except ImportError:
95 except ImportError:
96 raise SystemExit(
96 raise SystemExit(
97 "Couldn't import standard bz2 (incomplete Python install)."
97 "Couldn't import standard bz2 (incomplete Python install)."
98 )
98 )
99
99
100 ispypy = "PyPy" in sys.version
100 ispypy = "PyPy" in sys.version
101
101
102 import ctypes
102 import ctypes
103 import stat, subprocess, time
103 import stat, subprocess, time
104 import re
104 import re
105 import shutil
105 import shutil
106 import tempfile
106 import tempfile
107
107
108 # We have issues with setuptools on some platforms and builders. Until
108 # We have issues with setuptools on some platforms and builders. Until
109 # those are resolved, setuptools is opt-in except for platforms where
109 # those are resolved, setuptools is opt-in except for platforms where
110 # we don't have issues.
110 # we don't have issues.
111 issetuptools = os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ
111 issetuptools = os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ
112 if issetuptools:
112 if issetuptools:
113 from setuptools import setup
113 from setuptools import setup
114 else:
114 else:
115 try:
115 try:
116 from distutils.core import setup
116 from distutils.core import setup
117 except ModuleNotFoundError:
117 except ModuleNotFoundError:
118 from setuptools import setup
118 from setuptools import setup
119 from distutils.ccompiler import new_compiler
119 from distutils.ccompiler import new_compiler
120 from distutils.core import Command, Extension
120 from distutils.core import Command, Extension
121 from distutils.dist import Distribution
121 from distutils.dist import Distribution
122 from distutils.command.build import build
122 from distutils.command.build import build
123 from distutils.command.build_ext import build_ext
123 from distutils.command.build_ext import build_ext
124 from distutils.command.build_py import build_py
124 from distutils.command.build_py import build_py
125 from distutils.command.build_scripts import build_scripts
125 from distutils.command.build_scripts import build_scripts
126 from distutils.command.install import install
126 from distutils.command.install import install
127 from distutils.command.install_lib import install_lib
127 from distutils.command.install_lib import install_lib
128 from distutils.command.install_scripts import install_scripts
128 from distutils.command.install_scripts import install_scripts
129 from distutils import log
129 from distutils import log
130 from distutils.spawn import spawn, find_executable
130 from distutils.spawn import spawn, find_executable
131 from distutils import file_util
131 from distutils import file_util
132 from distutils.errors import (
132 from distutils.errors import (
133 CCompilerError,
133 CCompilerError,
134 DistutilsError,
134 DistutilsError,
135 DistutilsExecError,
135 DistutilsExecError,
136 )
136 )
137 from distutils.sysconfig import get_python_inc
137 from distutils.sysconfig import get_python_inc
138
138
139
139
140 def write_if_changed(path, content):
140 def write_if_changed(path, content):
141 """Write content to a file iff the content hasn't changed."""
141 """Write content to a file iff the content hasn't changed."""
142 if os.path.exists(path):
142 if os.path.exists(path):
143 with open(path, 'rb') as fh:
143 with open(path, 'rb') as fh:
144 current = fh.read()
144 current = fh.read()
145 else:
145 else:
146 current = b''
146 current = b''
147
147
148 if current != content:
148 if current != content:
149 with open(path, 'wb') as fh:
149 with open(path, 'wb') as fh:
150 fh.write(content)
150 fh.write(content)
151
151
152
152
153 scripts = ['hg']
153 scripts = ['hg']
154 if os.name == 'nt':
154 if os.name == 'nt':
155 # We remove hg.bat if we are able to build hg.exe.
155 # We remove hg.bat if we are able to build hg.exe.
156 scripts.append('contrib/win32/hg.bat')
156 scripts.append('contrib/win32/hg.bat')
157
157
158
158
159 def cancompile(cc, code):
159 def cancompile(cc, code):
160 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
160 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
161 devnull = oldstderr = None
161 devnull = oldstderr = None
162 try:
162 try:
163 fname = os.path.join(tmpdir, 'testcomp.c')
163 fname = os.path.join(tmpdir, 'testcomp.c')
164 f = open(fname, 'w')
164 f = open(fname, 'w')
165 f.write(code)
165 f.write(code)
166 f.close()
166 f.close()
167 # Redirect stderr to /dev/null to hide any error messages
167 # Redirect stderr to /dev/null to hide any error messages
168 # from the compiler.
168 # from the compiler.
169 # This will have to be changed if we ever have to check
169 # This will have to be changed if we ever have to check
170 # for a function on Windows.
170 # for a function on Windows.
171 devnull = open('/dev/null', 'w')
171 devnull = open('/dev/null', 'w')
172 oldstderr = os.dup(sys.stderr.fileno())
172 oldstderr = os.dup(sys.stderr.fileno())
173 os.dup2(devnull.fileno(), sys.stderr.fileno())
173 os.dup2(devnull.fileno(), sys.stderr.fileno())
174 objects = cc.compile([fname], output_dir=tmpdir)
174 objects = cc.compile([fname], output_dir=tmpdir)
175 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
175 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
176 return True
176 return True
177 except Exception:
177 except Exception:
178 return False
178 return False
179 finally:
179 finally:
180 if oldstderr is not None:
180 if oldstderr is not None:
181 os.dup2(oldstderr, sys.stderr.fileno())
181 os.dup2(oldstderr, sys.stderr.fileno())
182 if devnull is not None:
182 if devnull is not None:
183 devnull.close()
183 devnull.close()
184 shutil.rmtree(tmpdir)
184 shutil.rmtree(tmpdir)
185
185
186
186
187 # simplified version of distutils.ccompiler.CCompiler.has_function
187 # simplified version of distutils.ccompiler.CCompiler.has_function
188 # that actually removes its temporary files.
188 # that actually removes its temporary files.
189 def hasfunction(cc, funcname):
189 def hasfunction(cc, funcname):
190 code = 'int main(void) { %s(); }\n' % funcname
190 code = 'int main(void) { %s(); }\n' % funcname
191 return cancompile(cc, code)
191 return cancompile(cc, code)
192
192
193
193
194 def hasheader(cc, headername):
194 def hasheader(cc, headername):
195 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
195 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
196 return cancompile(cc, code)
196 return cancompile(cc, code)
197
197
198
198
199 # py2exe needs to be installed to work
199 # py2exe needs to be installed to work
200 try:
200 try:
201 import py2exe
201 import py2exe
202
202
203 py2exe.patch_distutils()
203 py2exe.patch_distutils()
204 py2exeloaded = True
204 py2exeloaded = True
205 # import py2exe's patched Distribution class
205 # import py2exe's patched Distribution class
206 from distutils.core import Distribution
206 from distutils.core import Distribution
207 except ImportError:
207 except ImportError:
208 py2exeloaded = False
208 py2exeloaded = False
209
209
210
210
211 def runcmd(cmd, env, cwd=None):
211 def runcmd(cmd, env, cwd=None):
212 p = subprocess.Popen(
212 p = subprocess.Popen(
213 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, cwd=cwd
213 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, cwd=cwd
214 )
214 )
215 out, err = p.communicate()
215 out, err = p.communicate()
216 return p.returncode, out, err
216 return p.returncode, out, err
217
217
218
218
219 class hgcommand:
219 class hgcommand:
220 def __init__(self, cmd, env):
220 def __init__(self, cmd, env):
221 self.cmd = cmd
221 self.cmd = cmd
222 self.env = env
222 self.env = env
223
223
224 def run(self, args):
224 def run(self, args):
225 cmd = self.cmd + args
225 cmd = self.cmd + args
226 returncode, out, err = runcmd(cmd, self.env)
226 returncode, out, err = runcmd(cmd, self.env)
227 err = filterhgerr(err)
227 err = filterhgerr(err)
228 if err:
228 if err:
229 print("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
229 print("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
230 print(err, file=sys.stderr)
230 print(err, file=sys.stderr)
231 if returncode != 0:
231 if returncode != 0:
232 return b''
232 return b''
233 return out
233 return out
234
234
235
235
236 def filterhgerr(err):
236 def filterhgerr(err):
237 # If root is executing setup.py, but the repository is owned by
237 # If root is executing setup.py, but the repository is owned by
238 # another user (as in "sudo python setup.py install") we will get
238 # another user (as in "sudo python setup.py install") we will get
239 # trust warnings since the .hg/hgrc file is untrusted. That is
239 # trust warnings since the .hg/hgrc file is untrusted. That is
240 # fine, we don't want to load it anyway. Python may warn about
240 # fine, we don't want to load it anyway. Python may warn about
241 # a missing __init__.py in mercurial/locale, we also ignore that.
241 # a missing __init__.py in mercurial/locale, we also ignore that.
242 err = [
242 err = [
243 e
243 e
244 for e in err.splitlines()
244 for e in err.splitlines()
245 if (
245 if (
246 not e.startswith(b'not trusting file')
246 not e.startswith(b'not trusting file')
247 and not e.startswith(b'warning: Not importing')
247 and not e.startswith(b'warning: Not importing')
248 and not e.startswith(b'obsolete feature not enabled')
248 and not e.startswith(b'obsolete feature not enabled')
249 and not e.startswith(b'*** failed to import extension')
249 and not e.startswith(b'*** failed to import extension')
250 and not e.startswith(b'devel-warn:')
250 and not e.startswith(b'devel-warn:')
251 and not (
251 and not (
252 e.startswith(b'(third party extension')
252 e.startswith(b'(third party extension')
253 and e.endswith(b'or newer of Mercurial; disabling)')
253 and e.endswith(b'or newer of Mercurial; disabling)')
254 )
254 )
255 )
255 )
256 ]
256 ]
257 return b'\n'.join(b' ' + e for e in err)
257 return b'\n'.join(b' ' + e for e in err)
258
258
259
259
260 def findhg():
260 def findhg():
261 """Try to figure out how we should invoke hg for examining the local
261 """Try to figure out how we should invoke hg for examining the local
262 repository contents.
262 repository contents.
263
263
264 Returns an hgcommand object."""
264 Returns an hgcommand object."""
265 # By default, prefer the "hg" command in the user's path. This was
265 # By default, prefer the "hg" command in the user's path. This was
266 # presumably the hg command that the user used to create this repository.
266 # presumably the hg command that the user used to create this repository.
267 #
267 #
268 # This repository may require extensions or other settings that would not
268 # This repository may require extensions or other settings that would not
269 # be enabled by running the hg script directly from this local repository.
269 # be enabled by running the hg script directly from this local repository.
270 hgenv = os.environ.copy()
270 hgenv = os.environ.copy()
271 # Use HGPLAIN to disable hgrc settings that would change output formatting,
271 # Use HGPLAIN to disable hgrc settings that would change output formatting,
272 # and disable localization for the same reasons.
272 # and disable localization for the same reasons.
273 hgenv['HGPLAIN'] = '1'
273 hgenv['HGPLAIN'] = '1'
274 hgenv['LANGUAGE'] = 'C'
274 hgenv['LANGUAGE'] = 'C'
275 hgcmd = ['hg']
275 hgcmd = ['hg']
276 # Run a simple "hg log" command just to see if using hg from the user's
276 # Run a simple "hg log" command just to see if using hg from the user's
277 # path works and can successfully interact with this repository. Windows
277 # path works and can successfully interact with this repository. Windows
278 # gives precedence to hg.exe in the current directory, so fall back to the
278 # gives precedence to hg.exe in the current directory, so fall back to the
279 # python invocation of local hg, where pythonXY.dll can always be found.
279 # python invocation of local hg, where pythonXY.dll can always be found.
280 check_cmd = ['log', '-r.', '-Ttest']
280 check_cmd = ['log', '-r.', '-Ttest']
281 if os.name != 'nt' or not os.path.exists("hg.exe"):
281 attempts = []
282
283 def attempt(cmd, env):
282 try:
284 try:
283 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
285 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
284 except EnvironmentError:
286 res = (True, retcode, out, err)
285 retcode = -1
287 if retcode == 0 and not filterhgerr(err):
286 if retcode == 0 and not filterhgerr(err):
288 return True
289 except EnvironmentError as e:
290 res = (False, e)
291 attempts.append((cmd, res))
292 return False
293
294 if os.name != 'nt' or not os.path.exists("hg.exe"):
295 if attempt(hgcmd + check_cmd, hgenv):
287 return hgcommand(hgcmd, hgenv)
296 return hgcommand(hgcmd, hgenv)
288
297
289 # Fall back to trying the local hg installation.
298 # Fall back to trying the local hg installation.
290 hgenv = localhgenv()
299 hgenv = localhgenv()
291 hgcmd = [sys.executable, 'hg']
300 hgcmd = [sys.executable, 'hg']
292 try:
301 if attempt(hgcmd + check_cmd, hgenv):
293 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
294 except EnvironmentError:
295 retcode = -1
296 if retcode == 0 and not filterhgerr(err):
297 return hgcommand(hgcmd, hgenv)
302 return hgcommand(hgcmd, hgenv)
298
303
299 eprint("/!\\")
304 eprint("/!\\")
300 eprint(r"/!\ Unable to find a working hg binary")
305 eprint(r"/!\ Unable to find a working hg binary")
301 eprint(r"/!\ Version cannot be extract from the repository")
306 eprint(r"/!\ Version cannot be extracted from the repository")
302 eprint(r"/!\ Re-run the setup once a first version is built")
307 eprint(r"/!\ Re-run the setup once a first version is built")
308 eprint(r"/!\ Attempts:")
309 for i, e in enumerate(attempts):
310 eprint(r"/!\ attempt #%d:" % (i))
311 eprint(r"/!\ cmd: ", e[0])
312 res = e[1]
313 if res[0]:
314 eprint(r"/!\ return code:", res[1])
315 eprint("/!\\ std output:\n%s" % (res[2].decode()), end="")
316 eprint("/!\\ std error:\n%s" % (res[3].decode()), end="")
317 else:
318 eprint(r"/!\ exception: ", res[1])
303 return None
319 return None
304
320
305
321
306 def localhgenv():
322 def localhgenv():
307 """Get an environment dictionary to use for invoking or importing
323 """Get an environment dictionary to use for invoking or importing
308 mercurial from the local repository."""
324 mercurial from the local repository."""
309 # Execute hg out of this directory with a custom environment which takes
325 # Execute hg out of this directory with a custom environment which takes
310 # care to not use any hgrc files and do no localization.
326 # care to not use any hgrc files and do no localization.
311 env = {
327 env = {
312 'HGMODULEPOLICY': 'py',
328 'HGMODULEPOLICY': 'py',
313 'HGRCPATH': '',
329 'HGRCPATH': '',
314 'LANGUAGE': 'C',
330 'LANGUAGE': 'C',
315 'PATH': '',
331 'PATH': '',
316 } # make pypi modules that use os.environ['PATH'] happy
332 } # make pypi modules that use os.environ['PATH'] happy
317 if 'LD_LIBRARY_PATH' in os.environ:
333 if 'LD_LIBRARY_PATH' in os.environ:
318 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
334 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
319 if 'SystemRoot' in os.environ:
335 if 'SystemRoot' in os.environ:
320 # SystemRoot is required by Windows to load various DLLs. See:
336 # SystemRoot is required by Windows to load various DLLs. See:
321 # https://bugs.python.org/issue13524#msg148850
337 # https://bugs.python.org/issue13524#msg148850
322 env['SystemRoot'] = os.environ['SystemRoot']
338 env['SystemRoot'] = os.environ['SystemRoot']
323 return env
339 return env
324
340
325
341
326 version = ''
342 version = ''
327
343
328
344
329 def _try_get_version():
345 def _try_get_version():
330 hg = findhg()
346 hg = findhg()
331 if hg is None:
347 if hg is None:
332 return ''
348 return ''
333 hgid = None
349 hgid = None
334 numerictags = []
350 numerictags = []
335 cmd = ['log', '-r', '.', '--template', '{tags}\n']
351 cmd = ['log', '-r', '.', '--template', '{tags}\n']
336 pieces = sysstr(hg.run(cmd)).split()
352 pieces = sysstr(hg.run(cmd)).split()
337 numerictags = [t for t in pieces if t[0:1].isdigit()]
353 numerictags = [t for t in pieces if t[0:1].isdigit()]
338 hgid = sysstr(hg.run(['id', '-i'])).strip()
354 hgid = sysstr(hg.run(['id', '-i'])).strip()
339 if hgid.count('+') == 2:
355 if hgid.count('+') == 2:
340 hgid = hgid.replace("+", ".", 1)
356 hgid = hgid.replace("+", ".", 1)
341 if not hgid:
357 if not hgid:
342 eprint("/!\\")
358 eprint("/!\\")
343 eprint(r"/!\ Unable to determine hg version from local repository")
359 eprint(r"/!\ Unable to determine hg version from local repository")
344 eprint(r"/!\ Failed to retrieve current revision tags")
360 eprint(r"/!\ Failed to retrieve current revision tags")
345 return ''
361 return ''
346 if numerictags: # tag(s) found
362 if numerictags: # tag(s) found
347 version = numerictags[-1]
363 version = numerictags[-1]
348 if hgid.endswith('+'): # propagate the dirty status to the tag
364 if hgid.endswith('+'): # propagate the dirty status to the tag
349 version += '+'
365 version += '+'
350 else: # no tag found on the checked out revision
366 else: # no tag found on the checked out revision
351 ltagcmd = ['log', '--rev', 'wdir()', '--template', '{latesttag}']
367 ltagcmd = ['log', '--rev', 'wdir()', '--template', '{latesttag}']
352 ltag = sysstr(hg.run(ltagcmd))
368 ltag = sysstr(hg.run(ltagcmd))
353 if not ltag:
369 if not ltag:
354 eprint("/!\\")
370 eprint("/!\\")
355 eprint(r"/!\ Unable to determine hg version from local repository")
371 eprint(r"/!\ Unable to determine hg version from local repository")
356 eprint(
372 eprint(
357 r"/!\ Failed to retrieve current revision distance to lated tag"
373 r"/!\ Failed to retrieve current revision distance to lated tag"
358 )
374 )
359 return ''
375 return ''
360 changessincecmd = [
376 changessincecmd = [
361 'log',
377 'log',
362 '-T',
378 '-T',
363 'x\n',
379 'x\n',
364 '-r',
380 '-r',
365 "only(parents(),'%s')" % ltag,
381 "only(parents(),'%s')" % ltag,
366 ]
382 ]
367 changessince = len(hg.run(changessincecmd).splitlines())
383 changessince = len(hg.run(changessincecmd).splitlines())
368 version = '%s+hg%s.%s' % (ltag, changessince, hgid)
384 version = '%s+hg%s.%s' % (ltag, changessince, hgid)
369 if version.endswith('+'):
385 if version.endswith('+'):
370 version = version[:-1] + 'local' + time.strftime('%Y%m%d')
386 version = version[:-1] + 'local' + time.strftime('%Y%m%d')
371 return version
387 return version
372
388
373
389
374 if os.path.isdir('.hg'):
390 if os.path.isdir('.hg'):
375 version = _try_get_version()
391 version = _try_get_version()
376 elif os.path.exists('.hg_archival.txt'):
392 elif os.path.exists('.hg_archival.txt'):
377 kw = dict(
393 kw = dict(
378 [[t.strip() for t in l.split(':', 1)] for l in open('.hg_archival.txt')]
394 [[t.strip() for t in l.split(':', 1)] for l in open('.hg_archival.txt')]
379 )
395 )
380 if 'tag' in kw:
396 if 'tag' in kw:
381 version = kw['tag']
397 version = kw['tag']
382 elif 'latesttag' in kw:
398 elif 'latesttag' in kw:
383 if 'changessincelatesttag' in kw:
399 if 'changessincelatesttag' in kw:
384 version = (
400 version = (
385 '%(latesttag)s+hg%(changessincelatesttag)s.%(node).12s' % kw
401 '%(latesttag)s+hg%(changessincelatesttag)s.%(node).12s' % kw
386 )
402 )
387 else:
403 else:
388 version = '%(latesttag)s+hg%(latesttagdistance)s.%(node).12s' % kw
404 version = '%(latesttag)s+hg%(latesttagdistance)s.%(node).12s' % kw
389 else:
405 else:
390 version = '0+hg' + kw.get('node', '')[:12]
406 version = '0+hg' + kw.get('node', '')[:12]
391 elif os.path.exists('mercurial/__version__.py'):
407 elif os.path.exists('mercurial/__version__.py'):
392 with open('mercurial/__version__.py') as f:
408 with open('mercurial/__version__.py') as f:
393 data = f.read()
409 data = f.read()
394 version = re.search('version = b"(.*)"', data).group(1)
410 version = re.search('version = b"(.*)"', data).group(1)
395 if not version:
411 if not version:
396 if os.environ.get("MERCURIAL_SETUP_MAKE_LOCAL") == "1":
412 if os.environ.get("MERCURIAL_SETUP_MAKE_LOCAL") == "1":
397 version = "0.0+0"
413 version = "0.0+0"
398 eprint("/!\\")
414 eprint("/!\\")
399 eprint(r"/!\ Using '0.0+0' as the default version")
415 eprint(r"/!\ Using '0.0+0' as the default version")
400 eprint(r"/!\ Re-run make local once that first version is built")
416 eprint(r"/!\ Re-run make local once that first version is built")
401 eprint("/!\\")
417 eprint("/!\\")
402 else:
418 else:
403 eprint("/!\\")
419 eprint("/!\\")
404 eprint(r"/!\ Could not determine the Mercurial version")
420 eprint(r"/!\ Could not determine the Mercurial version")
405 eprint(r"/!\ You need to build a local version first")
421 eprint(r"/!\ You need to build a local version first")
406 eprint(r"/!\ Run `make local` and try again")
422 eprint(r"/!\ Run `make local` and try again")
407 eprint("/!\\")
423 eprint("/!\\")
408 msg = "Run `make local` first to get a working local version"
424 msg = "Run `make local` first to get a working local version"
409 raise SystemExit(msg)
425 raise SystemExit(msg)
410
426
411 versionb = version
427 versionb = version
412 if not isinstance(versionb, bytes):
428 if not isinstance(versionb, bytes):
413 versionb = versionb.encode('ascii')
429 versionb = versionb.encode('ascii')
414
430
415 write_if_changed(
431 write_if_changed(
416 'mercurial/__version__.py',
432 'mercurial/__version__.py',
417 b''.join(
433 b''.join(
418 [
434 [
419 b'# this file is autogenerated by setup.py\n'
435 b'# this file is autogenerated by setup.py\n'
420 b'version = b"%s"\n' % versionb,
436 b'version = b"%s"\n' % versionb,
421 ]
437 ]
422 ),
438 ),
423 )
439 )
424
440
425
441
426 class hgbuild(build):
442 class hgbuild(build):
427 # Insert hgbuildmo first so that files in mercurial/locale/ are found
443 # Insert hgbuildmo first so that files in mercurial/locale/ are found
428 # when build_py is run next.
444 # when build_py is run next.
429 sub_commands = [('build_mo', None)] + build.sub_commands
445 sub_commands = [('build_mo', None)] + build.sub_commands
430
446
431
447
432 class hgbuildmo(build):
448 class hgbuildmo(build):
433
449
434 description = "build translations (.mo files)"
450 description = "build translations (.mo files)"
435
451
436 def run(self):
452 def run(self):
437 if not find_executable('msgfmt'):
453 if not find_executable('msgfmt'):
438 self.warn(
454 self.warn(
439 "could not find msgfmt executable, no translations "
455 "could not find msgfmt executable, no translations "
440 "will be built"
456 "will be built"
441 )
457 )
442 return
458 return
443
459
444 podir = 'i18n'
460 podir = 'i18n'
445 if not os.path.isdir(podir):
461 if not os.path.isdir(podir):
446 self.warn("could not find %s/ directory" % podir)
462 self.warn("could not find %s/ directory" % podir)
447 return
463 return
448
464
449 join = os.path.join
465 join = os.path.join
450 for po in os.listdir(podir):
466 for po in os.listdir(podir):
451 if not po.endswith('.po'):
467 if not po.endswith('.po'):
452 continue
468 continue
453 pofile = join(podir, po)
469 pofile = join(podir, po)
454 modir = join('locale', po[:-3], 'LC_MESSAGES')
470 modir = join('locale', po[:-3], 'LC_MESSAGES')
455 mofile = join(modir, 'hg.mo')
471 mofile = join(modir, 'hg.mo')
456 mobuildfile = join('mercurial', mofile)
472 mobuildfile = join('mercurial', mofile)
457 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
473 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
458 if sys.platform != 'sunos5':
474 if sys.platform != 'sunos5':
459 # msgfmt on Solaris does not know about -c
475 # msgfmt on Solaris does not know about -c
460 cmd.append('-c')
476 cmd.append('-c')
461 self.mkpath(join('mercurial', modir))
477 self.mkpath(join('mercurial', modir))
462 self.make_file([pofile], mobuildfile, spawn, (cmd,))
478 self.make_file([pofile], mobuildfile, spawn, (cmd,))
463
479
464
480
465 class hgdist(Distribution):
481 class hgdist(Distribution):
466 pure = False
482 pure = False
467 rust = False
483 rust = False
468 no_rust = False
484 no_rust = False
469 cffi = ispypy
485 cffi = ispypy
470
486
471 global_options = Distribution.global_options + [
487 global_options = Distribution.global_options + [
472 ('pure', None, "use pure (slow) Python code instead of C extensions"),
488 ('pure', None, "use pure (slow) Python code instead of C extensions"),
473 ('rust', None, "use Rust extensions additionally to C extensions"),
489 ('rust', None, "use Rust extensions additionally to C extensions"),
474 (
490 (
475 'no-rust',
491 'no-rust',
476 None,
492 None,
477 "do not use Rust extensions additionally to C extensions",
493 "do not use Rust extensions additionally to C extensions",
478 ),
494 ),
479 ]
495 ]
480
496
481 negative_opt = Distribution.negative_opt.copy()
497 negative_opt = Distribution.negative_opt.copy()
482 boolean_options = ['pure', 'rust', 'no-rust']
498 boolean_options = ['pure', 'rust', 'no-rust']
483 negative_opt['no-rust'] = 'rust'
499 negative_opt['no-rust'] = 'rust'
484
500
485 def _set_command_options(self, command_obj, option_dict=None):
501 def _set_command_options(self, command_obj, option_dict=None):
486 # Not all distutils versions in the wild have boolean_options.
502 # Not all distutils versions in the wild have boolean_options.
487 # This should be cleaned up when we're Python 3 only.
503 # This should be cleaned up when we're Python 3 only.
488 command_obj.boolean_options = (
504 command_obj.boolean_options = (
489 getattr(command_obj, 'boolean_options', []) + self.boolean_options
505 getattr(command_obj, 'boolean_options', []) + self.boolean_options
490 )
506 )
491 return Distribution._set_command_options(
507 return Distribution._set_command_options(
492 self, command_obj, option_dict=option_dict
508 self, command_obj, option_dict=option_dict
493 )
509 )
494
510
495 def parse_command_line(self):
511 def parse_command_line(self):
496 ret = Distribution.parse_command_line(self)
512 ret = Distribution.parse_command_line(self)
497 if not (self.rust or self.no_rust):
513 if not (self.rust or self.no_rust):
498 hgrustext = os.environ.get('HGWITHRUSTEXT')
514 hgrustext = os.environ.get('HGWITHRUSTEXT')
499 # TODO record it for proper rebuild upon changes
515 # TODO record it for proper rebuild upon changes
500 # (see mercurial/__modulepolicy__.py)
516 # (see mercurial/__modulepolicy__.py)
501 if hgrustext != 'cpython' and hgrustext is not None:
517 if hgrustext != 'cpython' and hgrustext is not None:
502 if hgrustext:
518 if hgrustext:
503 msg = 'unknown HGWITHRUSTEXT value: %s' % hgrustext
519 msg = 'unknown HGWITHRUSTEXT value: %s' % hgrustext
504 print(msg, file=sys.stderr)
520 print(msg, file=sys.stderr)
505 hgrustext = None
521 hgrustext = None
506 self.rust = hgrustext is not None
522 self.rust = hgrustext is not None
507 self.no_rust = not self.rust
523 self.no_rust = not self.rust
508 return ret
524 return ret
509
525
510 def has_ext_modules(self):
526 def has_ext_modules(self):
511 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
527 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
512 # too late for some cases
528 # too late for some cases
513 return not self.pure and Distribution.has_ext_modules(self)
529 return not self.pure and Distribution.has_ext_modules(self)
514
530
515
531
516 # This is ugly as a one-liner. So use a variable.
532 # This is ugly as a one-liner. So use a variable.
517 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
533 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
518 buildextnegops['no-zstd'] = 'zstd'
534 buildextnegops['no-zstd'] = 'zstd'
519 buildextnegops['no-rust'] = 'rust'
535 buildextnegops['no-rust'] = 'rust'
520
536
521
537
522 class hgbuildext(build_ext):
538 class hgbuildext(build_ext):
523 user_options = build_ext.user_options + [
539 user_options = build_ext.user_options + [
524 ('zstd', None, 'compile zstd bindings [default]'),
540 ('zstd', None, 'compile zstd bindings [default]'),
525 ('no-zstd', None, 'do not compile zstd bindings'),
541 ('no-zstd', None, 'do not compile zstd bindings'),
526 (
542 (
527 'rust',
543 'rust',
528 None,
544 None,
529 'compile Rust extensions if they are in use '
545 'compile Rust extensions if they are in use '
530 '(requires Cargo) [default]',
546 '(requires Cargo) [default]',
531 ),
547 ),
532 ('no-rust', None, 'do not compile Rust extensions'),
548 ('no-rust', None, 'do not compile Rust extensions'),
533 ]
549 ]
534
550
535 boolean_options = build_ext.boolean_options + ['zstd', 'rust']
551 boolean_options = build_ext.boolean_options + ['zstd', 'rust']
536 negative_opt = buildextnegops
552 negative_opt = buildextnegops
537
553
538 def initialize_options(self):
554 def initialize_options(self):
539 self.zstd = True
555 self.zstd = True
540 self.rust = True
556 self.rust = True
541
557
542 return build_ext.initialize_options(self)
558 return build_ext.initialize_options(self)
543
559
544 def finalize_options(self):
560 def finalize_options(self):
545 # Unless overridden by the end user, build extensions in parallel.
561 # Unless overridden by the end user, build extensions in parallel.
546 # Only influences behavior on Python 3.5+.
562 # Only influences behavior on Python 3.5+.
547 if getattr(self, 'parallel', None) is None:
563 if getattr(self, 'parallel', None) is None:
548 self.parallel = True
564 self.parallel = True
549
565
550 return build_ext.finalize_options(self)
566 return build_ext.finalize_options(self)
551
567
552 def build_extensions(self):
568 def build_extensions(self):
553 ruststandalones = [
569 ruststandalones = [
554 e for e in self.extensions if isinstance(e, RustStandaloneExtension)
570 e for e in self.extensions if isinstance(e, RustStandaloneExtension)
555 ]
571 ]
556 self.extensions = [
572 self.extensions = [
557 e for e in self.extensions if e not in ruststandalones
573 e for e in self.extensions if e not in ruststandalones
558 ]
574 ]
559 # Filter out zstd if disabled via argument.
575 # Filter out zstd if disabled via argument.
560 if not self.zstd:
576 if not self.zstd:
561 self.extensions = [
577 self.extensions = [
562 e for e in self.extensions if e.name != 'mercurial.zstd'
578 e for e in self.extensions if e.name != 'mercurial.zstd'
563 ]
579 ]
564
580
565 # Build Rust standalone extensions if it'll be used
581 # Build Rust standalone extensions if it'll be used
566 # and its build is not explicitly disabled (for external build
582 # and its build is not explicitly disabled (for external build
567 # as Linux distributions would do)
583 # as Linux distributions would do)
568 if self.distribution.rust and self.rust:
584 if self.distribution.rust and self.rust:
569 if not sys.platform.startswith('linux'):
585 if not sys.platform.startswith('linux'):
570 self.warn(
586 self.warn(
571 "rust extensions have only been tested on Linux "
587 "rust extensions have only been tested on Linux "
572 "and may not behave correctly on other platforms"
588 "and may not behave correctly on other platforms"
573 )
589 )
574
590
575 for rustext in ruststandalones:
591 for rustext in ruststandalones:
576 rustext.build('' if self.inplace else self.build_lib)
592 rustext.build('' if self.inplace else self.build_lib)
577
593
578 return build_ext.build_extensions(self)
594 return build_ext.build_extensions(self)
579
595
580 def build_extension(self, ext):
596 def build_extension(self, ext):
581 if (
597 if (
582 self.distribution.rust
598 self.distribution.rust
583 and self.rust
599 and self.rust
584 and isinstance(ext, RustExtension)
600 and isinstance(ext, RustExtension)
585 ):
601 ):
586 ext.rustbuild()
602 ext.rustbuild()
587 try:
603 try:
588 build_ext.build_extension(self, ext)
604 build_ext.build_extension(self, ext)
589 except CCompilerError:
605 except CCompilerError:
590 if not getattr(ext, 'optional', False):
606 if not getattr(ext, 'optional', False):
591 raise
607 raise
592 log.warn(
608 log.warn(
593 "Failed to build optional extension '%s' (skipping)", ext.name
609 "Failed to build optional extension '%s' (skipping)", ext.name
594 )
610 )
595
611
596
612
597 class hgbuildscripts(build_scripts):
613 class hgbuildscripts(build_scripts):
598 def run(self):
614 def run(self):
599 if os.name != 'nt' or self.distribution.pure:
615 if os.name != 'nt' or self.distribution.pure:
600 return build_scripts.run(self)
616 return build_scripts.run(self)
601
617
602 exebuilt = False
618 exebuilt = False
603 try:
619 try:
604 self.run_command('build_hgexe')
620 self.run_command('build_hgexe')
605 exebuilt = True
621 exebuilt = True
606 except (DistutilsError, CCompilerError):
622 except (DistutilsError, CCompilerError):
607 log.warn('failed to build optional hg.exe')
623 log.warn('failed to build optional hg.exe')
608
624
609 if exebuilt:
625 if exebuilt:
610 # Copying hg.exe to the scripts build directory ensures it is
626 # Copying hg.exe to the scripts build directory ensures it is
611 # installed by the install_scripts command.
627 # installed by the install_scripts command.
612 hgexecommand = self.get_finalized_command('build_hgexe')
628 hgexecommand = self.get_finalized_command('build_hgexe')
613 dest = os.path.join(self.build_dir, 'hg.exe')
629 dest = os.path.join(self.build_dir, 'hg.exe')
614 self.mkpath(self.build_dir)
630 self.mkpath(self.build_dir)
615 self.copy_file(hgexecommand.hgexepath, dest)
631 self.copy_file(hgexecommand.hgexepath, dest)
616
632
617 # Remove hg.bat because it is redundant with hg.exe.
633 # Remove hg.bat because it is redundant with hg.exe.
618 self.scripts.remove('contrib/win32/hg.bat')
634 self.scripts.remove('contrib/win32/hg.bat')
619
635
620 return build_scripts.run(self)
636 return build_scripts.run(self)
621
637
622
638
623 class hgbuildpy(build_py):
639 class hgbuildpy(build_py):
624 def finalize_options(self):
640 def finalize_options(self):
625 build_py.finalize_options(self)
641 build_py.finalize_options(self)
626
642
627 if self.distribution.pure:
643 if self.distribution.pure:
628 self.distribution.ext_modules = []
644 self.distribution.ext_modules = []
629 elif self.distribution.cffi:
645 elif self.distribution.cffi:
630 from mercurial.cffi import (
646 from mercurial.cffi import (
631 bdiffbuild,
647 bdiffbuild,
632 mpatchbuild,
648 mpatchbuild,
633 )
649 )
634
650
635 exts = [
651 exts = [
636 mpatchbuild.ffi.distutils_extension(),
652 mpatchbuild.ffi.distutils_extension(),
637 bdiffbuild.ffi.distutils_extension(),
653 bdiffbuild.ffi.distutils_extension(),
638 ]
654 ]
639 # cffi modules go here
655 # cffi modules go here
640 if sys.platform == 'darwin':
656 if sys.platform == 'darwin':
641 from mercurial.cffi import osutilbuild
657 from mercurial.cffi import osutilbuild
642
658
643 exts.append(osutilbuild.ffi.distutils_extension())
659 exts.append(osutilbuild.ffi.distutils_extension())
644 self.distribution.ext_modules = exts
660 self.distribution.ext_modules = exts
645 else:
661 else:
646 h = os.path.join(get_python_inc(), 'Python.h')
662 h = os.path.join(get_python_inc(), 'Python.h')
647 if not os.path.exists(h):
663 if not os.path.exists(h):
648 raise SystemExit(
664 raise SystemExit(
649 'Python headers are required to build '
665 'Python headers are required to build '
650 'Mercurial but weren\'t found in %s' % h
666 'Mercurial but weren\'t found in %s' % h
651 )
667 )
652
668
653 def run(self):
669 def run(self):
654 basepath = os.path.join(self.build_lib, 'mercurial')
670 basepath = os.path.join(self.build_lib, 'mercurial')
655 self.mkpath(basepath)
671 self.mkpath(basepath)
656
672
657 rust = self.distribution.rust
673 rust = self.distribution.rust
658 if self.distribution.pure:
674 if self.distribution.pure:
659 modulepolicy = 'py'
675 modulepolicy = 'py'
660 elif self.build_lib == '.':
676 elif self.build_lib == '.':
661 # in-place build should run without rebuilding and Rust extensions
677 # in-place build should run without rebuilding and Rust extensions
662 modulepolicy = 'rust+c-allow' if rust else 'allow'
678 modulepolicy = 'rust+c-allow' if rust else 'allow'
663 else:
679 else:
664 modulepolicy = 'rust+c' if rust else 'c'
680 modulepolicy = 'rust+c' if rust else 'c'
665
681
666 content = b''.join(
682 content = b''.join(
667 [
683 [
668 b'# this file is autogenerated by setup.py\n',
684 b'# this file is autogenerated by setup.py\n',
669 b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
685 b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
670 ]
686 ]
671 )
687 )
672 write_if_changed(os.path.join(basepath, '__modulepolicy__.py'), content)
688 write_if_changed(os.path.join(basepath, '__modulepolicy__.py'), content)
673
689
674 build_py.run(self)
690 build_py.run(self)
675
691
676
692
677 class buildhgextindex(Command):
693 class buildhgextindex(Command):
678 description = 'generate prebuilt index of hgext (for frozen package)'
694 description = 'generate prebuilt index of hgext (for frozen package)'
679 user_options = []
695 user_options = []
680 _indexfilename = 'hgext/__index__.py'
696 _indexfilename = 'hgext/__index__.py'
681
697
682 def initialize_options(self):
698 def initialize_options(self):
683 pass
699 pass
684
700
685 def finalize_options(self):
701 def finalize_options(self):
686 pass
702 pass
687
703
688 def run(self):
704 def run(self):
689 if os.path.exists(self._indexfilename):
705 if os.path.exists(self._indexfilename):
690 with open(self._indexfilename, 'w') as f:
706 with open(self._indexfilename, 'w') as f:
691 f.write('# empty\n')
707 f.write('# empty\n')
692
708
693 # here no extension enabled, disabled() lists up everything
709 # here no extension enabled, disabled() lists up everything
694 code = (
710 code = (
695 'import pprint; from mercurial import extensions; '
711 'import pprint; from mercurial import extensions; '
696 'ext = extensions.disabled();'
712 'ext = extensions.disabled();'
697 'ext.pop("__index__", None);'
713 'ext.pop("__index__", None);'
698 'pprint.pprint(ext)'
714 'pprint.pprint(ext)'
699 )
715 )
700 returncode, out, err = runcmd(
716 returncode, out, err = runcmd(
701 [sys.executable, '-c', code], localhgenv()
717 [sys.executable, '-c', code], localhgenv()
702 )
718 )
703 if err or returncode != 0:
719 if err or returncode != 0:
704 raise DistutilsExecError(err)
720 raise DistutilsExecError(err)
705
721
706 with open(self._indexfilename, 'wb') as f:
722 with open(self._indexfilename, 'wb') as f:
707 f.write(b'# this file is autogenerated by setup.py\n')
723 f.write(b'# this file is autogenerated by setup.py\n')
708 f.write(b'docs = ')
724 f.write(b'docs = ')
709 f.write(out)
725 f.write(out)
710
726
711
727
712 class buildhgexe(build_ext):
728 class buildhgexe(build_ext):
713 description = 'compile hg.exe from mercurial/exewrapper.c'
729 description = 'compile hg.exe from mercurial/exewrapper.c'
714
730
715 LONG_PATHS_MANIFEST = """\
731 LONG_PATHS_MANIFEST = """\
716 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
732 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
717 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
733 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
718 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
734 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
719 <security>
735 <security>
720 <requestedPrivileges>
736 <requestedPrivileges>
721 <requestedExecutionLevel
737 <requestedExecutionLevel
722 level="asInvoker"
738 level="asInvoker"
723 uiAccess="false"
739 uiAccess="false"
724 />
740 />
725 </requestedPrivileges>
741 </requestedPrivileges>
726 </security>
742 </security>
727 </trustInfo>
743 </trustInfo>
728 <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
744 <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
729 <application>
745 <application>
730 <!-- Windows Vista -->
746 <!-- Windows Vista -->
731 <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
747 <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
732 <!-- Windows 7 -->
748 <!-- Windows 7 -->
733 <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
749 <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
734 <!-- Windows 8 -->
750 <!-- Windows 8 -->
735 <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
751 <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
736 <!-- Windows 8.1 -->
752 <!-- Windows 8.1 -->
737 <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
753 <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
738 <!-- Windows 10 and Windows 11 -->
754 <!-- Windows 10 and Windows 11 -->
739 <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
755 <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
740 </application>
756 </application>
741 </compatibility>
757 </compatibility>
742 <application xmlns="urn:schemas-microsoft-com:asm.v3">
758 <application xmlns="urn:schemas-microsoft-com:asm.v3">
743 <windowsSettings
759 <windowsSettings
744 xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
760 xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
745 <ws2:longPathAware>true</ws2:longPathAware>
761 <ws2:longPathAware>true</ws2:longPathAware>
746 </windowsSettings>
762 </windowsSettings>
747 </application>
763 </application>
748 <dependency>
764 <dependency>
749 <dependentAssembly>
765 <dependentAssembly>
750 <assemblyIdentity type="win32"
766 <assemblyIdentity type="win32"
751 name="Microsoft.Windows.Common-Controls"
767 name="Microsoft.Windows.Common-Controls"
752 version="6.0.0.0"
768 version="6.0.0.0"
753 processorArchitecture="*"
769 processorArchitecture="*"
754 publicKeyToken="6595b64144ccf1df"
770 publicKeyToken="6595b64144ccf1df"
755 language="*" />
771 language="*" />
756 </dependentAssembly>
772 </dependentAssembly>
757 </dependency>
773 </dependency>
758 </assembly>
774 </assembly>
759 """
775 """
760
776
761 def initialize_options(self):
777 def initialize_options(self):
762 build_ext.initialize_options(self)
778 build_ext.initialize_options(self)
763
779
764 def build_extensions(self):
780 def build_extensions(self):
765 if os.name != 'nt':
781 if os.name != 'nt':
766 return
782 return
767 if isinstance(self.compiler, HackedMingw32CCompiler):
783 if isinstance(self.compiler, HackedMingw32CCompiler):
768 self.compiler.compiler_so = self.compiler.compiler # no -mdll
784 self.compiler.compiler_so = self.compiler.compiler # no -mdll
769 self.compiler.dll_libraries = [] # no -lmsrvc90
785 self.compiler.dll_libraries = [] # no -lmsrvc90
770
786
771 pythonlib = None
787 pythonlib = None
772
788
773 dirname = os.path.dirname(self.get_ext_fullpath('dummy'))
789 dirname = os.path.dirname(self.get_ext_fullpath('dummy'))
774 self.hgtarget = os.path.join(dirname, 'hg')
790 self.hgtarget = os.path.join(dirname, 'hg')
775
791
776 if getattr(sys, 'dllhandle', None):
792 if getattr(sys, 'dllhandle', None):
777 # Different Python installs can have different Python library
793 # Different Python installs can have different Python library
778 # names. e.g. the official CPython distribution uses pythonXY.dll
794 # names. e.g. the official CPython distribution uses pythonXY.dll
779 # and MinGW uses libpythonX.Y.dll.
795 # and MinGW uses libpythonX.Y.dll.
780 _kernel32 = ctypes.windll.kernel32
796 _kernel32 = ctypes.windll.kernel32
781 _kernel32.GetModuleFileNameA.argtypes = [
797 _kernel32.GetModuleFileNameA.argtypes = [
782 ctypes.c_void_p,
798 ctypes.c_void_p,
783 ctypes.c_void_p,
799 ctypes.c_void_p,
784 ctypes.c_ulong,
800 ctypes.c_ulong,
785 ]
801 ]
786 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
802 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
787 size = 1000
803 size = 1000
788 buf = ctypes.create_string_buffer(size + 1)
804 buf = ctypes.create_string_buffer(size + 1)
789 filelen = _kernel32.GetModuleFileNameA(
805 filelen = _kernel32.GetModuleFileNameA(
790 sys.dllhandle, ctypes.byref(buf), size
806 sys.dllhandle, ctypes.byref(buf), size
791 )
807 )
792
808
793 if filelen > 0 and filelen != size:
809 if filelen > 0 and filelen != size:
794 dllbasename = os.path.basename(buf.value)
810 dllbasename = os.path.basename(buf.value)
795 if not dllbasename.lower().endswith(b'.dll'):
811 if not dllbasename.lower().endswith(b'.dll'):
796 raise SystemExit(
812 raise SystemExit(
797 'Python DLL does not end with .dll: %s' % dllbasename
813 'Python DLL does not end with .dll: %s' % dllbasename
798 )
814 )
799 pythonlib = dllbasename[:-4]
815 pythonlib = dllbasename[:-4]
800
816
801 # Copy the pythonXY.dll next to the binary so that it runs
817 # Copy the pythonXY.dll next to the binary so that it runs
802 # without tampering with PATH.
818 # without tampering with PATH.
803 dest = os.path.join(
819 dest = os.path.join(
804 os.path.dirname(self.hgtarget),
820 os.path.dirname(self.hgtarget),
805 os.fsdecode(dllbasename),
821 os.fsdecode(dllbasename),
806 )
822 )
807
823
808 if not os.path.exists(dest):
824 if not os.path.exists(dest):
809 shutil.copy(buf.value, dest)
825 shutil.copy(buf.value, dest)
810
826
811 # Also overwrite python3.dll so that hgext.git is usable.
827 # Also overwrite python3.dll so that hgext.git is usable.
812 # TODO: also handle the MSYS flavor
828 # TODO: also handle the MSYS flavor
813 python_x = os.path.join(
829 python_x = os.path.join(
814 os.path.dirname(os.fsdecode(buf.value)),
830 os.path.dirname(os.fsdecode(buf.value)),
815 "python3.dll",
831 "python3.dll",
816 )
832 )
817
833
818 if os.path.exists(python_x):
834 if os.path.exists(python_x):
819 dest = os.path.join(
835 dest = os.path.join(
820 os.path.dirname(self.hgtarget),
836 os.path.dirname(self.hgtarget),
821 os.path.basename(python_x),
837 os.path.basename(python_x),
822 )
838 )
823
839
824 shutil.copy(python_x, dest)
840 shutil.copy(python_x, dest)
825
841
826 if not pythonlib:
842 if not pythonlib:
827 log.warn(
843 log.warn(
828 'could not determine Python DLL filename; assuming pythonXY'
844 'could not determine Python DLL filename; assuming pythonXY'
829 )
845 )
830
846
831 hv = sys.hexversion
847 hv = sys.hexversion
832 pythonlib = b'python%d%d' % (hv >> 24, (hv >> 16) & 0xFF)
848 pythonlib = b'python%d%d' % (hv >> 24, (hv >> 16) & 0xFF)
833
849
834 log.info('using %s as Python library name' % pythonlib)
850 log.info('using %s as Python library name' % pythonlib)
835 with open('mercurial/hgpythonlib.h', 'wb') as f:
851 with open('mercurial/hgpythonlib.h', 'wb') as f:
836 f.write(b'/* this file is autogenerated by setup.py */\n')
852 f.write(b'/* this file is autogenerated by setup.py */\n')
837 f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib)
853 f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib)
838
854
839 objects = self.compiler.compile(
855 objects = self.compiler.compile(
840 ['mercurial/exewrapper.c'],
856 ['mercurial/exewrapper.c'],
841 output_dir=self.build_temp,
857 output_dir=self.build_temp,
842 macros=[('_UNICODE', None), ('UNICODE', None)],
858 macros=[('_UNICODE', None), ('UNICODE', None)],
843 )
859 )
844 self.compiler.link_executable(
860 self.compiler.link_executable(
845 objects, self.hgtarget, libraries=[], output_dir=self.build_temp
861 objects, self.hgtarget, libraries=[], output_dir=self.build_temp
846 )
862 )
847
863
848 self.addlongpathsmanifest()
864 self.addlongpathsmanifest()
849
865
850 def addlongpathsmanifest(self):
866 def addlongpathsmanifest(self):
851 """Add manifest pieces so that hg.exe understands long paths
867 """Add manifest pieces so that hg.exe understands long paths
852
868
853 Why resource #1 should be used for .exe manifests? I don't know and
869 Why resource #1 should be used for .exe manifests? I don't know and
854 wasn't able to find an explanation for mortals. But it seems to work.
870 wasn't able to find an explanation for mortals. But it seems to work.
855 """
871 """
856 exefname = self.compiler.executable_filename(self.hgtarget)
872 exefname = self.compiler.executable_filename(self.hgtarget)
857 fdauto, manfname = tempfile.mkstemp(suffix='.hg.exe.manifest')
873 fdauto, manfname = tempfile.mkstemp(suffix='.hg.exe.manifest')
858 os.close(fdauto)
874 os.close(fdauto)
859 with open(manfname, 'w', encoding="UTF-8") as f:
875 with open(manfname, 'w', encoding="UTF-8") as f:
860 f.write(self.LONG_PATHS_MANIFEST)
876 f.write(self.LONG_PATHS_MANIFEST)
861 log.info("long paths manifest is written to '%s'" % manfname)
877 log.info("long paths manifest is written to '%s'" % manfname)
862 outputresource = '-outputresource:%s;#1' % exefname
878 outputresource = '-outputresource:%s;#1' % exefname
863 log.info("running mt.exe to update hg.exe's manifest in-place")
879 log.info("running mt.exe to update hg.exe's manifest in-place")
864
880
865 self.spawn(
881 self.spawn(
866 [
882 [
867 self.compiler.mt,
883 self.compiler.mt,
868 '-nologo',
884 '-nologo',
869 '-manifest',
885 '-manifest',
870 manfname,
886 manfname,
871 outputresource,
887 outputresource,
872 ]
888 ]
873 )
889 )
874 log.info("done updating hg.exe's manifest")
890 log.info("done updating hg.exe's manifest")
875 os.remove(manfname)
891 os.remove(manfname)
876
892
877 @property
893 @property
878 def hgexepath(self):
894 def hgexepath(self):
879 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
895 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
880 return os.path.join(self.build_temp, dir, 'hg.exe')
896 return os.path.join(self.build_temp, dir, 'hg.exe')
881
897
882
898
883 class hgbuilddoc(Command):
899 class hgbuilddoc(Command):
884 description = 'build documentation'
900 description = 'build documentation'
885 user_options = [
901 user_options = [
886 ('man', None, 'generate man pages'),
902 ('man', None, 'generate man pages'),
887 ('html', None, 'generate html pages'),
903 ('html', None, 'generate html pages'),
888 ]
904 ]
889
905
890 def initialize_options(self):
906 def initialize_options(self):
891 self.man = None
907 self.man = None
892 self.html = None
908 self.html = None
893
909
894 def finalize_options(self):
910 def finalize_options(self):
895 # If --man or --html are set, only generate what we're told to.
911 # If --man or --html are set, only generate what we're told to.
896 # Otherwise generate everything.
912 # Otherwise generate everything.
897 have_subset = self.man is not None or self.html is not None
913 have_subset = self.man is not None or self.html is not None
898
914
899 if have_subset:
915 if have_subset:
900 self.man = True if self.man else False
916 self.man = True if self.man else False
901 self.html = True if self.html else False
917 self.html = True if self.html else False
902 else:
918 else:
903 self.man = True
919 self.man = True
904 self.html = True
920 self.html = True
905
921
906 def run(self):
922 def run(self):
907 def normalizecrlf(p):
923 def normalizecrlf(p):
908 with open(p, 'rb') as fh:
924 with open(p, 'rb') as fh:
909 orig = fh.read()
925 orig = fh.read()
910
926
911 if b'\r\n' not in orig:
927 if b'\r\n' not in orig:
912 return
928 return
913
929
914 log.info('normalizing %s to LF line endings' % p)
930 log.info('normalizing %s to LF line endings' % p)
915 with open(p, 'wb') as fh:
931 with open(p, 'wb') as fh:
916 fh.write(orig.replace(b'\r\n', b'\n'))
932 fh.write(orig.replace(b'\r\n', b'\n'))
917
933
918 def gentxt(root):
934 def gentxt(root):
919 txt = 'doc/%s.txt' % root
935 txt = 'doc/%s.txt' % root
920 log.info('generating %s' % txt)
936 log.info('generating %s' % txt)
921 res, out, err = runcmd(
937 res, out, err = runcmd(
922 [sys.executable, 'gendoc.py', root], os.environ, cwd='doc'
938 [sys.executable, 'gendoc.py', root], os.environ, cwd='doc'
923 )
939 )
924 if res:
940 if res:
925 raise SystemExit(
941 raise SystemExit(
926 'error running gendoc.py: %s'
942 'error running gendoc.py: %s'
927 % '\n'.join([sysstr(out), sysstr(err)])
943 % '\n'.join([sysstr(out), sysstr(err)])
928 )
944 )
929
945
930 with open(txt, 'wb') as fh:
946 with open(txt, 'wb') as fh:
931 fh.write(out)
947 fh.write(out)
932
948
933 def gengendoc(root):
949 def gengendoc(root):
934 gendoc = 'doc/%s.gendoc.txt' % root
950 gendoc = 'doc/%s.gendoc.txt' % root
935
951
936 log.info('generating %s' % gendoc)
952 log.info('generating %s' % gendoc)
937 res, out, err = runcmd(
953 res, out, err = runcmd(
938 [sys.executable, 'gendoc.py', '%s.gendoc' % root],
954 [sys.executable, 'gendoc.py', '%s.gendoc' % root],
939 os.environ,
955 os.environ,
940 cwd='doc',
956 cwd='doc',
941 )
957 )
942 if res:
958 if res:
943 raise SystemExit(
959 raise SystemExit(
944 'error running gendoc: %s'
960 'error running gendoc: %s'
945 % '\n'.join([sysstr(out), sysstr(err)])
961 % '\n'.join([sysstr(out), sysstr(err)])
946 )
962 )
947
963
948 with open(gendoc, 'wb') as fh:
964 with open(gendoc, 'wb') as fh:
949 fh.write(out)
965 fh.write(out)
950
966
951 def genman(root):
967 def genman(root):
952 log.info('generating doc/%s' % root)
968 log.info('generating doc/%s' % root)
953 res, out, err = runcmd(
969 res, out, err = runcmd(
954 [
970 [
955 sys.executable,
971 sys.executable,
956 'runrst',
972 'runrst',
957 'hgmanpage',
973 'hgmanpage',
958 '--halt',
974 '--halt',
959 'warning',
975 'warning',
960 '--strip-elements-with-class',
976 '--strip-elements-with-class',
961 'htmlonly',
977 'htmlonly',
962 '%s.txt' % root,
978 '%s.txt' % root,
963 root,
979 root,
964 ],
980 ],
965 os.environ,
981 os.environ,
966 cwd='doc',
982 cwd='doc',
967 )
983 )
968 if res:
984 if res:
969 raise SystemExit(
985 raise SystemExit(
970 'error running runrst: %s'
986 'error running runrst: %s'
971 % '\n'.join([sysstr(out), sysstr(err)])
987 % '\n'.join([sysstr(out), sysstr(err)])
972 )
988 )
973
989
974 normalizecrlf('doc/%s' % root)
990 normalizecrlf('doc/%s' % root)
975
991
976 def genhtml(root):
992 def genhtml(root):
977 log.info('generating doc/%s.html' % root)
993 log.info('generating doc/%s.html' % root)
978 res, out, err = runcmd(
994 res, out, err = runcmd(
979 [
995 [
980 sys.executable,
996 sys.executable,
981 'runrst',
997 'runrst',
982 'html',
998 'html',
983 '--halt',
999 '--halt',
984 'warning',
1000 'warning',
985 '--link-stylesheet',
1001 '--link-stylesheet',
986 '--stylesheet-path',
1002 '--stylesheet-path',
987 'style.css',
1003 'style.css',
988 '%s.txt' % root,
1004 '%s.txt' % root,
989 '%s.html' % root,
1005 '%s.html' % root,
990 ],
1006 ],
991 os.environ,
1007 os.environ,
992 cwd='doc',
1008 cwd='doc',
993 )
1009 )
994 if res:
1010 if res:
995 raise SystemExit(
1011 raise SystemExit(
996 'error running runrst: %s'
1012 'error running runrst: %s'
997 % '\n'.join([sysstr(out), sysstr(err)])
1013 % '\n'.join([sysstr(out), sysstr(err)])
998 )
1014 )
999
1015
1000 normalizecrlf('doc/%s.html' % root)
1016 normalizecrlf('doc/%s.html' % root)
1001
1017
1002 # This logic is duplicated in doc/Makefile.
1018 # This logic is duplicated in doc/Makefile.
1003 sources = {
1019 sources = {
1004 f
1020 f
1005 for f in os.listdir('mercurial/helptext')
1021 for f in os.listdir('mercurial/helptext')
1006 if re.search(r'[0-9]\.txt$', f)
1022 if re.search(r'[0-9]\.txt$', f)
1007 }
1023 }
1008
1024
1009 # common.txt is a one-off.
1025 # common.txt is a one-off.
1010 gentxt('common')
1026 gentxt('common')
1011
1027
1012 for source in sorted(sources):
1028 for source in sorted(sources):
1013 assert source[-4:] == '.txt'
1029 assert source[-4:] == '.txt'
1014 root = source[:-4]
1030 root = source[:-4]
1015
1031
1016 gentxt(root)
1032 gentxt(root)
1017 gengendoc(root)
1033 gengendoc(root)
1018
1034
1019 if self.man:
1035 if self.man:
1020 genman(root)
1036 genman(root)
1021 if self.html:
1037 if self.html:
1022 genhtml(root)
1038 genhtml(root)
1023
1039
1024
1040
1025 class hginstall(install):
1041 class hginstall(install):
1026
1042
1027 user_options = install.user_options + [
1043 user_options = install.user_options + [
1028 (
1044 (
1029 'old-and-unmanageable',
1045 'old-and-unmanageable',
1030 None,
1046 None,
1031 'noop, present for eggless setuptools compat',
1047 'noop, present for eggless setuptools compat',
1032 ),
1048 ),
1033 (
1049 (
1034 'single-version-externally-managed',
1050 'single-version-externally-managed',
1035 None,
1051 None,
1036 'noop, present for eggless setuptools compat',
1052 'noop, present for eggless setuptools compat',
1037 ),
1053 ),
1038 ]
1054 ]
1039
1055
1040 sub_commands = install.sub_commands + [
1056 sub_commands = install.sub_commands + [
1041 ('install_completion', lambda self: True)
1057 ('install_completion', lambda self: True)
1042 ]
1058 ]
1043
1059
1044 # Also helps setuptools not be sad while we refuse to create eggs.
1060 # Also helps setuptools not be sad while we refuse to create eggs.
1045 single_version_externally_managed = True
1061 single_version_externally_managed = True
1046
1062
1047 def get_sub_commands(self):
1063 def get_sub_commands(self):
1048 # Screen out egg related commands to prevent egg generation. But allow
1064 # Screen out egg related commands to prevent egg generation. But allow
1049 # mercurial.egg-info generation, since that is part of modern
1065 # mercurial.egg-info generation, since that is part of modern
1050 # packaging.
1066 # packaging.
1051 excl = {'bdist_egg'}
1067 excl = {'bdist_egg'}
1052 return filter(lambda x: x not in excl, install.get_sub_commands(self))
1068 return filter(lambda x: x not in excl, install.get_sub_commands(self))
1053
1069
1054
1070
1055 class hginstalllib(install_lib):
1071 class hginstalllib(install_lib):
1056 """
1072 """
1057 This is a specialization of install_lib that replaces the copy_file used
1073 This is a specialization of install_lib that replaces the copy_file used
1058 there so that it supports setting the mode of files after copying them,
1074 there so that it supports setting the mode of files after copying them,
1059 instead of just preserving the mode that the files originally had. If your
1075 instead of just preserving the mode that the files originally had. If your
1060 system has a umask of something like 027, preserving the permissions when
1076 system has a umask of something like 027, preserving the permissions when
1061 copying will lead to a broken install.
1077 copying will lead to a broken install.
1062
1078
1063 Note that just passing keep_permissions=False to copy_file would be
1079 Note that just passing keep_permissions=False to copy_file would be
1064 insufficient, as it might still be applying a umask.
1080 insufficient, as it might still be applying a umask.
1065 """
1081 """
1066
1082
1067 def run(self):
1083 def run(self):
1068 realcopyfile = file_util.copy_file
1084 realcopyfile = file_util.copy_file
1069
1085
1070 def copyfileandsetmode(*args, **kwargs):
1086 def copyfileandsetmode(*args, **kwargs):
1071 src, dst = args[0], args[1]
1087 src, dst = args[0], args[1]
1072 dst, copied = realcopyfile(*args, **kwargs)
1088 dst, copied = realcopyfile(*args, **kwargs)
1073 if copied:
1089 if copied:
1074 st = os.stat(src)
1090 st = os.stat(src)
1075 # Persist executable bit (apply it to group and other if user
1091 # Persist executable bit (apply it to group and other if user
1076 # has it)
1092 # has it)
1077 if st[stat.ST_MODE] & stat.S_IXUSR:
1093 if st[stat.ST_MODE] & stat.S_IXUSR:
1078 setmode = int('0755', 8)
1094 setmode = int('0755', 8)
1079 else:
1095 else:
1080 setmode = int('0644', 8)
1096 setmode = int('0644', 8)
1081 m = stat.S_IMODE(st[stat.ST_MODE])
1097 m = stat.S_IMODE(st[stat.ST_MODE])
1082 m = (m & ~int('0777', 8)) | setmode
1098 m = (m & ~int('0777', 8)) | setmode
1083 os.chmod(dst, m)
1099 os.chmod(dst, m)
1084
1100
1085 file_util.copy_file = copyfileandsetmode
1101 file_util.copy_file = copyfileandsetmode
1086 try:
1102 try:
1087 install_lib.run(self)
1103 install_lib.run(self)
1088 finally:
1104 finally:
1089 file_util.copy_file = realcopyfile
1105 file_util.copy_file = realcopyfile
1090
1106
1091
1107
1092 class hginstallscripts(install_scripts):
1108 class hginstallscripts(install_scripts):
1093 """
1109 """
1094 This is a specialization of install_scripts that replaces the @LIBDIR@ with
1110 This is a specialization of install_scripts that replaces the @LIBDIR@ with
1095 the configured directory for modules. If possible, the path is made relative
1111 the configured directory for modules. If possible, the path is made relative
1096 to the directory for scripts.
1112 to the directory for scripts.
1097 """
1113 """
1098
1114
1099 def initialize_options(self):
1115 def initialize_options(self):
1100 install_scripts.initialize_options(self)
1116 install_scripts.initialize_options(self)
1101
1117
1102 self.install_lib = None
1118 self.install_lib = None
1103
1119
1104 def finalize_options(self):
1120 def finalize_options(self):
1105 install_scripts.finalize_options(self)
1121 install_scripts.finalize_options(self)
1106 self.set_undefined_options('install', ('install_lib', 'install_lib'))
1122 self.set_undefined_options('install', ('install_lib', 'install_lib'))
1107
1123
1108 def run(self):
1124 def run(self):
1109 install_scripts.run(self)
1125 install_scripts.run(self)
1110
1126
1111 # It only makes sense to replace @LIBDIR@ with the install path if
1127 # It only makes sense to replace @LIBDIR@ with the install path if
1112 # the install path is known. For wheels, the logic below calculates
1128 # the install path is known. For wheels, the logic below calculates
1113 # the libdir to be "../..". This is because the internal layout of a
1129 # the libdir to be "../..". This is because the internal layout of a
1114 # wheel archive looks like:
1130 # wheel archive looks like:
1115 #
1131 #
1116 # mercurial-3.6.1.data/scripts/hg
1132 # mercurial-3.6.1.data/scripts/hg
1117 # mercurial/__init__.py
1133 # mercurial/__init__.py
1118 #
1134 #
1119 # When installing wheels, the subdirectories of the "<pkg>.data"
1135 # When installing wheels, the subdirectories of the "<pkg>.data"
1120 # directory are translated to system local paths and files therein
1136 # directory are translated to system local paths and files therein
1121 # are copied in place. The mercurial/* files are installed into the
1137 # are copied in place. The mercurial/* files are installed into the
1122 # site-packages directory. However, the site-packages directory
1138 # site-packages directory. However, the site-packages directory
1123 # isn't known until wheel install time. This means we have no clue
1139 # isn't known until wheel install time. This means we have no clue
1124 # at wheel generation time what the installed site-packages directory
1140 # at wheel generation time what the installed site-packages directory
1125 # will be. And, wheels don't appear to provide the ability to register
1141 # will be. And, wheels don't appear to provide the ability to register
1126 # custom code to run during wheel installation. This all means that
1142 # custom code to run during wheel installation. This all means that
1127 # we can't reliably set the libdir in wheels: the default behavior
1143 # we can't reliably set the libdir in wheels: the default behavior
1128 # of looking in sys.path must do.
1144 # of looking in sys.path must do.
1129
1145
1130 if (
1146 if (
1131 os.path.splitdrive(self.install_dir)[0]
1147 os.path.splitdrive(self.install_dir)[0]
1132 != os.path.splitdrive(self.install_lib)[0]
1148 != os.path.splitdrive(self.install_lib)[0]
1133 ):
1149 ):
1134 # can't make relative paths from one drive to another, so use an
1150 # can't make relative paths from one drive to another, so use an
1135 # absolute path instead
1151 # absolute path instead
1136 libdir = self.install_lib
1152 libdir = self.install_lib
1137 else:
1153 else:
1138 libdir = os.path.relpath(self.install_lib, self.install_dir)
1154 libdir = os.path.relpath(self.install_lib, self.install_dir)
1139
1155
1140 for outfile in self.outfiles:
1156 for outfile in self.outfiles:
1141 with open(outfile, 'rb') as fp:
1157 with open(outfile, 'rb') as fp:
1142 data = fp.read()
1158 data = fp.read()
1143
1159
1144 # skip binary files
1160 # skip binary files
1145 if b'\0' in data:
1161 if b'\0' in data:
1146 continue
1162 continue
1147
1163
1148 # During local installs, the shebang will be rewritten to the final
1164 # During local installs, the shebang will be rewritten to the final
1149 # install path. During wheel packaging, the shebang has a special
1165 # install path. During wheel packaging, the shebang has a special
1150 # value.
1166 # value.
1151 if data.startswith(b'#!python'):
1167 if data.startswith(b'#!python'):
1152 log.info(
1168 log.info(
1153 'not rewriting @LIBDIR@ in %s because install path '
1169 'not rewriting @LIBDIR@ in %s because install path '
1154 'not known' % outfile
1170 'not known' % outfile
1155 )
1171 )
1156 continue
1172 continue
1157
1173
1158 data = data.replace(b'@LIBDIR@', libdir.encode('unicode_escape'))
1174 data = data.replace(b'@LIBDIR@', libdir.encode('unicode_escape'))
1159 with open(outfile, 'wb') as fp:
1175 with open(outfile, 'wb') as fp:
1160 fp.write(data)
1176 fp.write(data)
1161
1177
1162
1178
1163 class hginstallcompletion(Command):
1179 class hginstallcompletion(Command):
1164 description = 'Install shell completion'
1180 description = 'Install shell completion'
1165
1181
1166 def initialize_options(self):
1182 def initialize_options(self):
1167 self.install_dir = None
1183 self.install_dir = None
1168 self.outputs = []
1184 self.outputs = []
1169
1185
1170 def finalize_options(self):
1186 def finalize_options(self):
1171 self.set_undefined_options(
1187 self.set_undefined_options(
1172 'install_data', ('install_dir', 'install_dir')
1188 'install_data', ('install_dir', 'install_dir')
1173 )
1189 )
1174
1190
1175 def get_outputs(self):
1191 def get_outputs(self):
1176 return self.outputs
1192 return self.outputs
1177
1193
1178 def run(self):
1194 def run(self):
1179 for src, dir_path, dest in (
1195 for src, dir_path, dest in (
1180 (
1196 (
1181 'bash_completion',
1197 'bash_completion',
1182 ('share', 'bash-completion', 'completions'),
1198 ('share', 'bash-completion', 'completions'),
1183 'hg',
1199 'hg',
1184 ),
1200 ),
1185 ('zsh_completion', ('share', 'zsh', 'site-functions'), '_hg'),
1201 ('zsh_completion', ('share', 'zsh', 'site-functions'), '_hg'),
1186 ):
1202 ):
1187 dir = os.path.join(self.install_dir, *dir_path)
1203 dir = os.path.join(self.install_dir, *dir_path)
1188 self.mkpath(dir)
1204 self.mkpath(dir)
1189
1205
1190 dest = os.path.join(dir, dest)
1206 dest = os.path.join(dir, dest)
1191 self.outputs.append(dest)
1207 self.outputs.append(dest)
1192 self.copy_file(os.path.join('contrib', src), dest)
1208 self.copy_file(os.path.join('contrib', src), dest)
1193
1209
1194
1210
1195 # virtualenv installs custom distutils/__init__.py and
1211 # virtualenv installs custom distutils/__init__.py and
1196 # distutils/distutils.cfg files which essentially proxy back to the
1212 # distutils/distutils.cfg files which essentially proxy back to the
1197 # "real" distutils in the main Python install. The presence of this
1213 # "real" distutils in the main Python install. The presence of this
1198 # directory causes py2exe to pick up the "hacked" distutils package
1214 # directory causes py2exe to pick up the "hacked" distutils package
1199 # from the virtualenv and "import distutils" will fail from the py2exe
1215 # from the virtualenv and "import distutils" will fail from the py2exe
1200 # build because the "real" distutils files can't be located.
1216 # build because the "real" distutils files can't be located.
1201 #
1217 #
1202 # We work around this by monkeypatching the py2exe code finding Python
1218 # We work around this by monkeypatching the py2exe code finding Python
1203 # modules to replace the found virtualenv distutils modules with the
1219 # modules to replace the found virtualenv distutils modules with the
1204 # original versions via filesystem scanning. This is a bit hacky. But
1220 # original versions via filesystem scanning. This is a bit hacky. But
1205 # it allows us to use virtualenvs for py2exe packaging, which is more
1221 # it allows us to use virtualenvs for py2exe packaging, which is more
1206 # deterministic and reproducible.
1222 # deterministic and reproducible.
1207 #
1223 #
1208 # It's worth noting that the common StackOverflow suggestions for this
1224 # It's worth noting that the common StackOverflow suggestions for this
1209 # problem involve copying the original distutils files into the
1225 # problem involve copying the original distutils files into the
1210 # virtualenv or into the staging directory after setup() is invoked.
1226 # virtualenv or into the staging directory after setup() is invoked.
1211 # The former is very brittle and can easily break setup(). Our hacking
1227 # The former is very brittle and can easily break setup(). Our hacking
1212 # of the found modules routine has a similar result as copying the files
1228 # of the found modules routine has a similar result as copying the files
1213 # manually. But it makes fewer assumptions about how py2exe works and
1229 # manually. But it makes fewer assumptions about how py2exe works and
1214 # is less brittle.
1230 # is less brittle.
1215
1231
1216 # This only catches virtualenvs made with virtualenv (as opposed to
1232 # This only catches virtualenvs made with virtualenv (as opposed to
1217 # venv, which is likely what Python 3 uses).
1233 # venv, which is likely what Python 3 uses).
1218 py2exehacked = py2exeloaded and getattr(sys, 'real_prefix', None) is not None
1234 py2exehacked = py2exeloaded and getattr(sys, 'real_prefix', None) is not None
1219
1235
1220 if py2exehacked:
1236 if py2exehacked:
1221 from distutils.command.py2exe import py2exe as buildpy2exe
1237 from distutils.command.py2exe import py2exe as buildpy2exe
1222 from py2exe.mf import Module as py2exemodule
1238 from py2exe.mf import Module as py2exemodule
1223
1239
1224 class hgbuildpy2exe(buildpy2exe):
1240 class hgbuildpy2exe(buildpy2exe):
1225 def find_needed_modules(self, mf, files, modules):
1241 def find_needed_modules(self, mf, files, modules):
1226 res = buildpy2exe.find_needed_modules(self, mf, files, modules)
1242 res = buildpy2exe.find_needed_modules(self, mf, files, modules)
1227
1243
1228 # Replace virtualenv's distutils modules with the real ones.
1244 # Replace virtualenv's distutils modules with the real ones.
1229 modules = {}
1245 modules = {}
1230 for k, v in res.modules.items():
1246 for k, v in res.modules.items():
1231 if k != 'distutils' and not k.startswith('distutils.'):
1247 if k != 'distutils' and not k.startswith('distutils.'):
1232 modules[k] = v
1248 modules[k] = v
1233
1249
1234 res.modules = modules
1250 res.modules = modules
1235
1251
1236 import opcode
1252 import opcode
1237
1253
1238 distutilsreal = os.path.join(
1254 distutilsreal = os.path.join(
1239 os.path.dirname(opcode.__file__), 'distutils'
1255 os.path.dirname(opcode.__file__), 'distutils'
1240 )
1256 )
1241
1257
1242 for root, dirs, files in os.walk(distutilsreal):
1258 for root, dirs, files in os.walk(distutilsreal):
1243 for f in sorted(files):
1259 for f in sorted(files):
1244 if not f.endswith('.py'):
1260 if not f.endswith('.py'):
1245 continue
1261 continue
1246
1262
1247 full = os.path.join(root, f)
1263 full = os.path.join(root, f)
1248
1264
1249 parents = ['distutils']
1265 parents = ['distutils']
1250
1266
1251 if root != distutilsreal:
1267 if root != distutilsreal:
1252 rel = os.path.relpath(root, distutilsreal)
1268 rel = os.path.relpath(root, distutilsreal)
1253 parents.extend(p for p in rel.split(os.sep))
1269 parents.extend(p for p in rel.split(os.sep))
1254
1270
1255 modname = '%s.%s' % ('.'.join(parents), f[:-3])
1271 modname = '%s.%s' % ('.'.join(parents), f[:-3])
1256
1272
1257 if modname.startswith('distutils.tests.'):
1273 if modname.startswith('distutils.tests.'):
1258 continue
1274 continue
1259
1275
1260 if modname.endswith('.__init__'):
1276 if modname.endswith('.__init__'):
1261 modname = modname[: -len('.__init__')]
1277 modname = modname[: -len('.__init__')]
1262 path = os.path.dirname(full)
1278 path = os.path.dirname(full)
1263 else:
1279 else:
1264 path = None
1280 path = None
1265
1281
1266 res.modules[modname] = py2exemodule(
1282 res.modules[modname] = py2exemodule(
1267 modname, full, path=path
1283 modname, full, path=path
1268 )
1284 )
1269
1285
1270 if 'distutils' not in res.modules:
1286 if 'distutils' not in res.modules:
1271 raise SystemExit('could not find distutils modules')
1287 raise SystemExit('could not find distutils modules')
1272
1288
1273 return res
1289 return res
1274
1290
1275
1291
1276 cmdclass = {
1292 cmdclass = {
1277 'build': hgbuild,
1293 'build': hgbuild,
1278 'build_doc': hgbuilddoc,
1294 'build_doc': hgbuilddoc,
1279 'build_mo': hgbuildmo,
1295 'build_mo': hgbuildmo,
1280 'build_ext': hgbuildext,
1296 'build_ext': hgbuildext,
1281 'build_py': hgbuildpy,
1297 'build_py': hgbuildpy,
1282 'build_scripts': hgbuildscripts,
1298 'build_scripts': hgbuildscripts,
1283 'build_hgextindex': buildhgextindex,
1299 'build_hgextindex': buildhgextindex,
1284 'install': hginstall,
1300 'install': hginstall,
1285 'install_completion': hginstallcompletion,
1301 'install_completion': hginstallcompletion,
1286 'install_lib': hginstalllib,
1302 'install_lib': hginstalllib,
1287 'install_scripts': hginstallscripts,
1303 'install_scripts': hginstallscripts,
1288 'build_hgexe': buildhgexe,
1304 'build_hgexe': buildhgexe,
1289 }
1305 }
1290
1306
1291 if py2exehacked:
1307 if py2exehacked:
1292 cmdclass['py2exe'] = hgbuildpy2exe
1308 cmdclass['py2exe'] = hgbuildpy2exe
1293
1309
1294 packages = [
1310 packages = [
1295 'mercurial',
1311 'mercurial',
1296 'mercurial.cext',
1312 'mercurial.cext',
1297 'mercurial.cffi',
1313 'mercurial.cffi',
1298 'mercurial.defaultrc',
1314 'mercurial.defaultrc',
1299 'mercurial.dirstateutils',
1315 'mercurial.dirstateutils',
1300 'mercurial.helptext',
1316 'mercurial.helptext',
1301 'mercurial.helptext.internals',
1317 'mercurial.helptext.internals',
1302 'mercurial.hgweb',
1318 'mercurial.hgweb',
1303 'mercurial.interfaces',
1319 'mercurial.interfaces',
1304 'mercurial.pure',
1320 'mercurial.pure',
1305 'mercurial.stabletailgraph',
1321 'mercurial.stabletailgraph',
1306 'mercurial.templates',
1322 'mercurial.templates',
1307 'mercurial.thirdparty',
1323 'mercurial.thirdparty',
1308 'mercurial.thirdparty.attr',
1324 'mercurial.thirdparty.attr',
1309 'mercurial.thirdparty.tomli',
1325 'mercurial.thirdparty.tomli',
1310 'mercurial.thirdparty.zope',
1326 'mercurial.thirdparty.zope',
1311 'mercurial.thirdparty.zope.interface',
1327 'mercurial.thirdparty.zope.interface',
1312 'mercurial.upgrade_utils',
1328 'mercurial.upgrade_utils',
1313 'mercurial.utils',
1329 'mercurial.utils',
1314 'mercurial.revlogutils',
1330 'mercurial.revlogutils',
1315 'mercurial.testing',
1331 'mercurial.testing',
1316 'hgext',
1332 'hgext',
1317 'hgext.convert',
1333 'hgext.convert',
1318 'hgext.fsmonitor',
1334 'hgext.fsmonitor',
1319 'hgext.fastannotate',
1335 'hgext.fastannotate',
1320 'hgext.fsmonitor.pywatchman',
1336 'hgext.fsmonitor.pywatchman',
1321 'hgext.git',
1337 'hgext.git',
1322 'hgext.highlight',
1338 'hgext.highlight',
1323 'hgext.hooklib',
1339 'hgext.hooklib',
1324 'hgext.largefiles',
1340 'hgext.largefiles',
1325 'hgext.lfs',
1341 'hgext.lfs',
1326 'hgext.narrow',
1342 'hgext.narrow',
1327 'hgext.remotefilelog',
1343 'hgext.remotefilelog',
1328 'hgext.zeroconf',
1344 'hgext.zeroconf',
1329 'hgext3rd',
1345 'hgext3rd',
1330 'hgdemandimport',
1346 'hgdemandimport',
1331 ]
1347 ]
1332
1348
1333 for name in os.listdir(os.path.join('mercurial', 'templates')):
1349 for name in os.listdir(os.path.join('mercurial', 'templates')):
1334 if name != '__pycache__' and os.path.isdir(
1350 if name != '__pycache__' and os.path.isdir(
1335 os.path.join('mercurial', 'templates', name)
1351 os.path.join('mercurial', 'templates', name)
1336 ):
1352 ):
1337 packages.append('mercurial.templates.%s' % name)
1353 packages.append('mercurial.templates.%s' % name)
1338
1354
1339 if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ:
1355 if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ:
1340 # py2exe can't cope with namespace packages very well, so we have to
1356 # py2exe can't cope with namespace packages very well, so we have to
1341 # install any hgext3rd.* extensions that we want in the final py2exe
1357 # install any hgext3rd.* extensions that we want in the final py2exe
1342 # image here. This is gross, but you gotta do what you gotta do.
1358 # image here. This is gross, but you gotta do what you gotta do.
1343 packages.extend(os.environ['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'].split(' '))
1359 packages.extend(os.environ['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'].split(' '))
1344
1360
1345 common_depends = [
1361 common_depends = [
1346 'mercurial/bitmanipulation.h',
1362 'mercurial/bitmanipulation.h',
1347 'mercurial/compat.h',
1363 'mercurial/compat.h',
1348 'mercurial/cext/util.h',
1364 'mercurial/cext/util.h',
1349 ]
1365 ]
1350 common_include_dirs = ['mercurial']
1366 common_include_dirs = ['mercurial']
1351
1367
1352 common_cflags = []
1368 common_cflags = []
1353
1369
1354 # MSVC 2008 still needs declarations at the top of the scope, but Python 3.9
1370 # MSVC 2008 still needs declarations at the top of the scope, but Python 3.9
1355 # makes declarations not at the top of a scope in the headers.
1371 # makes declarations not at the top of a scope in the headers.
1356 if os.name != 'nt' and sys.version_info[1] < 9:
1372 if os.name != 'nt' and sys.version_info[1] < 9:
1357 common_cflags = ['-Werror=declaration-after-statement']
1373 common_cflags = ['-Werror=declaration-after-statement']
1358
1374
1359 osutil_cflags = []
1375 osutil_cflags = []
1360 osutil_ldflags = []
1376 osutil_ldflags = []
1361
1377
1362 # platform specific macros
1378 # platform specific macros
1363 for plat, func in [('bsd', 'setproctitle')]:
1379 for plat, func in [('bsd', 'setproctitle')]:
1364 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
1380 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
1365 osutil_cflags.append('-DHAVE_%s' % func.upper())
1381 osutil_cflags.append('-DHAVE_%s' % func.upper())
1366
1382
1367 for plat, macro, code in [
1383 for plat, macro, code in [
1368 (
1384 (
1369 'bsd|darwin',
1385 'bsd|darwin',
1370 'BSD_STATFS',
1386 'BSD_STATFS',
1371 '''
1387 '''
1372 #include <sys/param.h>
1388 #include <sys/param.h>
1373 #include <sys/mount.h>
1389 #include <sys/mount.h>
1374 int main() { struct statfs s; return sizeof(s.f_fstypename); }
1390 int main() { struct statfs s; return sizeof(s.f_fstypename); }
1375 ''',
1391 ''',
1376 ),
1392 ),
1377 (
1393 (
1378 'linux',
1394 'linux',
1379 'LINUX_STATFS',
1395 'LINUX_STATFS',
1380 '''
1396 '''
1381 #include <linux/magic.h>
1397 #include <linux/magic.h>
1382 #include <sys/vfs.h>
1398 #include <sys/vfs.h>
1383 int main() { struct statfs s; return sizeof(s.f_type); }
1399 int main() { struct statfs s; return sizeof(s.f_type); }
1384 ''',
1400 ''',
1385 ),
1401 ),
1386 ]:
1402 ]:
1387 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
1403 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
1388 osutil_cflags.append('-DHAVE_%s' % macro)
1404 osutil_cflags.append('-DHAVE_%s' % macro)
1389
1405
1390 if sys.platform == 'darwin':
1406 if sys.platform == 'darwin':
1391 osutil_ldflags += ['-framework', 'ApplicationServices']
1407 osutil_ldflags += ['-framework', 'ApplicationServices']
1392
1408
1393 if sys.platform == 'sunos5':
1409 if sys.platform == 'sunos5':
1394 osutil_ldflags += ['-lsocket']
1410 osutil_ldflags += ['-lsocket']
1395
1411
1396 xdiff_srcs = [
1412 xdiff_srcs = [
1397 'mercurial/thirdparty/xdiff/xdiffi.c',
1413 'mercurial/thirdparty/xdiff/xdiffi.c',
1398 'mercurial/thirdparty/xdiff/xprepare.c',
1414 'mercurial/thirdparty/xdiff/xprepare.c',
1399 'mercurial/thirdparty/xdiff/xutils.c',
1415 'mercurial/thirdparty/xdiff/xutils.c',
1400 ]
1416 ]
1401
1417
1402 xdiff_headers = [
1418 xdiff_headers = [
1403 'mercurial/thirdparty/xdiff/xdiff.h',
1419 'mercurial/thirdparty/xdiff/xdiff.h',
1404 'mercurial/thirdparty/xdiff/xdiffi.h',
1420 'mercurial/thirdparty/xdiff/xdiffi.h',
1405 'mercurial/thirdparty/xdiff/xinclude.h',
1421 'mercurial/thirdparty/xdiff/xinclude.h',
1406 'mercurial/thirdparty/xdiff/xmacros.h',
1422 'mercurial/thirdparty/xdiff/xmacros.h',
1407 'mercurial/thirdparty/xdiff/xprepare.h',
1423 'mercurial/thirdparty/xdiff/xprepare.h',
1408 'mercurial/thirdparty/xdiff/xtypes.h',
1424 'mercurial/thirdparty/xdiff/xtypes.h',
1409 'mercurial/thirdparty/xdiff/xutils.h',
1425 'mercurial/thirdparty/xdiff/xutils.h',
1410 ]
1426 ]
1411
1427
1412
1428
1413 class RustCompilationError(CCompilerError):
1429 class RustCompilationError(CCompilerError):
1414 """Exception class for Rust compilation errors."""
1430 """Exception class for Rust compilation errors."""
1415
1431
1416
1432
1417 class RustExtension(Extension):
1433 class RustExtension(Extension):
1418 """Base classes for concrete Rust Extension classes."""
1434 """Base classes for concrete Rust Extension classes."""
1419
1435
1420 rusttargetdir = os.path.join('rust', 'target', 'release')
1436 rusttargetdir = os.path.join('rust', 'target', 'release')
1421
1437
1422 def __init__(self, mpath, sources, rustlibname, subcrate, **kw):
1438 def __init__(self, mpath, sources, rustlibname, subcrate, **kw):
1423 Extension.__init__(self, mpath, sources, **kw)
1439 Extension.__init__(self, mpath, sources, **kw)
1424 srcdir = self.rustsrcdir = os.path.join('rust', subcrate)
1440 srcdir = self.rustsrcdir = os.path.join('rust', subcrate)
1425
1441
1426 # adding Rust source and control files to depends so that the extension
1442 # adding Rust source and control files to depends so that the extension
1427 # gets rebuilt if they've changed
1443 # gets rebuilt if they've changed
1428 self.depends.append(os.path.join(srcdir, 'Cargo.toml'))
1444 self.depends.append(os.path.join(srcdir, 'Cargo.toml'))
1429 cargo_lock = os.path.join(srcdir, 'Cargo.lock')
1445 cargo_lock = os.path.join(srcdir, 'Cargo.lock')
1430 if os.path.exists(cargo_lock):
1446 if os.path.exists(cargo_lock):
1431 self.depends.append(cargo_lock)
1447 self.depends.append(cargo_lock)
1432 for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')):
1448 for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')):
1433 self.depends.extend(
1449 self.depends.extend(
1434 os.path.join(dirpath, fname)
1450 os.path.join(dirpath, fname)
1435 for fname in fnames
1451 for fname in fnames
1436 if os.path.splitext(fname)[1] == '.rs'
1452 if os.path.splitext(fname)[1] == '.rs'
1437 )
1453 )
1438
1454
1439 @staticmethod
1455 @staticmethod
1440 def rustdylibsuffix():
1456 def rustdylibsuffix():
1441 """Return the suffix for shared libraries produced by rustc.
1457 """Return the suffix for shared libraries produced by rustc.
1442
1458
1443 See also: https://doc.rust-lang.org/reference/linkage.html
1459 See also: https://doc.rust-lang.org/reference/linkage.html
1444 """
1460 """
1445 if sys.platform == 'darwin':
1461 if sys.platform == 'darwin':
1446 return '.dylib'
1462 return '.dylib'
1447 elif os.name == 'nt':
1463 elif os.name == 'nt':
1448 return '.dll'
1464 return '.dll'
1449 else:
1465 else:
1450 return '.so'
1466 return '.so'
1451
1467
1452 def rustbuild(self):
1468 def rustbuild(self):
1453 env = os.environ.copy()
1469 env = os.environ.copy()
1454 if 'HGTEST_RESTOREENV' in env:
1470 if 'HGTEST_RESTOREENV' in env:
1455 # Mercurial tests change HOME to a temporary directory,
1471 # Mercurial tests change HOME to a temporary directory,
1456 # but, if installed with rustup, the Rust toolchain needs
1472 # but, if installed with rustup, the Rust toolchain needs
1457 # HOME to be correct (otherwise the 'no default toolchain'
1473 # HOME to be correct (otherwise the 'no default toolchain'
1458 # error message is issued and the build fails).
1474 # error message is issued and the build fails).
1459 # This happens currently with test-hghave.t, which does
1475 # This happens currently with test-hghave.t, which does
1460 # invoke this build.
1476 # invoke this build.
1461
1477
1462 # Unix only fix (os.path.expanduser not really reliable if
1478 # Unix only fix (os.path.expanduser not really reliable if
1463 # HOME is shadowed like this)
1479 # HOME is shadowed like this)
1464 import pwd
1480 import pwd
1465
1481
1466 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir
1482 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir
1467
1483
1468 cargocmd = ['cargo', 'rustc', '--release']
1484 cargocmd = ['cargo', 'rustc', '--release']
1469
1485
1470 rust_features = env.get("HG_RUST_FEATURES")
1486 rust_features = env.get("HG_RUST_FEATURES")
1471 if rust_features:
1487 if rust_features:
1472 cargocmd.extend(('--features', rust_features))
1488 cargocmd.extend(('--features', rust_features))
1473
1489
1474 cargocmd.append('--')
1490 cargocmd.append('--')
1475 if sys.platform == 'darwin':
1491 if sys.platform == 'darwin':
1476 cargocmd.extend(
1492 cargocmd.extend(
1477 ("-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup")
1493 ("-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup")
1478 )
1494 )
1479 try:
1495 try:
1480 subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir)
1496 subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir)
1481 except FileNotFoundError:
1497 except FileNotFoundError:
1482 raise RustCompilationError("Cargo not found")
1498 raise RustCompilationError("Cargo not found")
1483 except PermissionError:
1499 except PermissionError:
1484 raise RustCompilationError(
1500 raise RustCompilationError(
1485 "Cargo found, but permission to execute it is denied"
1501 "Cargo found, but permission to execute it is denied"
1486 )
1502 )
1487 except subprocess.CalledProcessError:
1503 except subprocess.CalledProcessError:
1488 raise RustCompilationError(
1504 raise RustCompilationError(
1489 "Cargo failed. Working directory: %r, "
1505 "Cargo failed. Working directory: %r, "
1490 "command: %r, environment: %r"
1506 "command: %r, environment: %r"
1491 % (self.rustsrcdir, cargocmd, env)
1507 % (self.rustsrcdir, cargocmd, env)
1492 )
1508 )
1493
1509
1494
1510
1495 class RustStandaloneExtension(RustExtension):
1511 class RustStandaloneExtension(RustExtension):
1496 def __init__(self, pydottedname, rustcrate, dylibname, **kw):
1512 def __init__(self, pydottedname, rustcrate, dylibname, **kw):
1497 RustExtension.__init__(
1513 RustExtension.__init__(
1498 self, pydottedname, [], dylibname, rustcrate, **kw
1514 self, pydottedname, [], dylibname, rustcrate, **kw
1499 )
1515 )
1500 self.dylibname = dylibname
1516 self.dylibname = dylibname
1501
1517
1502 def build(self, target_dir):
1518 def build(self, target_dir):
1503 self.rustbuild()
1519 self.rustbuild()
1504 target = [target_dir]
1520 target = [target_dir]
1505 target.extend(self.name.split('.'))
1521 target.extend(self.name.split('.'))
1506 target[-1] += DYLIB_SUFFIX
1522 target[-1] += DYLIB_SUFFIX
1507 target = os.path.join(*target)
1523 target = os.path.join(*target)
1508 os.makedirs(os.path.dirname(target), exist_ok=True)
1524 os.makedirs(os.path.dirname(target), exist_ok=True)
1509 shutil.copy2(
1525 shutil.copy2(
1510 os.path.join(
1526 os.path.join(
1511 self.rusttargetdir, self.dylibname + self.rustdylibsuffix()
1527 self.rusttargetdir, self.dylibname + self.rustdylibsuffix()
1512 ),
1528 ),
1513 target,
1529 target,
1514 )
1530 )
1515
1531
1516
1532
1517 extmodules = [
1533 extmodules = [
1518 Extension(
1534 Extension(
1519 'mercurial.cext.base85',
1535 'mercurial.cext.base85',
1520 ['mercurial/cext/base85.c'],
1536 ['mercurial/cext/base85.c'],
1521 include_dirs=common_include_dirs,
1537 include_dirs=common_include_dirs,
1522 extra_compile_args=common_cflags,
1538 extra_compile_args=common_cflags,
1523 depends=common_depends,
1539 depends=common_depends,
1524 ),
1540 ),
1525 Extension(
1541 Extension(
1526 'mercurial.cext.bdiff',
1542 'mercurial.cext.bdiff',
1527 ['mercurial/bdiff.c', 'mercurial/cext/bdiff.c'] + xdiff_srcs,
1543 ['mercurial/bdiff.c', 'mercurial/cext/bdiff.c'] + xdiff_srcs,
1528 include_dirs=common_include_dirs,
1544 include_dirs=common_include_dirs,
1529 extra_compile_args=common_cflags,
1545 extra_compile_args=common_cflags,
1530 depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers,
1546 depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers,
1531 ),
1547 ),
1532 Extension(
1548 Extension(
1533 'mercurial.cext.mpatch',
1549 'mercurial.cext.mpatch',
1534 ['mercurial/mpatch.c', 'mercurial/cext/mpatch.c'],
1550 ['mercurial/mpatch.c', 'mercurial/cext/mpatch.c'],
1535 include_dirs=common_include_dirs,
1551 include_dirs=common_include_dirs,
1536 extra_compile_args=common_cflags,
1552 extra_compile_args=common_cflags,
1537 depends=common_depends,
1553 depends=common_depends,
1538 ),
1554 ),
1539 Extension(
1555 Extension(
1540 'mercurial.cext.parsers',
1556 'mercurial.cext.parsers',
1541 [
1557 [
1542 'mercurial/cext/charencode.c',
1558 'mercurial/cext/charencode.c',
1543 'mercurial/cext/dirs.c',
1559 'mercurial/cext/dirs.c',
1544 'mercurial/cext/manifest.c',
1560 'mercurial/cext/manifest.c',
1545 'mercurial/cext/parsers.c',
1561 'mercurial/cext/parsers.c',
1546 'mercurial/cext/pathencode.c',
1562 'mercurial/cext/pathencode.c',
1547 'mercurial/cext/revlog.c',
1563 'mercurial/cext/revlog.c',
1548 ],
1564 ],
1549 include_dirs=common_include_dirs,
1565 include_dirs=common_include_dirs,
1550 extra_compile_args=common_cflags,
1566 extra_compile_args=common_cflags,
1551 depends=common_depends
1567 depends=common_depends
1552 + [
1568 + [
1553 'mercurial/cext/charencode.h',
1569 'mercurial/cext/charencode.h',
1554 'mercurial/cext/revlog.h',
1570 'mercurial/cext/revlog.h',
1555 ],
1571 ],
1556 ),
1572 ),
1557 Extension(
1573 Extension(
1558 'mercurial.cext.osutil',
1574 'mercurial.cext.osutil',
1559 ['mercurial/cext/osutil.c'],
1575 ['mercurial/cext/osutil.c'],
1560 include_dirs=common_include_dirs,
1576 include_dirs=common_include_dirs,
1561 extra_compile_args=common_cflags + osutil_cflags,
1577 extra_compile_args=common_cflags + osutil_cflags,
1562 extra_link_args=osutil_ldflags,
1578 extra_link_args=osutil_ldflags,
1563 depends=common_depends,
1579 depends=common_depends,
1564 ),
1580 ),
1565 Extension(
1581 Extension(
1566 'mercurial.thirdparty.zope.interface._zope_interface_coptimizations',
1582 'mercurial.thirdparty.zope.interface._zope_interface_coptimizations',
1567 [
1583 [
1568 'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c',
1584 'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c',
1569 ],
1585 ],
1570 extra_compile_args=common_cflags,
1586 extra_compile_args=common_cflags,
1571 ),
1587 ),
1572 Extension(
1588 Extension(
1573 'mercurial.thirdparty.sha1dc',
1589 'mercurial.thirdparty.sha1dc',
1574 [
1590 [
1575 'mercurial/thirdparty/sha1dc/cext.c',
1591 'mercurial/thirdparty/sha1dc/cext.c',
1576 'mercurial/thirdparty/sha1dc/lib/sha1.c',
1592 'mercurial/thirdparty/sha1dc/lib/sha1.c',
1577 'mercurial/thirdparty/sha1dc/lib/ubc_check.c',
1593 'mercurial/thirdparty/sha1dc/lib/ubc_check.c',
1578 ],
1594 ],
1579 extra_compile_args=common_cflags,
1595 extra_compile_args=common_cflags,
1580 ),
1596 ),
1581 Extension(
1597 Extension(
1582 'hgext.fsmonitor.pywatchman.bser',
1598 'hgext.fsmonitor.pywatchman.bser',
1583 ['hgext/fsmonitor/pywatchman/bser.c'],
1599 ['hgext/fsmonitor/pywatchman/bser.c'],
1584 extra_compile_args=common_cflags,
1600 extra_compile_args=common_cflags,
1585 ),
1601 ),
1586 RustStandaloneExtension(
1602 RustStandaloneExtension(
1587 'mercurial.rustext',
1603 'mercurial.rustext',
1588 'hg-cpython',
1604 'hg-cpython',
1589 'librusthg',
1605 'librusthg',
1590 ),
1606 ),
1591 ]
1607 ]
1592
1608
1593
1609
1594 sys.path.insert(0, 'contrib/python-zstandard')
1610 sys.path.insert(0, 'contrib/python-zstandard')
1595 import setup_zstd
1611 import setup_zstd
1596
1612
1597 zstd = setup_zstd.get_c_extension(
1613 zstd = setup_zstd.get_c_extension(
1598 name='mercurial.zstd', root=os.path.abspath(os.path.dirname(__file__))
1614 name='mercurial.zstd', root=os.path.abspath(os.path.dirname(__file__))
1599 )
1615 )
1600 zstd.extra_compile_args += common_cflags
1616 zstd.extra_compile_args += common_cflags
1601 extmodules.append(zstd)
1617 extmodules.append(zstd)
1602
1618
1603 try:
1619 try:
1604 from distutils import cygwinccompiler
1620 from distutils import cygwinccompiler
1605
1621
1606 # the -mno-cygwin option has been deprecated for years
1622 # the -mno-cygwin option has been deprecated for years
1607 mingw32compilerclass = cygwinccompiler.Mingw32CCompiler
1623 mingw32compilerclass = cygwinccompiler.Mingw32CCompiler
1608
1624
1609 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
1625 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
1610 def __init__(self, *args, **kwargs):
1626 def __init__(self, *args, **kwargs):
1611 mingw32compilerclass.__init__(self, *args, **kwargs)
1627 mingw32compilerclass.__init__(self, *args, **kwargs)
1612 for i in 'compiler compiler_so linker_exe linker_so'.split():
1628 for i in 'compiler compiler_so linker_exe linker_so'.split():
1613 try:
1629 try:
1614 getattr(self, i).remove('-mno-cygwin')
1630 getattr(self, i).remove('-mno-cygwin')
1615 except ValueError:
1631 except ValueError:
1616 pass
1632 pass
1617
1633
1618 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
1634 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
1619 except ImportError:
1635 except ImportError:
1620 # the cygwinccompiler package is not available on some Python
1636 # the cygwinccompiler package is not available on some Python
1621 # distributions like the ones from the optware project for Synology
1637 # distributions like the ones from the optware project for Synology
1622 # DiskStation boxes
1638 # DiskStation boxes
1623 class HackedMingw32CCompiler:
1639 class HackedMingw32CCompiler:
1624 pass
1640 pass
1625
1641
1626
1642
1627 if os.name == 'nt':
1643 if os.name == 'nt':
1628 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
1644 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
1629 # extra_link_args to distutils.extensions.Extension() doesn't have any
1645 # extra_link_args to distutils.extensions.Extension() doesn't have any
1630 # effect.
1646 # effect.
1631 from distutils import msvccompiler
1647 from distutils import msvccompiler
1632
1648
1633 msvccompilerclass = msvccompiler.MSVCCompiler
1649 msvccompilerclass = msvccompiler.MSVCCompiler
1634
1650
1635 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
1651 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
1636 def initialize(self):
1652 def initialize(self):
1637 msvccompilerclass.initialize(self)
1653 msvccompilerclass.initialize(self)
1638 # "warning LNK4197: export 'func' specified multiple times"
1654 # "warning LNK4197: export 'func' specified multiple times"
1639 self.ldflags_shared.append('/ignore:4197')
1655 self.ldflags_shared.append('/ignore:4197')
1640 self.ldflags_shared_debug.append('/ignore:4197')
1656 self.ldflags_shared_debug.append('/ignore:4197')
1641
1657
1642 msvccompiler.MSVCCompiler = HackedMSVCCompiler
1658 msvccompiler.MSVCCompiler = HackedMSVCCompiler
1643
1659
1644 packagedata = {
1660 packagedata = {
1645 'mercurial': [
1661 'mercurial': [
1646 'configitems.toml',
1662 'configitems.toml',
1647 'locale/*/LC_MESSAGES/hg.mo',
1663 'locale/*/LC_MESSAGES/hg.mo',
1648 'dummycert.pem',
1664 'dummycert.pem',
1649 ],
1665 ],
1650 'mercurial.defaultrc': [
1666 'mercurial.defaultrc': [
1651 '*.rc',
1667 '*.rc',
1652 ],
1668 ],
1653 'mercurial.helptext': [
1669 'mercurial.helptext': [
1654 '*.txt',
1670 '*.txt',
1655 ],
1671 ],
1656 'mercurial.helptext.internals': [
1672 'mercurial.helptext.internals': [
1657 '*.txt',
1673 '*.txt',
1658 ],
1674 ],
1659 'mercurial.thirdparty.attr': [
1675 'mercurial.thirdparty.attr': [
1660 '*.pyi',
1676 '*.pyi',
1661 'py.typed',
1677 'py.typed',
1662 ],
1678 ],
1663 }
1679 }
1664
1680
1665
1681
1666 def ordinarypath(p):
1682 def ordinarypath(p):
1667 return p and p[0] != '.' and p[-1] != '~'
1683 return p and p[0] != '.' and p[-1] != '~'
1668
1684
1669
1685
1670 for root in ('templates',):
1686 for root in ('templates',):
1671 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
1687 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
1672 packagename = curdir.replace(os.sep, '.')
1688 packagename = curdir.replace(os.sep, '.')
1673 packagedata[packagename] = list(filter(ordinarypath, files))
1689 packagedata[packagename] = list(filter(ordinarypath, files))
1674
1690
1675 datafiles = []
1691 datafiles = []
1676
1692
1677 # distutils expects version to be str/unicode. Converting it to
1693 # distutils expects version to be str/unicode. Converting it to
1678 # unicode on Python 2 still works because it won't contain any
1694 # unicode on Python 2 still works because it won't contain any
1679 # non-ascii bytes and will be implicitly converted back to bytes
1695 # non-ascii bytes and will be implicitly converted back to bytes
1680 # when operated on.
1696 # when operated on.
1681 assert isinstance(version, str)
1697 assert isinstance(version, str)
1682 setupversion = version
1698 setupversion = version
1683
1699
1684 extra = {}
1700 extra = {}
1685
1701
1686 py2exepackages = [
1702 py2exepackages = [
1687 'hgdemandimport',
1703 'hgdemandimport',
1688 'hgext3rd',
1704 'hgext3rd',
1689 'hgext',
1705 'hgext',
1690 'email',
1706 'email',
1691 # implicitly imported per module policy
1707 # implicitly imported per module policy
1692 # (cffi wouldn't be used as a frozen exe)
1708 # (cffi wouldn't be used as a frozen exe)
1693 'mercurial.cext',
1709 'mercurial.cext',
1694 #'mercurial.cffi',
1710 #'mercurial.cffi',
1695 'mercurial.pure',
1711 'mercurial.pure',
1696 ]
1712 ]
1697
1713
1698 py2exe_includes = []
1714 py2exe_includes = []
1699
1715
1700 py2exeexcludes = []
1716 py2exeexcludes = []
1701 py2exedllexcludes = ['crypt32.dll']
1717 py2exedllexcludes = ['crypt32.dll']
1702
1718
1703 if issetuptools:
1719 if issetuptools:
1704 extra['python_requires'] = supportedpy
1720 extra['python_requires'] = supportedpy
1705
1721
1706 if py2exeloaded:
1722 if py2exeloaded:
1707 extra['console'] = [
1723 extra['console'] = [
1708 {
1724 {
1709 'script': 'hg',
1725 'script': 'hg',
1710 'copyright': 'Copyright (C) 2005-2023 Olivia Mackall and others',
1726 'copyright': 'Copyright (C) 2005-2023 Olivia Mackall and others',
1711 'product_version': version,
1727 'product_version': version,
1712 }
1728 }
1713 ]
1729 ]
1714 # Sub command of 'build' because 'py2exe' does not handle sub_commands.
1730 # Sub command of 'build' because 'py2exe' does not handle sub_commands.
1715 # Need to override hgbuild because it has a private copy of
1731 # Need to override hgbuild because it has a private copy of
1716 # build.sub_commands.
1732 # build.sub_commands.
1717 hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
1733 hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
1718 # put dlls in sub directory so that they won't pollute PATH
1734 # put dlls in sub directory so that they won't pollute PATH
1719 extra['zipfile'] = 'lib/library.zip'
1735 extra['zipfile'] = 'lib/library.zip'
1720
1736
1721 # We allow some configuration to be supplemented via environment
1737 # We allow some configuration to be supplemented via environment
1722 # variables. This is better than setup.cfg files because it allows
1738 # variables. This is better than setup.cfg files because it allows
1723 # supplementing configs instead of replacing them.
1739 # supplementing configs instead of replacing them.
1724 extrapackages = os.environ.get('HG_PY2EXE_EXTRA_PACKAGES')
1740 extrapackages = os.environ.get('HG_PY2EXE_EXTRA_PACKAGES')
1725 if extrapackages:
1741 if extrapackages:
1726 py2exepackages.extend(extrapackages.split(' '))
1742 py2exepackages.extend(extrapackages.split(' '))
1727
1743
1728 extra_includes = os.environ.get('HG_PY2EXE_EXTRA_INCLUDES')
1744 extra_includes = os.environ.get('HG_PY2EXE_EXTRA_INCLUDES')
1729 if extra_includes:
1745 if extra_includes:
1730 py2exe_includes.extend(extra_includes.split(' '))
1746 py2exe_includes.extend(extra_includes.split(' '))
1731
1747
1732 excludes = os.environ.get('HG_PY2EXE_EXTRA_EXCLUDES')
1748 excludes = os.environ.get('HG_PY2EXE_EXTRA_EXCLUDES')
1733 if excludes:
1749 if excludes:
1734 py2exeexcludes.extend(excludes.split(' '))
1750 py2exeexcludes.extend(excludes.split(' '))
1735
1751
1736 dllexcludes = os.environ.get('HG_PY2EXE_EXTRA_DLL_EXCLUDES')
1752 dllexcludes = os.environ.get('HG_PY2EXE_EXTRA_DLL_EXCLUDES')
1737 if dllexcludes:
1753 if dllexcludes:
1738 py2exedllexcludes.extend(dllexcludes.split(' '))
1754 py2exedllexcludes.extend(dllexcludes.split(' '))
1739
1755
1740 if os.environ.get('PYOXIDIZER'):
1756 if os.environ.get('PYOXIDIZER'):
1741 hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
1757 hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
1742
1758
1743 if os.name == 'nt':
1759 if os.name == 'nt':
1744 # Windows binary file versions for exe/dll files must have the
1760 # Windows binary file versions for exe/dll files must have the
1745 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
1761 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
1746 setupversion = setupversion.split(r'+', 1)[0]
1762 setupversion = setupversion.split(r'+', 1)[0]
1747
1763
1748 setup(
1764 setup(
1749 name='mercurial',
1765 name='mercurial',
1750 version=setupversion,
1766 version=setupversion,
1751 author='Olivia Mackall and many others',
1767 author='Olivia Mackall and many others',
1752 author_email='mercurial@mercurial-scm.org',
1768 author_email='mercurial@mercurial-scm.org',
1753 url='https://mercurial-scm.org/',
1769 url='https://mercurial-scm.org/',
1754 download_url='https://mercurial-scm.org/release/',
1770 download_url='https://mercurial-scm.org/release/',
1755 description=(
1771 description=(
1756 'Fast scalable distributed SCM (revision control, version '
1772 'Fast scalable distributed SCM (revision control, version '
1757 'control) system'
1773 'control) system'
1758 ),
1774 ),
1759 long_description=(
1775 long_description=(
1760 'Mercurial is a distributed SCM tool written in Python.'
1776 'Mercurial is a distributed SCM tool written in Python.'
1761 ' It is used by a number of large projects that require'
1777 ' It is used by a number of large projects that require'
1762 ' fast, reliable distributed revision control, such as '
1778 ' fast, reliable distributed revision control, such as '
1763 'Mozilla.'
1779 'Mozilla.'
1764 ),
1780 ),
1765 license='GNU GPLv2 or any later version',
1781 license='GNU GPLv2 or any later version',
1766 classifiers=[
1782 classifiers=[
1767 'Development Status :: 6 - Mature',
1783 'Development Status :: 6 - Mature',
1768 'Environment :: Console',
1784 'Environment :: Console',
1769 'Intended Audience :: Developers',
1785 'Intended Audience :: Developers',
1770 'Intended Audience :: System Administrators',
1786 'Intended Audience :: System Administrators',
1771 'License :: OSI Approved :: GNU General Public License (GPL)',
1787 'License :: OSI Approved :: GNU General Public License (GPL)',
1772 'Natural Language :: Danish',
1788 'Natural Language :: Danish',
1773 'Natural Language :: English',
1789 'Natural Language :: English',
1774 'Natural Language :: German',
1790 'Natural Language :: German',
1775 'Natural Language :: Italian',
1791 'Natural Language :: Italian',
1776 'Natural Language :: Japanese',
1792 'Natural Language :: Japanese',
1777 'Natural Language :: Portuguese (Brazilian)',
1793 'Natural Language :: Portuguese (Brazilian)',
1778 'Operating System :: Microsoft :: Windows',
1794 'Operating System :: Microsoft :: Windows',
1779 'Operating System :: OS Independent',
1795 'Operating System :: OS Independent',
1780 'Operating System :: POSIX',
1796 'Operating System :: POSIX',
1781 'Programming Language :: C',
1797 'Programming Language :: C',
1782 'Programming Language :: Python',
1798 'Programming Language :: Python',
1783 'Topic :: Software Development :: Version Control',
1799 'Topic :: Software Development :: Version Control',
1784 ],
1800 ],
1785 scripts=scripts,
1801 scripts=scripts,
1786 packages=packages,
1802 packages=packages,
1787 ext_modules=extmodules,
1803 ext_modules=extmodules,
1788 data_files=datafiles,
1804 data_files=datafiles,
1789 package_data=packagedata,
1805 package_data=packagedata,
1790 cmdclass=cmdclass,
1806 cmdclass=cmdclass,
1791 distclass=hgdist,
1807 distclass=hgdist,
1792 options={
1808 options={
1793 'py2exe': {
1809 'py2exe': {
1794 'bundle_files': 3,
1810 'bundle_files': 3,
1795 'dll_excludes': py2exedllexcludes,
1811 'dll_excludes': py2exedllexcludes,
1796 'includes': py2exe_includes,
1812 'includes': py2exe_includes,
1797 'excludes': py2exeexcludes,
1813 'excludes': py2exeexcludes,
1798 'packages': py2exepackages,
1814 'packages': py2exepackages,
1799 },
1815 },
1800 'bdist_mpkg': {
1816 'bdist_mpkg': {
1801 'zipdist': False,
1817 'zipdist': False,
1802 'license': 'COPYING',
1818 'license': 'COPYING',
1803 'readme': 'contrib/packaging/macosx/Readme.html',
1819 'readme': 'contrib/packaging/macosx/Readme.html',
1804 'welcome': 'contrib/packaging/macosx/Welcome.html',
1820 'welcome': 'contrib/packaging/macosx/Welcome.html',
1805 },
1821 },
1806 },
1822 },
1807 **extra
1823 **extra
1808 )
1824 )
@@ -1,4081 +1,4082 b''
1 #!/usr/bin/env python3
1 #!/usr/bin/env python3
2 #
2 #
3 # run-tests.py - Run a set of tests on Mercurial
3 # run-tests.py - Run a set of tests on Mercurial
4 #
4 #
5 # Copyright 2006 Olivia Mackall <olivia@selenic.com>
5 # Copyright 2006 Olivia Mackall <olivia@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 # Modifying this script is tricky because it has many modes:
10 # Modifying this script is tricky because it has many modes:
11 # - serial (default) vs parallel (-jN, N > 1)
11 # - serial (default) vs parallel (-jN, N > 1)
12 # - no coverage (default) vs coverage (-c, -C, -s)
12 # - no coverage (default) vs coverage (-c, -C, -s)
13 # - temp install (default) vs specific hg script (--with-hg, --local)
13 # - temp install (default) vs specific hg script (--with-hg, --local)
14 # - tests are a mix of shell scripts and Python scripts
14 # - tests are a mix of shell scripts and Python scripts
15 #
15 #
16 # If you change this script, it is recommended that you ensure you
16 # If you change this script, it is recommended that you ensure you
17 # haven't broken it by running it in various modes with a representative
17 # haven't broken it by running it in various modes with a representative
18 # sample of test scripts. For example:
18 # sample of test scripts. For example:
19 #
19 #
20 # 1) serial, no coverage, temp install:
20 # 1) serial, no coverage, temp install:
21 # ./run-tests.py test-s*
21 # ./run-tests.py test-s*
22 # 2) serial, no coverage, local hg:
22 # 2) serial, no coverage, local hg:
23 # ./run-tests.py --local test-s*
23 # ./run-tests.py --local test-s*
24 # 3) serial, coverage, temp install:
24 # 3) serial, coverage, temp install:
25 # ./run-tests.py -c test-s*
25 # ./run-tests.py -c test-s*
26 # 4) serial, coverage, local hg:
26 # 4) serial, coverage, local hg:
27 # ./run-tests.py -c --local test-s* # unsupported
27 # ./run-tests.py -c --local test-s* # unsupported
28 # 5) parallel, no coverage, temp install:
28 # 5) parallel, no coverage, temp install:
29 # ./run-tests.py -j2 test-s*
29 # ./run-tests.py -j2 test-s*
30 # 6) parallel, no coverage, local hg:
30 # 6) parallel, no coverage, local hg:
31 # ./run-tests.py -j2 --local test-s*
31 # ./run-tests.py -j2 --local test-s*
32 # 7) parallel, coverage, temp install:
32 # 7) parallel, coverage, temp install:
33 # ./run-tests.py -j2 -c test-s* # currently broken
33 # ./run-tests.py -j2 -c test-s* # currently broken
34 # 8) parallel, coverage, local install:
34 # 8) parallel, coverage, local install:
35 # ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
35 # ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
36 # 9) parallel, custom tmp dir:
36 # 9) parallel, custom tmp dir:
37 # ./run-tests.py -j2 --tmpdir /tmp/myhgtests
37 # ./run-tests.py -j2 --tmpdir /tmp/myhgtests
38 # 10) parallel, pure, tests that call run-tests:
38 # 10) parallel, pure, tests that call run-tests:
39 # ./run-tests.py --pure `grep -l run-tests.py *.t`
39 # ./run-tests.py --pure `grep -l run-tests.py *.t`
40 #
40 #
41 # (You could use any subset of the tests: test-s* happens to match
41 # (You could use any subset of the tests: test-s* happens to match
42 # enough that it's worth doing parallel runs, few enough that it
42 # enough that it's worth doing parallel runs, few enough that it
43 # completes fairly quickly, includes both shell and Python scripts, and
43 # completes fairly quickly, includes both shell and Python scripts, and
44 # includes some scripts that run daemon processes.)
44 # includes some scripts that run daemon processes.)
45
45
46
46
47 import argparse
47 import argparse
48 import collections
48 import collections
49 import contextlib
49 import contextlib
50 import difflib
50 import difflib
51
51
52 import errno
52 import errno
53 import functools
53 import functools
54 import json
54 import json
55 import multiprocessing
55 import multiprocessing
56 import os
56 import os
57 import platform
57 import platform
58 import queue
58 import queue
59 import random
59 import random
60 import re
60 import re
61 import shlex
61 import shlex
62 import shutil
62 import shutil
63 import signal
63 import signal
64 import socket
64 import socket
65 import subprocess
65 import subprocess
66 import sys
66 import sys
67 import sysconfig
67 import sysconfig
68 import tempfile
68 import tempfile
69 import threading
69 import threading
70 import time
70 import time
71 import unittest
71 import unittest
72 import uuid
72 import uuid
73 import xml.dom.minidom as minidom
73 import xml.dom.minidom as minidom
74
74
75
75
76 if sys.version_info < (3, 5, 0):
76 if sys.version_info < (3, 5, 0):
77 print(
77 print(
78 '%s is only supported on Python 3.5+, not %s'
78 '%s is only supported on Python 3.5+, not %s'
79 % (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3]))
79 % (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3]))
80 )
80 )
81 sys.exit(70) # EX_SOFTWARE from `man 3 sysexit`
81 sys.exit(70) # EX_SOFTWARE from `man 3 sysexit`
82
82
83 MACOS = sys.platform == 'darwin'
83 MACOS = sys.platform == 'darwin'
84 WINDOWS = os.name == r'nt'
84 WINDOWS = os.name == r'nt'
85 shellquote = shlex.quote
85 shellquote = shlex.quote
86
86
87
87
88 processlock = threading.Lock()
88 processlock = threading.Lock()
89
89
90 pygmentspresent = False
90 pygmentspresent = False
91 try: # is pygments installed
91 try: # is pygments installed
92 import pygments
92 import pygments
93 import pygments.lexers as lexers
93 import pygments.lexers as lexers
94 import pygments.lexer as lexer
94 import pygments.lexer as lexer
95 import pygments.formatters as formatters
95 import pygments.formatters as formatters
96 import pygments.token as token
96 import pygments.token as token
97 import pygments.style as style
97 import pygments.style as style
98
98
99 if WINDOWS:
99 if WINDOWS:
100 hgpath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
100 hgpath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
101 sys.path.append(hgpath)
101 sys.path.append(hgpath)
102 try:
102 try:
103 from mercurial import win32 # pytype: disable=import-error
103 from mercurial import win32 # pytype: disable=import-error
104
104
105 # Don't check the result code because it fails on heptapod, but
105 # Don't check the result code because it fails on heptapod, but
106 # something is able to convert to color anyway.
106 # something is able to convert to color anyway.
107 win32.enablevtmode()
107 win32.enablevtmode()
108 finally:
108 finally:
109 sys.path = sys.path[:-1]
109 sys.path = sys.path[:-1]
110
110
111 pygmentspresent = True
111 pygmentspresent = True
112 difflexer = lexers.DiffLexer()
112 difflexer = lexers.DiffLexer()
113 terminal256formatter = formatters.Terminal256Formatter()
113 terminal256formatter = formatters.Terminal256Formatter()
114 except ImportError:
114 except ImportError:
115 pass
115 pass
116
116
117 if pygmentspresent:
117 if pygmentspresent:
118
118
119 class TestRunnerStyle(style.Style):
119 class TestRunnerStyle(style.Style):
120 default_style = ""
120 default_style = ""
121 skipped = token.string_to_tokentype("Token.Generic.Skipped")
121 skipped = token.string_to_tokentype("Token.Generic.Skipped")
122 failed = token.string_to_tokentype("Token.Generic.Failed")
122 failed = token.string_to_tokentype("Token.Generic.Failed")
123 skippedname = token.string_to_tokentype("Token.Generic.SName")
123 skippedname = token.string_to_tokentype("Token.Generic.SName")
124 failedname = token.string_to_tokentype("Token.Generic.FName")
124 failedname = token.string_to_tokentype("Token.Generic.FName")
125 styles = {
125 styles = {
126 skipped: '#e5e5e5',
126 skipped: '#e5e5e5',
127 skippedname: '#00ffff',
127 skippedname: '#00ffff',
128 failed: '#7f0000',
128 failed: '#7f0000',
129 failedname: '#ff0000',
129 failedname: '#ff0000',
130 }
130 }
131
131
132 class TestRunnerLexer(lexer.RegexLexer):
132 class TestRunnerLexer(lexer.RegexLexer):
133 testpattern = r'[\w-]+\.(t|py)(#[a-zA-Z0-9_\-\.]+)?'
133 testpattern = r'[\w-]+\.(t|py)(#[a-zA-Z0-9_\-\.]+)?'
134 tokens = {
134 tokens = {
135 'root': [
135 'root': [
136 (r'^Skipped', token.Generic.Skipped, 'skipped'),
136 (r'^Skipped', token.Generic.Skipped, 'skipped'),
137 (r'^Failed ', token.Generic.Failed, 'failed'),
137 (r'^Failed ', token.Generic.Failed, 'failed'),
138 (r'^ERROR: ', token.Generic.Failed, 'failed'),
138 (r'^ERROR: ', token.Generic.Failed, 'failed'),
139 ],
139 ],
140 'skipped': [
140 'skipped': [
141 (testpattern, token.Generic.SName),
141 (testpattern, token.Generic.SName),
142 (r':.*', token.Generic.Skipped),
142 (r':.*', token.Generic.Skipped),
143 ],
143 ],
144 'failed': [
144 'failed': [
145 (testpattern, token.Generic.FName),
145 (testpattern, token.Generic.FName),
146 (r'(:| ).*', token.Generic.Failed),
146 (r'(:| ).*', token.Generic.Failed),
147 ],
147 ],
148 }
148 }
149
149
150 runnerformatter = formatters.Terminal256Formatter(style=TestRunnerStyle)
150 runnerformatter = formatters.Terminal256Formatter(style=TestRunnerStyle)
151 runnerlexer = TestRunnerLexer()
151 runnerlexer = TestRunnerLexer()
152
152
153 origenviron = os.environ.copy()
153 origenviron = os.environ.copy()
154
154
155
155
156 def _sys2bytes(p):
156 def _sys2bytes(p):
157 if p is None:
157 if p is None:
158 return p
158 return p
159 return p.encode('utf-8')
159 return p.encode('utf-8')
160
160
161
161
162 def _bytes2sys(p):
162 def _bytes2sys(p):
163 if p is None:
163 if p is None:
164 return p
164 return p
165 return p.decode('utf-8')
165 return p.decode('utf-8')
166
166
167
167
168 original_env = os.environ.copy()
168 osenvironb = getattr(os, 'environb', None)
169 osenvironb = getattr(os, 'environb', None)
169 if osenvironb is None:
170 if osenvironb is None:
170 # Windows lacks os.environb, for instance. A proxy over the real thing
171 # Windows lacks os.environb, for instance. A proxy over the real thing
171 # instead of a copy allows the environment to be updated via bytes on
172 # instead of a copy allows the environment to be updated via bytes on
172 # all platforms.
173 # all platforms.
173 class environbytes:
174 class environbytes:
174 def __init__(self, strenv):
175 def __init__(self, strenv):
175 self.__len__ = strenv.__len__
176 self.__len__ = strenv.__len__
176 self.clear = strenv.clear
177 self.clear = strenv.clear
177 self._strenv = strenv
178 self._strenv = strenv
178
179
179 def __getitem__(self, k):
180 def __getitem__(self, k):
180 v = self._strenv.__getitem__(_bytes2sys(k))
181 v = self._strenv.__getitem__(_bytes2sys(k))
181 return _sys2bytes(v)
182 return _sys2bytes(v)
182
183
183 def __setitem__(self, k, v):
184 def __setitem__(self, k, v):
184 self._strenv.__setitem__(_bytes2sys(k), _bytes2sys(v))
185 self._strenv.__setitem__(_bytes2sys(k), _bytes2sys(v))
185
186
186 def __delitem__(self, k):
187 def __delitem__(self, k):
187 self._strenv.__delitem__(_bytes2sys(k))
188 self._strenv.__delitem__(_bytes2sys(k))
188
189
189 def __contains__(self, k):
190 def __contains__(self, k):
190 return self._strenv.__contains__(_bytes2sys(k))
191 return self._strenv.__contains__(_bytes2sys(k))
191
192
192 def __iter__(self):
193 def __iter__(self):
193 return iter([_sys2bytes(k) for k in iter(self._strenv)])
194 return iter([_sys2bytes(k) for k in iter(self._strenv)])
194
195
195 def get(self, k, default=None):
196 def get(self, k, default=None):
196 v = self._strenv.get(_bytes2sys(k), _bytes2sys(default))
197 v = self._strenv.get(_bytes2sys(k), _bytes2sys(default))
197 return _sys2bytes(v)
198 return _sys2bytes(v)
198
199
199 def pop(self, k, default=None):
200 def pop(self, k, default=None):
200 v = self._strenv.pop(_bytes2sys(k), _bytes2sys(default))
201 v = self._strenv.pop(_bytes2sys(k), _bytes2sys(default))
201 return _sys2bytes(v)
202 return _sys2bytes(v)
202
203
203 osenvironb = environbytes(os.environ)
204 osenvironb = environbytes(os.environ)
204
205
205 getcwdb = getattr(os, 'getcwdb')
206 getcwdb = getattr(os, 'getcwdb')
206 if not getcwdb or WINDOWS:
207 if not getcwdb or WINDOWS:
207 getcwdb = lambda: _sys2bytes(os.getcwd())
208 getcwdb = lambda: _sys2bytes(os.getcwd())
208
209
209
210
210 if WINDOWS:
211 if WINDOWS:
211 _getcwdb = getcwdb
212 _getcwdb = getcwdb
212
213
213 def getcwdb():
214 def getcwdb():
214 cwd = _getcwdb()
215 cwd = _getcwdb()
215 if re.match(b'^[a-z]:', cwd):
216 if re.match(b'^[a-z]:', cwd):
216 # os.getcwd() is inconsistent on the capitalization of the drive
217 # os.getcwd() is inconsistent on the capitalization of the drive
217 # letter, so adjust it. see https://bugs.python.org/issue40368
218 # letter, so adjust it. see https://bugs.python.org/issue40368
218 cwd = cwd[0:1].upper() + cwd[1:]
219 cwd = cwd[0:1].upper() + cwd[1:]
219 return cwd
220 return cwd
220
221
221
222
222 # For Windows support
223 # For Windows support
223 wifexited = getattr(os, "WIFEXITED", lambda x: False)
224 wifexited = getattr(os, "WIFEXITED", lambda x: False)
224
225
225 # Whether to use IPv6
226 # Whether to use IPv6
226 def checksocketfamily(name, port=20058):
227 def checksocketfamily(name, port=20058):
227 """return true if we can listen on localhost using family=name
228 """return true if we can listen on localhost using family=name
228
229
229 name should be either 'AF_INET', or 'AF_INET6'.
230 name should be either 'AF_INET', or 'AF_INET6'.
230 port being used is okay - EADDRINUSE is considered as successful.
231 port being used is okay - EADDRINUSE is considered as successful.
231 """
232 """
232 family = getattr(socket, name, None)
233 family = getattr(socket, name, None)
233 if family is None:
234 if family is None:
234 return False
235 return False
235 try:
236 try:
236 s = socket.socket(family, socket.SOCK_STREAM)
237 s = socket.socket(family, socket.SOCK_STREAM)
237 s.bind(('localhost', port))
238 s.bind(('localhost', port))
238 s.close()
239 s.close()
239 return True
240 return True
240 except (socket.error, OSError) as exc:
241 except (socket.error, OSError) as exc:
241 if exc.errno == errno.EADDRINUSE:
242 if exc.errno == errno.EADDRINUSE:
242 return True
243 return True
243 elif exc.errno in (
244 elif exc.errno in (
244 errno.EADDRNOTAVAIL,
245 errno.EADDRNOTAVAIL,
245 errno.EPROTONOSUPPORT,
246 errno.EPROTONOSUPPORT,
246 errno.EAFNOSUPPORT,
247 errno.EAFNOSUPPORT,
247 ):
248 ):
248 return False
249 return False
249 else:
250 else:
250 raise
251 raise
251 else:
252 else:
252 return False
253 return False
253
254
254
255
255 # useipv6 will be set by parseargs
256 # useipv6 will be set by parseargs
256 useipv6 = None
257 useipv6 = None
257
258
258
259
259 def checkportisavailable(port):
260 def checkportisavailable(port):
260 """return true if a port seems free to bind on localhost"""
261 """return true if a port seems free to bind on localhost"""
261 if useipv6:
262 if useipv6:
262 family = socket.AF_INET6
263 family = socket.AF_INET6
263 else:
264 else:
264 family = socket.AF_INET
265 family = socket.AF_INET
265 try:
266 try:
266 with contextlib.closing(socket.socket(family, socket.SOCK_STREAM)) as s:
267 with contextlib.closing(socket.socket(family, socket.SOCK_STREAM)) as s:
267 s.bind(('localhost', port))
268 s.bind(('localhost', port))
268 return True
269 return True
269 except PermissionError:
270 except PermissionError:
270 return False
271 return False
271 except socket.error as exc:
272 except socket.error as exc:
272 if WINDOWS and exc.errno == errno.WSAEACCES:
273 if WINDOWS and exc.errno == errno.WSAEACCES:
273 return False
274 return False
274 if exc.errno not in (
275 if exc.errno not in (
275 errno.EADDRINUSE,
276 errno.EADDRINUSE,
276 errno.EADDRNOTAVAIL,
277 errno.EADDRNOTAVAIL,
277 errno.EPROTONOSUPPORT,
278 errno.EPROTONOSUPPORT,
278 ):
279 ):
279 raise
280 raise
280 return False
281 return False
281
282
282
283
283 closefds = os.name == 'posix'
284 closefds = os.name == 'posix'
284
285
285
286
286 def Popen4(cmd, wd, timeout, env=None):
287 def Popen4(cmd, wd, timeout, env=None):
287 processlock.acquire()
288 processlock.acquire()
288 p = subprocess.Popen(
289 p = subprocess.Popen(
289 _bytes2sys(cmd),
290 _bytes2sys(cmd),
290 shell=True,
291 shell=True,
291 bufsize=-1,
292 bufsize=-1,
292 cwd=_bytes2sys(wd),
293 cwd=_bytes2sys(wd),
293 env=env,
294 env=env,
294 close_fds=closefds,
295 close_fds=closefds,
295 stdin=subprocess.PIPE,
296 stdin=subprocess.PIPE,
296 stdout=subprocess.PIPE,
297 stdout=subprocess.PIPE,
297 stderr=subprocess.STDOUT,
298 stderr=subprocess.STDOUT,
298 )
299 )
299 processlock.release()
300 processlock.release()
300
301
301 p.fromchild = p.stdout
302 p.fromchild = p.stdout
302 p.tochild = p.stdin
303 p.tochild = p.stdin
303 p.childerr = p.stderr
304 p.childerr = p.stderr
304
305
305 p.timeout = False
306 p.timeout = False
306 if timeout:
307 if timeout:
307
308
308 def t():
309 def t():
309 start = time.time()
310 start = time.time()
310 while time.time() - start < timeout and p.returncode is None:
311 while time.time() - start < timeout and p.returncode is None:
311 time.sleep(0.1)
312 time.sleep(0.1)
312 p.timeout = True
313 p.timeout = True
313 vlog('# Timout reached for process %d' % p.pid)
314 vlog('# Timout reached for process %d' % p.pid)
314 if p.returncode is None:
315 if p.returncode is None:
315 terminate(p)
316 terminate(p)
316
317
317 threading.Thread(target=t).start()
318 threading.Thread(target=t).start()
318
319
319 return p
320 return p
320
321
321
322
322 if sys.executable:
323 if sys.executable:
323 sysexecutable = sys.executable
324 sysexecutable = sys.executable
324 elif os.environ.get('PYTHONEXECUTABLE'):
325 elif os.environ.get('PYTHONEXECUTABLE'):
325 sysexecutable = os.environ['PYTHONEXECUTABLE']
326 sysexecutable = os.environ['PYTHONEXECUTABLE']
326 elif os.environ.get('PYTHON'):
327 elif os.environ.get('PYTHON'):
327 sysexecutable = os.environ['PYTHON']
328 sysexecutable = os.environ['PYTHON']
328 else:
329 else:
329 raise AssertionError('Could not find Python interpreter')
330 raise AssertionError('Could not find Python interpreter')
330
331
331 PYTHON = _sys2bytes(sysexecutable.replace('\\', '/'))
332 PYTHON = _sys2bytes(sysexecutable.replace('\\', '/'))
332 IMPL_PATH = b'PYTHONPATH'
333 IMPL_PATH = b'PYTHONPATH'
333 if 'java' in sys.platform:
334 if 'java' in sys.platform:
334 IMPL_PATH = b'JYTHONPATH'
335 IMPL_PATH = b'JYTHONPATH'
335
336
336 default_defaults = {
337 default_defaults = {
337 'jobs': ('HGTEST_JOBS', multiprocessing.cpu_count()),
338 'jobs': ('HGTEST_JOBS', multiprocessing.cpu_count()),
338 'timeout': ('HGTEST_TIMEOUT', 360),
339 'timeout': ('HGTEST_TIMEOUT', 360),
339 'slowtimeout': ('HGTEST_SLOWTIMEOUT', 1500),
340 'slowtimeout': ('HGTEST_SLOWTIMEOUT', 1500),
340 'port': ('HGTEST_PORT', 20059),
341 'port': ('HGTEST_PORT', 20059),
341 'shell': ('HGTEST_SHELL', 'sh'),
342 'shell': ('HGTEST_SHELL', 'sh'),
342 }
343 }
343
344
344 defaults = default_defaults.copy()
345 defaults = default_defaults.copy()
345
346
346
347
347 def canonpath(path):
348 def canonpath(path):
348 return os.path.realpath(os.path.expanduser(path))
349 return os.path.realpath(os.path.expanduser(path))
349
350
350
351
351 def which(exe):
352 def which(exe):
352 # shutil.which only accept bytes from 3.8
353 # shutil.which only accept bytes from 3.8
353 cmd = _bytes2sys(exe)
354 cmd = _bytes2sys(exe)
354 real_exec = shutil.which(cmd)
355 real_exec = shutil.which(cmd)
355 return _sys2bytes(real_exec)
356 return _sys2bytes(real_exec)
356
357
357
358
358 def parselistfiles(files, listtype, warn=True):
359 def parselistfiles(files, listtype, warn=True):
359 entries = dict()
360 entries = dict()
360 for filename in files:
361 for filename in files:
361 try:
362 try:
362 path = os.path.expanduser(os.path.expandvars(filename))
363 path = os.path.expanduser(os.path.expandvars(filename))
363 f = open(path, "rb")
364 f = open(path, "rb")
364 except FileNotFoundError:
365 except FileNotFoundError:
365 if warn:
366 if warn:
366 print("warning: no such %s file: %s" % (listtype, filename))
367 print("warning: no such %s file: %s" % (listtype, filename))
367 continue
368 continue
368
369
369 for line in f.readlines():
370 for line in f.readlines():
370 line = line.split(b'#', 1)[0].strip()
371 line = line.split(b'#', 1)[0].strip()
371 if line:
372 if line:
372 # Ensure path entries are compatible with os.path.relpath()
373 # Ensure path entries are compatible with os.path.relpath()
373 entries[os.path.normpath(line)] = filename
374 entries[os.path.normpath(line)] = filename
374
375
375 f.close()
376 f.close()
376 return entries
377 return entries
377
378
378
379
379 def parsettestcases(path):
380 def parsettestcases(path):
380 """read a .t test file, return a set of test case names
381 """read a .t test file, return a set of test case names
381
382
382 If path does not exist, return an empty set.
383 If path does not exist, return an empty set.
383 """
384 """
384 cases = []
385 cases = []
385 try:
386 try:
386 with open(path, 'rb') as f:
387 with open(path, 'rb') as f:
387 for l in f:
388 for l in f:
388 if l.startswith(b'#testcases '):
389 if l.startswith(b'#testcases '):
389 cases.append(sorted(l[11:].split()))
390 cases.append(sorted(l[11:].split()))
390 except FileNotFoundError:
391 except FileNotFoundError:
391 pass
392 pass
392 return cases
393 return cases
393
394
394
395
395 def getparser():
396 def getparser():
396 """Obtain the OptionParser used by the CLI."""
397 """Obtain the OptionParser used by the CLI."""
397 parser = argparse.ArgumentParser(usage='%(prog)s [options] [tests]')
398 parser = argparse.ArgumentParser(usage='%(prog)s [options] [tests]')
398
399
399 selection = parser.add_argument_group('Test Selection')
400 selection = parser.add_argument_group('Test Selection')
400 selection.add_argument(
401 selection.add_argument(
401 '--allow-slow-tests',
402 '--allow-slow-tests',
402 action='store_true',
403 action='store_true',
403 help='allow extremely slow tests',
404 help='allow extremely slow tests',
404 )
405 )
405 selection.add_argument(
406 selection.add_argument(
406 "--blacklist",
407 "--blacklist",
407 action="append",
408 action="append",
408 help="skip tests listed in the specified blacklist file",
409 help="skip tests listed in the specified blacklist file",
409 )
410 )
410 selection.add_argument(
411 selection.add_argument(
411 "--changed",
412 "--changed",
412 help="run tests that are changed in parent rev or working directory",
413 help="run tests that are changed in parent rev or working directory",
413 )
414 )
414 selection.add_argument(
415 selection.add_argument(
415 "-k", "--keywords", help="run tests matching keywords"
416 "-k", "--keywords", help="run tests matching keywords"
416 )
417 )
417 selection.add_argument(
418 selection.add_argument(
418 "-r", "--retest", action="store_true", help="retest failed tests"
419 "-r", "--retest", action="store_true", help="retest failed tests"
419 )
420 )
420 selection.add_argument(
421 selection.add_argument(
421 "--test-list",
422 "--test-list",
422 action="append",
423 action="append",
423 help="read tests to run from the specified file",
424 help="read tests to run from the specified file",
424 )
425 )
425 selection.add_argument(
426 selection.add_argument(
426 "--whitelist",
427 "--whitelist",
427 action="append",
428 action="append",
428 help="always run tests listed in the specified whitelist file",
429 help="always run tests listed in the specified whitelist file",
429 )
430 )
430 selection.add_argument(
431 selection.add_argument(
431 'tests', metavar='TESTS', nargs='*', help='Tests to run'
432 'tests', metavar='TESTS', nargs='*', help='Tests to run'
432 )
433 )
433
434
434 harness = parser.add_argument_group('Test Harness Behavior')
435 harness = parser.add_argument_group('Test Harness Behavior')
435 harness.add_argument(
436 harness.add_argument(
436 '--bisect-repo',
437 '--bisect-repo',
437 metavar='bisect_repo',
438 metavar='bisect_repo',
438 help=(
439 help=(
439 "Path of a repo to bisect. Use together with " "--known-good-rev"
440 "Path of a repo to bisect. Use together with " "--known-good-rev"
440 ),
441 ),
441 )
442 )
442 harness.add_argument(
443 harness.add_argument(
443 "-d",
444 "-d",
444 "--debug",
445 "--debug",
445 action="store_true",
446 action="store_true",
446 help="debug mode: write output of test scripts to console"
447 help="debug mode: write output of test scripts to console"
447 " rather than capturing and diffing it (disables timeout)",
448 " rather than capturing and diffing it (disables timeout)",
448 )
449 )
449 harness.add_argument(
450 harness.add_argument(
450 "-f",
451 "-f",
451 "--first",
452 "--first",
452 action="store_true",
453 action="store_true",
453 help="exit on the first test failure",
454 help="exit on the first test failure",
454 )
455 )
455 harness.add_argument(
456 harness.add_argument(
456 "-i",
457 "-i",
457 "--interactive",
458 "--interactive",
458 action="store_true",
459 action="store_true",
459 help="prompt to accept changed output",
460 help="prompt to accept changed output",
460 )
461 )
461 harness.add_argument(
462 harness.add_argument(
462 "-j",
463 "-j",
463 "--jobs",
464 "--jobs",
464 type=int,
465 type=int,
465 help="number of jobs to run in parallel"
466 help="number of jobs to run in parallel"
466 " (default: $%s or %d)" % defaults['jobs'],
467 " (default: $%s or %d)" % defaults['jobs'],
467 )
468 )
468 harness.add_argument(
469 harness.add_argument(
469 "--keep-tmpdir",
470 "--keep-tmpdir",
470 action="store_true",
471 action="store_true",
471 help="keep temporary directory after running tests",
472 help="keep temporary directory after running tests",
472 )
473 )
473 harness.add_argument(
474 harness.add_argument(
474 '--known-good-rev',
475 '--known-good-rev',
475 metavar="known_good_rev",
476 metavar="known_good_rev",
476 help=(
477 help=(
477 "Automatically bisect any failures using this "
478 "Automatically bisect any failures using this "
478 "revision as a known-good revision."
479 "revision as a known-good revision."
479 ),
480 ),
480 )
481 )
481 harness.add_argument(
482 harness.add_argument(
482 "--list-tests",
483 "--list-tests",
483 action="store_true",
484 action="store_true",
484 help="list tests instead of running them",
485 help="list tests instead of running them",
485 )
486 )
486 harness.add_argument(
487 harness.add_argument(
487 "--loop", action="store_true", help="loop tests repeatedly"
488 "--loop", action="store_true", help="loop tests repeatedly"
488 )
489 )
489 harness.add_argument(
490 harness.add_argument(
490 '--random', action="store_true", help='run tests in random order'
491 '--random', action="store_true", help='run tests in random order'
491 )
492 )
492 harness.add_argument(
493 harness.add_argument(
493 '--order-by-runtime',
494 '--order-by-runtime',
494 action="store_true",
495 action="store_true",
495 help='run slowest tests first, according to .testtimes',
496 help='run slowest tests first, according to .testtimes',
496 )
497 )
497 harness.add_argument(
498 harness.add_argument(
498 "-p",
499 "-p",
499 "--port",
500 "--port",
500 type=int,
501 type=int,
501 help="port on which servers should listen"
502 help="port on which servers should listen"
502 " (default: $%s or %d)" % defaults['port'],
503 " (default: $%s or %d)" % defaults['port'],
503 )
504 )
504 harness.add_argument(
505 harness.add_argument(
505 '--profile-runner',
506 '--profile-runner',
506 action='store_true',
507 action='store_true',
507 help='run statprof on run-tests',
508 help='run statprof on run-tests',
508 )
509 )
509 harness.add_argument(
510 harness.add_argument(
510 "-R", "--restart", action="store_true", help="restart at last error"
511 "-R", "--restart", action="store_true", help="restart at last error"
511 )
512 )
512 harness.add_argument(
513 harness.add_argument(
513 "--runs-per-test",
514 "--runs-per-test",
514 type=int,
515 type=int,
515 dest="runs_per_test",
516 dest="runs_per_test",
516 help="run each test N times (default=1)",
517 help="run each test N times (default=1)",
517 default=1,
518 default=1,
518 )
519 )
519 harness.add_argument(
520 harness.add_argument(
520 "--shell", help="shell to use (default: $%s or %s)" % defaults['shell']
521 "--shell", help="shell to use (default: $%s or %s)" % defaults['shell']
521 )
522 )
522 harness.add_argument(
523 harness.add_argument(
523 '--showchannels', action='store_true', help='show scheduling channels'
524 '--showchannels', action='store_true', help='show scheduling channels'
524 )
525 )
525 harness.add_argument(
526 harness.add_argument(
526 "--slowtimeout",
527 "--slowtimeout",
527 type=int,
528 type=int,
528 help="kill errant slow tests after SLOWTIMEOUT seconds"
529 help="kill errant slow tests after SLOWTIMEOUT seconds"
529 " (default: $%s or %d)" % defaults['slowtimeout'],
530 " (default: $%s or %d)" % defaults['slowtimeout'],
530 )
531 )
531 harness.add_argument(
532 harness.add_argument(
532 "-t",
533 "-t",
533 "--timeout",
534 "--timeout",
534 type=int,
535 type=int,
535 help="kill errant tests after TIMEOUT seconds"
536 help="kill errant tests after TIMEOUT seconds"
536 " (default: $%s or %d)" % defaults['timeout'],
537 " (default: $%s or %d)" % defaults['timeout'],
537 )
538 )
538 harness.add_argument(
539 harness.add_argument(
539 "--tmpdir",
540 "--tmpdir",
540 help="run tests in the given temporary directory"
541 help="run tests in the given temporary directory"
541 " (implies --keep-tmpdir)",
542 " (implies --keep-tmpdir)",
542 )
543 )
543 harness.add_argument(
544 harness.add_argument(
544 "-v", "--verbose", action="store_true", help="output verbose messages"
545 "-v", "--verbose", action="store_true", help="output verbose messages"
545 )
546 )
546
547
547 hgconf = parser.add_argument_group('Mercurial Configuration')
548 hgconf = parser.add_argument_group('Mercurial Configuration')
548 hgconf.add_argument(
549 hgconf.add_argument(
549 "--chg",
550 "--chg",
550 action="store_true",
551 action="store_true",
551 help="install and use chg wrapper in place of hg",
552 help="install and use chg wrapper in place of hg",
552 )
553 )
553 hgconf.add_argument(
554 hgconf.add_argument(
554 "--chg-debug",
555 "--chg-debug",
555 action="store_true",
556 action="store_true",
556 help="show chg debug logs",
557 help="show chg debug logs",
557 )
558 )
558 hgconf.add_argument(
559 hgconf.add_argument(
559 "--rhg",
560 "--rhg",
560 action="store_true",
561 action="store_true",
561 help="install and use rhg Rust implementation in place of hg",
562 help="install and use rhg Rust implementation in place of hg",
562 )
563 )
563 hgconf.add_argument(
564 hgconf.add_argument(
564 "--pyoxidized",
565 "--pyoxidized",
565 action="store_true",
566 action="store_true",
566 help="build the hg binary using pyoxidizer",
567 help="build the hg binary using pyoxidizer",
567 )
568 )
568 hgconf.add_argument("--compiler", help="compiler to build with")
569 hgconf.add_argument("--compiler", help="compiler to build with")
569 hgconf.add_argument(
570 hgconf.add_argument(
570 '--extra-config-opt',
571 '--extra-config-opt',
571 action="append",
572 action="append",
572 default=[],
573 default=[],
573 help='set the given config opt in the test hgrc',
574 help='set the given config opt in the test hgrc',
574 )
575 )
575 hgconf.add_argument(
576 hgconf.add_argument(
576 "-l",
577 "-l",
577 "--local",
578 "--local",
578 action="store_true",
579 action="store_true",
579 help="shortcut for --with-hg=<testdir>/../hg, "
580 help="shortcut for --with-hg=<testdir>/../hg, "
580 "--with-rhg=<testdir>/../rust/target/release/rhg if --rhg is set, "
581 "--with-rhg=<testdir>/../rust/target/release/rhg if --rhg is set, "
581 "and --with-chg=<testdir>/../contrib/chg/chg if --chg is set",
582 "and --with-chg=<testdir>/../contrib/chg/chg if --chg is set",
582 )
583 )
583 hgconf.add_argument(
584 hgconf.add_argument(
584 "--ipv6",
585 "--ipv6",
585 action="store_true",
586 action="store_true",
586 help="prefer IPv6 to IPv4 for network related tests",
587 help="prefer IPv6 to IPv4 for network related tests",
587 )
588 )
588 hgconf.add_argument(
589 hgconf.add_argument(
589 "--pure",
590 "--pure",
590 action="store_true",
591 action="store_true",
591 help="use pure Python code instead of C extensions",
592 help="use pure Python code instead of C extensions",
592 )
593 )
593 hgconf.add_argument(
594 hgconf.add_argument(
594 "--rust",
595 "--rust",
595 action="store_true",
596 action="store_true",
596 help="use Rust code alongside C extensions",
597 help="use Rust code alongside C extensions",
597 )
598 )
598 hgconf.add_argument(
599 hgconf.add_argument(
599 "--no-rust",
600 "--no-rust",
600 action="store_true",
601 action="store_true",
601 help="do not use Rust code even if compiled",
602 help="do not use Rust code even if compiled",
602 )
603 )
603 hgconf.add_argument(
604 hgconf.add_argument(
604 "--with-chg",
605 "--with-chg",
605 metavar="CHG",
606 metavar="CHG",
606 help="use specified chg wrapper in place of hg",
607 help="use specified chg wrapper in place of hg",
607 )
608 )
608 hgconf.add_argument(
609 hgconf.add_argument(
609 "--with-rhg",
610 "--with-rhg",
610 metavar="RHG",
611 metavar="RHG",
611 help="use specified rhg Rust implementation in place of hg",
612 help="use specified rhg Rust implementation in place of hg",
612 )
613 )
613 hgconf.add_argument(
614 hgconf.add_argument(
614 "--with-hg",
615 "--with-hg",
615 metavar="HG",
616 metavar="HG",
616 help="test using specified hg script rather than a "
617 help="test using specified hg script rather than a "
617 "temporary installation",
618 "temporary installation",
618 )
619 )
619
620
620 reporting = parser.add_argument_group('Results Reporting')
621 reporting = parser.add_argument_group('Results Reporting')
621 reporting.add_argument(
622 reporting.add_argument(
622 "-C",
623 "-C",
623 "--annotate",
624 "--annotate",
624 action="store_true",
625 action="store_true",
625 help="output files annotated with coverage",
626 help="output files annotated with coverage",
626 )
627 )
627 reporting.add_argument(
628 reporting.add_argument(
628 "--color",
629 "--color",
629 choices=["always", "auto", "never"],
630 choices=["always", "auto", "never"],
630 default=os.environ.get('HGRUNTESTSCOLOR', 'auto'),
631 default=os.environ.get('HGRUNTESTSCOLOR', 'auto'),
631 help="colorisation: always|auto|never (default: auto)",
632 help="colorisation: always|auto|never (default: auto)",
632 )
633 )
633 reporting.add_argument(
634 reporting.add_argument(
634 "-c",
635 "-c",
635 "--cover",
636 "--cover",
636 action="store_true",
637 action="store_true",
637 help="print a test coverage report",
638 help="print a test coverage report",
638 )
639 )
639 reporting.add_argument(
640 reporting.add_argument(
640 '--exceptions',
641 '--exceptions',
641 action='store_true',
642 action='store_true',
642 help='log all exceptions and generate an exception report',
643 help='log all exceptions and generate an exception report',
643 )
644 )
644 reporting.add_argument(
645 reporting.add_argument(
645 "-H",
646 "-H",
646 "--htmlcov",
647 "--htmlcov",
647 action="store_true",
648 action="store_true",
648 help="create an HTML report of the coverage of the files",
649 help="create an HTML report of the coverage of the files",
649 )
650 )
650 reporting.add_argument(
651 reporting.add_argument(
651 "--json",
652 "--json",
652 action="store_true",
653 action="store_true",
653 help="store test result data in 'report.json' file",
654 help="store test result data in 'report.json' file",
654 )
655 )
655 reporting.add_argument(
656 reporting.add_argument(
656 "--outputdir",
657 "--outputdir",
657 help="directory to write error logs to (default=test directory)",
658 help="directory to write error logs to (default=test directory)",
658 )
659 )
659 reporting.add_argument(
660 reporting.add_argument(
660 "-n", "--nodiff", action="store_true", help="skip showing test changes"
661 "-n", "--nodiff", action="store_true", help="skip showing test changes"
661 )
662 )
662 reporting.add_argument(
663 reporting.add_argument(
663 "-S",
664 "-S",
664 "--noskips",
665 "--noskips",
665 action="store_true",
666 action="store_true",
666 help="don't report skip tests verbosely",
667 help="don't report skip tests verbosely",
667 )
668 )
668 reporting.add_argument(
669 reporting.add_argument(
669 "--time", action="store_true", help="time how long each test takes"
670 "--time", action="store_true", help="time how long each test takes"
670 )
671 )
671 reporting.add_argument("--view", help="external diff viewer")
672 reporting.add_argument("--view", help="external diff viewer")
672 reporting.add_argument(
673 reporting.add_argument(
673 "--xunit", help="record xunit results at specified path"
674 "--xunit", help="record xunit results at specified path"
674 )
675 )
675
676
676 for option, (envvar, default) in defaults.items():
677 for option, (envvar, default) in defaults.items():
677 defaults[option] = type(default)(os.environ.get(envvar, default))
678 defaults[option] = type(default)(os.environ.get(envvar, default))
678 parser.set_defaults(**defaults)
679 parser.set_defaults(**defaults)
679
680
680 return parser
681 return parser
681
682
682
683
683 def parseargs(args, parser):
684 def parseargs(args, parser):
684 """Parse arguments with our OptionParser and validate results."""
685 """Parse arguments with our OptionParser and validate results."""
685 options = parser.parse_args(args)
686 options = parser.parse_args(args)
686
687
687 # jython is always pure
688 # jython is always pure
688 if 'java' in sys.platform or '__pypy__' in sys.modules:
689 if 'java' in sys.platform or '__pypy__' in sys.modules:
689 options.pure = True
690 options.pure = True
690
691
691 if platform.python_implementation() != 'CPython' and options.rust:
692 if platform.python_implementation() != 'CPython' and options.rust:
692 parser.error('Rust extensions are only available with CPython')
693 parser.error('Rust extensions are only available with CPython')
693
694
694 if options.pure and options.rust:
695 if options.pure and options.rust:
695 parser.error('--rust cannot be used with --pure')
696 parser.error('--rust cannot be used with --pure')
696
697
697 if options.rust and options.no_rust:
698 if options.rust and options.no_rust:
698 parser.error('--rust cannot be used with --no-rust')
699 parser.error('--rust cannot be used with --no-rust')
699
700
700 if options.local:
701 if options.local:
701 if options.with_hg or options.with_rhg or options.with_chg:
702 if options.with_hg or options.with_rhg or options.with_chg:
702 parser.error(
703 parser.error(
703 '--local cannot be used with --with-hg or --with-rhg or --with-chg'
704 '--local cannot be used with --with-hg or --with-rhg or --with-chg'
704 )
705 )
705 if options.pyoxidized:
706 if options.pyoxidized:
706 parser.error('--pyoxidized does not work with --local (yet)')
707 parser.error('--pyoxidized does not work with --local (yet)')
707 testdir = os.path.dirname(_sys2bytes(canonpath(sys.argv[0])))
708 testdir = os.path.dirname(_sys2bytes(canonpath(sys.argv[0])))
708 reporootdir = os.path.dirname(testdir)
709 reporootdir = os.path.dirname(testdir)
709 pathandattrs = [(b'hg', 'with_hg')]
710 pathandattrs = [(b'hg', 'with_hg')]
710 if options.chg:
711 if options.chg:
711 pathandattrs.append((b'contrib/chg/chg', 'with_chg'))
712 pathandattrs.append((b'contrib/chg/chg', 'with_chg'))
712 if options.rhg:
713 if options.rhg:
713 pathandattrs.append((b'rust/target/release/rhg', 'with_rhg'))
714 pathandattrs.append((b'rust/target/release/rhg', 'with_rhg'))
714 for relpath, attr in pathandattrs:
715 for relpath, attr in pathandattrs:
715 binpath = os.path.join(reporootdir, relpath)
716 binpath = os.path.join(reporootdir, relpath)
716 if not (WINDOWS or os.access(binpath, os.X_OK)):
717 if not (WINDOWS or os.access(binpath, os.X_OK)):
717 parser.error(
718 parser.error(
718 '--local specified, but %r not found or '
719 '--local specified, but %r not found or '
719 'not executable' % binpath
720 'not executable' % binpath
720 )
721 )
721 setattr(options, attr, _bytes2sys(binpath))
722 setattr(options, attr, _bytes2sys(binpath))
722
723
723 if options.with_hg:
724 if options.with_hg:
724 options.with_hg = canonpath(_sys2bytes(options.with_hg))
725 options.with_hg = canonpath(_sys2bytes(options.with_hg))
725 if not (
726 if not (
726 os.path.isfile(options.with_hg)
727 os.path.isfile(options.with_hg)
727 and os.access(options.with_hg, os.X_OK)
728 and os.access(options.with_hg, os.X_OK)
728 ):
729 ):
729 parser.error('--with-hg must specify an executable hg script')
730 parser.error('--with-hg must specify an executable hg script')
730 if os.path.basename(options.with_hg) not in [b'hg', b'hg.exe']:
731 if os.path.basename(options.with_hg) not in [b'hg', b'hg.exe']:
731 msg = 'warning: --with-hg should specify an hg script, not: %s\n'
732 msg = 'warning: --with-hg should specify an hg script, not: %s\n'
732 msg %= _bytes2sys(os.path.basename(options.with_hg))
733 msg %= _bytes2sys(os.path.basename(options.with_hg))
733 sys.stderr.write(msg)
734 sys.stderr.write(msg)
734 sys.stderr.flush()
735 sys.stderr.flush()
735
736
736 if (options.chg or options.with_chg) and WINDOWS:
737 if (options.chg or options.with_chg) and WINDOWS:
737 parser.error('chg does not work on %s' % os.name)
738 parser.error('chg does not work on %s' % os.name)
738 if (options.rhg or options.with_rhg) and WINDOWS:
739 if (options.rhg or options.with_rhg) and WINDOWS:
739 parser.error('rhg does not work on %s' % os.name)
740 parser.error('rhg does not work on %s' % os.name)
740 if options.pyoxidized and not (MACOS or WINDOWS):
741 if options.pyoxidized and not (MACOS or WINDOWS):
741 parser.error('--pyoxidized is currently macOS and Windows only')
742 parser.error('--pyoxidized is currently macOS and Windows only')
742 if options.with_chg:
743 if options.with_chg:
743 options.chg = False # no installation to temporary location
744 options.chg = False # no installation to temporary location
744 options.with_chg = canonpath(_sys2bytes(options.with_chg))
745 options.with_chg = canonpath(_sys2bytes(options.with_chg))
745 if not (
746 if not (
746 os.path.isfile(options.with_chg)
747 os.path.isfile(options.with_chg)
747 and os.access(options.with_chg, os.X_OK)
748 and os.access(options.with_chg, os.X_OK)
748 ):
749 ):
749 parser.error('--with-chg must specify a chg executable')
750 parser.error('--with-chg must specify a chg executable')
750 if options.with_rhg:
751 if options.with_rhg:
751 options.rhg = False # no installation to temporary location
752 options.rhg = False # no installation to temporary location
752 options.with_rhg = canonpath(_sys2bytes(options.with_rhg))
753 options.with_rhg = canonpath(_sys2bytes(options.with_rhg))
753 if not (
754 if not (
754 os.path.isfile(options.with_rhg)
755 os.path.isfile(options.with_rhg)
755 and os.access(options.with_rhg, os.X_OK)
756 and os.access(options.with_rhg, os.X_OK)
756 ):
757 ):
757 parser.error('--with-rhg must specify a rhg executable')
758 parser.error('--with-rhg must specify a rhg executable')
758 if options.chg and options.with_hg:
759 if options.chg and options.with_hg:
759 # chg shares installation location with hg
760 # chg shares installation location with hg
760 parser.error(
761 parser.error(
761 '--chg does not work when --with-hg is specified '
762 '--chg does not work when --with-hg is specified '
762 '(use --with-chg instead)'
763 '(use --with-chg instead)'
763 )
764 )
764 if options.rhg and options.with_hg:
765 if options.rhg and options.with_hg:
765 # rhg shares installation location with hg
766 # rhg shares installation location with hg
766 parser.error(
767 parser.error(
767 '--rhg does not work when --with-hg is specified '
768 '--rhg does not work when --with-hg is specified '
768 '(use --with-rhg instead)'
769 '(use --with-rhg instead)'
769 )
770 )
770 if options.rhg and options.chg:
771 if options.rhg and options.chg:
771 parser.error('--rhg and --chg do not work together')
772 parser.error('--rhg and --chg do not work together')
772
773
773 if options.color == 'always' and not pygmentspresent:
774 if options.color == 'always' and not pygmentspresent:
774 sys.stderr.write(
775 sys.stderr.write(
775 'warning: --color=always ignored because '
776 'warning: --color=always ignored because '
776 'pygments is not installed\n'
777 'pygments is not installed\n'
777 )
778 )
778
779
779 if options.bisect_repo and not options.known_good_rev:
780 if options.bisect_repo and not options.known_good_rev:
780 parser.error("--bisect-repo cannot be used without --known-good-rev")
781 parser.error("--bisect-repo cannot be used without --known-good-rev")
781
782
782 global useipv6
783 global useipv6
783 if options.ipv6:
784 if options.ipv6:
784 useipv6 = checksocketfamily('AF_INET6')
785 useipv6 = checksocketfamily('AF_INET6')
785 else:
786 else:
786 # only use IPv6 if IPv4 is unavailable and IPv6 is available
787 # only use IPv6 if IPv4 is unavailable and IPv6 is available
787 useipv6 = (not checksocketfamily('AF_INET')) and checksocketfamily(
788 useipv6 = (not checksocketfamily('AF_INET')) and checksocketfamily(
788 'AF_INET6'
789 'AF_INET6'
789 )
790 )
790
791
791 options.anycoverage = options.cover or options.annotate or options.htmlcov
792 options.anycoverage = options.cover or options.annotate or options.htmlcov
792 if options.anycoverage:
793 if options.anycoverage:
793 try:
794 try:
794 import coverage
795 import coverage
795
796
796 coverage.__version__ # silence unused import warning
797 coverage.__version__ # silence unused import warning
797 except ImportError:
798 except ImportError:
798 parser.error('coverage options now require the coverage package')
799 parser.error('coverage options now require the coverage package')
799
800
800 if options.anycoverage and options.local:
801 if options.anycoverage and options.local:
801 # this needs some path mangling somewhere, I guess
802 # this needs some path mangling somewhere, I guess
802 parser.error(
803 parser.error(
803 "sorry, coverage options do not work when --local " "is specified"
804 "sorry, coverage options do not work when --local " "is specified"
804 )
805 )
805
806
806 if options.anycoverage and options.with_hg:
807 if options.anycoverage and options.with_hg:
807 parser.error(
808 parser.error(
808 "sorry, coverage options do not work when --with-hg " "is specified"
809 "sorry, coverage options do not work when --with-hg " "is specified"
809 )
810 )
810
811
811 global verbose
812 global verbose
812 if options.verbose:
813 if options.verbose:
813 verbose = ''
814 verbose = ''
814
815
815 if options.tmpdir:
816 if options.tmpdir:
816 options.tmpdir = canonpath(options.tmpdir)
817 options.tmpdir = canonpath(options.tmpdir)
817
818
818 if options.jobs < 1:
819 if options.jobs < 1:
819 parser.error('--jobs must be positive')
820 parser.error('--jobs must be positive')
820 if options.interactive and options.debug:
821 if options.interactive and options.debug:
821 parser.error("-i/--interactive and -d/--debug are incompatible")
822 parser.error("-i/--interactive and -d/--debug are incompatible")
822 if options.debug:
823 if options.debug:
823 if options.timeout != defaults['timeout']:
824 if options.timeout != defaults['timeout']:
824 sys.stderr.write('warning: --timeout option ignored with --debug\n')
825 sys.stderr.write('warning: --timeout option ignored with --debug\n')
825 if options.slowtimeout != defaults['slowtimeout']:
826 if options.slowtimeout != defaults['slowtimeout']:
826 sys.stderr.write(
827 sys.stderr.write(
827 'warning: --slowtimeout option ignored with --debug\n'
828 'warning: --slowtimeout option ignored with --debug\n'
828 )
829 )
829 options.timeout = 0
830 options.timeout = 0
830 options.slowtimeout = 0
831 options.slowtimeout = 0
831
832
832 if options.blacklist:
833 if options.blacklist:
833 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
834 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
834 if options.whitelist:
835 if options.whitelist:
835 options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
836 options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
836 else:
837 else:
837 options.whitelisted = {}
838 options.whitelisted = {}
838
839
839 if options.showchannels:
840 if options.showchannels:
840 options.nodiff = True
841 options.nodiff = True
841
842
842 return options
843 return options
843
844
844
845
845 def rename(src, dst):
846 def rename(src, dst):
846 """Like os.rename(), trade atomicity and opened files friendliness
847 """Like os.rename(), trade atomicity and opened files friendliness
847 for existing destination support.
848 for existing destination support.
848 """
849 """
849 shutil.copy(src, dst)
850 shutil.copy(src, dst)
850 os.remove(src)
851 os.remove(src)
851
852
852
853
853 def makecleanable(path):
854 def makecleanable(path):
854 """Try to fix directory permission recursively so that the entire tree
855 """Try to fix directory permission recursively so that the entire tree
855 can be deleted"""
856 can be deleted"""
856 for dirpath, dirnames, _filenames in os.walk(path, topdown=True):
857 for dirpath, dirnames, _filenames in os.walk(path, topdown=True):
857 for d in dirnames:
858 for d in dirnames:
858 p = os.path.join(dirpath, d)
859 p = os.path.join(dirpath, d)
859 try:
860 try:
860 os.chmod(p, os.stat(p).st_mode & 0o777 | 0o700) # chmod u+rwx
861 os.chmod(p, os.stat(p).st_mode & 0o777 | 0o700) # chmod u+rwx
861 except OSError:
862 except OSError:
862 pass
863 pass
863
864
864
865
865 _unified_diff = functools.partial(difflib.diff_bytes, difflib.unified_diff)
866 _unified_diff = functools.partial(difflib.diff_bytes, difflib.unified_diff)
866
867
867
868
868 def getdiff(expected, output, ref, err):
869 def getdiff(expected, output, ref, err):
869 servefail = False
870 servefail = False
870 lines = []
871 lines = []
871 for line in _unified_diff(expected, output, ref, err):
872 for line in _unified_diff(expected, output, ref, err):
872 if line.startswith(b'+++') or line.startswith(b'---'):
873 if line.startswith(b'+++') or line.startswith(b'---'):
873 line = line.replace(b'\\', b'/')
874 line = line.replace(b'\\', b'/')
874 if line.endswith(b' \n'):
875 if line.endswith(b' \n'):
875 line = line[:-2] + b'\n'
876 line = line[:-2] + b'\n'
876 lines.append(line)
877 lines.append(line)
877 if not servefail and line.startswith(
878 if not servefail and line.startswith(
878 b'+ abort: child process failed to start'
879 b'+ abort: child process failed to start'
879 ):
880 ):
880 servefail = True
881 servefail = True
881
882
882 return servefail, lines
883 return servefail, lines
883
884
884
885
885 verbose = False
886 verbose = False
886
887
887
888
888 def vlog(*msg):
889 def vlog(*msg):
889 """Log only when in verbose mode."""
890 """Log only when in verbose mode."""
890 if verbose is False:
891 if verbose is False:
891 return
892 return
892
893
893 return log(*msg)
894 return log(*msg)
894
895
895
896
896 # Bytes that break XML even in a CDATA block: control characters 0-31
897 # Bytes that break XML even in a CDATA block: control characters 0-31
897 # sans \t, \n and \r
898 # sans \t, \n and \r
898 CDATA_EVIL = re.compile(br"[\000-\010\013\014\016-\037]")
899 CDATA_EVIL = re.compile(br"[\000-\010\013\014\016-\037]")
899
900
900 # Match feature conditionalized output lines in the form, capturing the feature
901 # Match feature conditionalized output lines in the form, capturing the feature
901 # list in group 2, and the preceeding line output in group 1:
902 # list in group 2, and the preceeding line output in group 1:
902 #
903 #
903 # output..output (feature !)\n
904 # output..output (feature !)\n
904 optline = re.compile(br'(.*) \((.+?) !\)\n$')
905 optline = re.compile(br'(.*) \((.+?) !\)\n$')
905
906
906
907
907 def cdatasafe(data):
908 def cdatasafe(data):
908 """Make a string safe to include in a CDATA block.
909 """Make a string safe to include in a CDATA block.
909
910
910 Certain control characters are illegal in a CDATA block, and
911 Certain control characters are illegal in a CDATA block, and
911 there's no way to include a ]]> in a CDATA either. This function
912 there's no way to include a ]]> in a CDATA either. This function
912 replaces illegal bytes with ? and adds a space between the ]] so
913 replaces illegal bytes with ? and adds a space between the ]] so
913 that it won't break the CDATA block.
914 that it won't break the CDATA block.
914 """
915 """
915 return CDATA_EVIL.sub(b'?', data).replace(b']]>', b'] ]>')
916 return CDATA_EVIL.sub(b'?', data).replace(b']]>', b'] ]>')
916
917
917
918
918 def log(*msg):
919 def log(*msg):
919 """Log something to stdout.
920 """Log something to stdout.
920
921
921 Arguments are strings to print.
922 Arguments are strings to print.
922 """
923 """
923 with iolock:
924 with iolock:
924 if verbose:
925 if verbose:
925 print(verbose, end=' ')
926 print(verbose, end=' ')
926 for m in msg:
927 for m in msg:
927 print(m, end=' ')
928 print(m, end=' ')
928 print()
929 print()
929 sys.stdout.flush()
930 sys.stdout.flush()
930
931
931
932
932 def highlightdiff(line, color):
933 def highlightdiff(line, color):
933 if not color:
934 if not color:
934 return line
935 return line
935 assert pygmentspresent
936 assert pygmentspresent
936 return pygments.highlight(
937 return pygments.highlight(
937 line.decode('latin1'), difflexer, terminal256formatter
938 line.decode('latin1'), difflexer, terminal256formatter
938 ).encode('latin1')
939 ).encode('latin1')
939
940
940
941
941 def highlightmsg(msg, color):
942 def highlightmsg(msg, color):
942 if not color:
943 if not color:
943 return msg
944 return msg
944 assert pygmentspresent
945 assert pygmentspresent
945 return pygments.highlight(msg, runnerlexer, runnerformatter)
946 return pygments.highlight(msg, runnerlexer, runnerformatter)
946
947
947
948
948 def terminate(proc):
949 def terminate(proc):
949 """Terminate subprocess"""
950 """Terminate subprocess"""
950 vlog('# Terminating process %d' % proc.pid)
951 vlog('# Terminating process %d' % proc.pid)
951 try:
952 try:
952 proc.terminate()
953 proc.terminate()
953 except OSError:
954 except OSError:
954 pass
955 pass
955
956
956
957
957 def killdaemons(pidfile):
958 def killdaemons(pidfile):
958 import killdaemons as killmod
959 import killdaemons as killmod
959
960
960 return killmod.killdaemons(pidfile, tryhard=False, remove=True, logfn=vlog)
961 return killmod.killdaemons(pidfile, tryhard=False, remove=True, logfn=vlog)
961
962
962
963
963 # sysconfig is not thread-safe (https://github.com/python/cpython/issues/92452)
964 # sysconfig is not thread-safe (https://github.com/python/cpython/issues/92452)
964 sysconfiglock = threading.Lock()
965 sysconfiglock = threading.Lock()
965
966
966
967
967 class Test(unittest.TestCase):
968 class Test(unittest.TestCase):
968 """Encapsulates a single, runnable test.
969 """Encapsulates a single, runnable test.
969
970
970 While this class conforms to the unittest.TestCase API, it differs in that
971 While this class conforms to the unittest.TestCase API, it differs in that
971 instances need to be instantiated manually. (Typically, unittest.TestCase
972 instances need to be instantiated manually. (Typically, unittest.TestCase
972 classes are instantiated automatically by scanning modules.)
973 classes are instantiated automatically by scanning modules.)
973 """
974 """
974
975
975 # Status code reserved for skipped tests (used by hghave).
976 # Status code reserved for skipped tests (used by hghave).
976 SKIPPED_STATUS = 80
977 SKIPPED_STATUS = 80
977
978
978 def __init__(
979 def __init__(
979 self,
980 self,
980 path,
981 path,
981 outputdir,
982 outputdir,
982 tmpdir,
983 tmpdir,
983 keeptmpdir=False,
984 keeptmpdir=False,
984 debug=False,
985 debug=False,
985 first=False,
986 first=False,
986 timeout=None,
987 timeout=None,
987 startport=None,
988 startport=None,
988 extraconfigopts=None,
989 extraconfigopts=None,
989 shell=None,
990 shell=None,
990 hgcommand=None,
991 hgcommand=None,
991 slowtimeout=None,
992 slowtimeout=None,
992 usechg=False,
993 usechg=False,
993 chgdebug=False,
994 chgdebug=False,
994 useipv6=False,
995 useipv6=False,
995 ):
996 ):
996 """Create a test from parameters.
997 """Create a test from parameters.
997
998
998 path is the full path to the file defining the test.
999 path is the full path to the file defining the test.
999
1000
1000 tmpdir is the main temporary directory to use for this test.
1001 tmpdir is the main temporary directory to use for this test.
1001
1002
1002 keeptmpdir determines whether to keep the test's temporary directory
1003 keeptmpdir determines whether to keep the test's temporary directory
1003 after execution. It defaults to removal (False).
1004 after execution. It defaults to removal (False).
1004
1005
1005 debug mode will make the test execute verbosely, with unfiltered
1006 debug mode will make the test execute verbosely, with unfiltered
1006 output.
1007 output.
1007
1008
1008 timeout controls the maximum run time of the test. It is ignored when
1009 timeout controls the maximum run time of the test. It is ignored when
1009 debug is True. See slowtimeout for tests with #require slow.
1010 debug is True. See slowtimeout for tests with #require slow.
1010
1011
1011 slowtimeout overrides timeout if the test has #require slow.
1012 slowtimeout overrides timeout if the test has #require slow.
1012
1013
1013 startport controls the starting port number to use for this test. Each
1014 startport controls the starting port number to use for this test. Each
1014 test will reserve 3 port numbers for execution. It is the caller's
1015 test will reserve 3 port numbers for execution. It is the caller's
1015 responsibility to allocate a non-overlapping port range to Test
1016 responsibility to allocate a non-overlapping port range to Test
1016 instances.
1017 instances.
1017
1018
1018 extraconfigopts is an iterable of extra hgrc config options. Values
1019 extraconfigopts is an iterable of extra hgrc config options. Values
1019 must have the form "key=value" (something understood by hgrc). Values
1020 must have the form "key=value" (something understood by hgrc). Values
1020 of the form "foo.key=value" will result in "[foo] key=value".
1021 of the form "foo.key=value" will result in "[foo] key=value".
1021
1022
1022 shell is the shell to execute tests in.
1023 shell is the shell to execute tests in.
1023 """
1024 """
1024 if timeout is None:
1025 if timeout is None:
1025 timeout = defaults['timeout']
1026 timeout = defaults['timeout']
1026 if startport is None:
1027 if startport is None:
1027 startport = defaults['port']
1028 startport = defaults['port']
1028 if slowtimeout is None:
1029 if slowtimeout is None:
1029 slowtimeout = defaults['slowtimeout']
1030 slowtimeout = defaults['slowtimeout']
1030 self.path = path
1031 self.path = path
1031 self.relpath = os.path.relpath(path)
1032 self.relpath = os.path.relpath(path)
1032 self.bname = os.path.basename(path)
1033 self.bname = os.path.basename(path)
1033 self.name = _bytes2sys(self.bname)
1034 self.name = _bytes2sys(self.bname)
1034 self._testdir = os.path.dirname(path)
1035 self._testdir = os.path.dirname(path)
1035 self._outputdir = outputdir
1036 self._outputdir = outputdir
1036 self._tmpname = os.path.basename(path)
1037 self._tmpname = os.path.basename(path)
1037 self.errpath = os.path.join(self._outputdir, b'%s.err' % self.bname)
1038 self.errpath = os.path.join(self._outputdir, b'%s.err' % self.bname)
1038
1039
1039 self._threadtmp = tmpdir
1040 self._threadtmp = tmpdir
1040 self._keeptmpdir = keeptmpdir
1041 self._keeptmpdir = keeptmpdir
1041 self._debug = debug
1042 self._debug = debug
1042 self._first = first
1043 self._first = first
1043 self._timeout = timeout
1044 self._timeout = timeout
1044 self._slowtimeout = slowtimeout
1045 self._slowtimeout = slowtimeout
1045 self._startport = startport
1046 self._startport = startport
1046 self._extraconfigopts = extraconfigopts or []
1047 self._extraconfigopts = extraconfigopts or []
1047 self._shell = _sys2bytes(shell)
1048 self._shell = _sys2bytes(shell)
1048 self._hgcommand = hgcommand or b'hg'
1049 self._hgcommand = hgcommand or b'hg'
1049 self._usechg = usechg
1050 self._usechg = usechg
1050 self._chgdebug = chgdebug
1051 self._chgdebug = chgdebug
1051 self._useipv6 = useipv6
1052 self._useipv6 = useipv6
1052
1053
1053 self._aborted = False
1054 self._aborted = False
1054 self._daemonpids = []
1055 self._daemonpids = []
1055 self._finished = None
1056 self._finished = None
1056 self._ret = None
1057 self._ret = None
1057 self._out = None
1058 self._out = None
1058 self._skipped = None
1059 self._skipped = None
1059 self._testtmp = None
1060 self._testtmp = None
1060 self._chgsockdir = None
1061 self._chgsockdir = None
1061
1062
1062 self._refout = self.readrefout()
1063 self._refout = self.readrefout()
1063
1064
1064 def readrefout(self):
1065 def readrefout(self):
1065 """read reference output"""
1066 """read reference output"""
1066 # If we're not in --debug mode and reference output file exists,
1067 # If we're not in --debug mode and reference output file exists,
1067 # check test output against it.
1068 # check test output against it.
1068 if self._debug:
1069 if self._debug:
1069 return None # to match "out is None"
1070 return None # to match "out is None"
1070 elif os.path.exists(self.refpath):
1071 elif os.path.exists(self.refpath):
1071 with open(self.refpath, 'rb') as f:
1072 with open(self.refpath, 'rb') as f:
1072 return f.read().splitlines(True)
1073 return f.read().splitlines(True)
1073 else:
1074 else:
1074 return []
1075 return []
1075
1076
1076 # needed to get base class __repr__ running
1077 # needed to get base class __repr__ running
1077 @property
1078 @property
1078 def _testMethodName(self):
1079 def _testMethodName(self):
1079 return self.name
1080 return self.name
1080
1081
1081 def __str__(self):
1082 def __str__(self):
1082 return self.name
1083 return self.name
1083
1084
1084 def shortDescription(self):
1085 def shortDescription(self):
1085 return self.name
1086 return self.name
1086
1087
1087 def setUp(self):
1088 def setUp(self):
1088 """Tasks to perform before run()."""
1089 """Tasks to perform before run()."""
1089 self._finished = False
1090 self._finished = False
1090 self._ret = None
1091 self._ret = None
1091 self._out = None
1092 self._out = None
1092 self._skipped = None
1093 self._skipped = None
1093
1094
1094 try:
1095 try:
1095 os.mkdir(self._threadtmp)
1096 os.mkdir(self._threadtmp)
1096 except FileExistsError:
1097 except FileExistsError:
1097 pass
1098 pass
1098
1099
1099 name = self._tmpname
1100 name = self._tmpname
1100 self._testtmp = os.path.join(self._threadtmp, name)
1101 self._testtmp = os.path.join(self._threadtmp, name)
1101 os.mkdir(self._testtmp)
1102 os.mkdir(self._testtmp)
1102
1103
1103 # Remove any previous output files.
1104 # Remove any previous output files.
1104 if os.path.exists(self.errpath):
1105 if os.path.exists(self.errpath):
1105 try:
1106 try:
1106 os.remove(self.errpath)
1107 os.remove(self.errpath)
1107 except FileNotFoundError:
1108 except FileNotFoundError:
1108 # We might have raced another test to clean up a .err file,
1109 # We might have raced another test to clean up a .err file,
1109 # so ignore FileNotFoundError when removing a previous .err
1110 # so ignore FileNotFoundError when removing a previous .err
1110 # file.
1111 # file.
1111 pass
1112 pass
1112
1113
1113 if self._usechg:
1114 if self._usechg:
1114 self._chgsockdir = os.path.join(
1115 self._chgsockdir = os.path.join(
1115 self._threadtmp, b'%s.chgsock' % name
1116 self._threadtmp, b'%s.chgsock' % name
1116 )
1117 )
1117 os.mkdir(self._chgsockdir)
1118 os.mkdir(self._chgsockdir)
1118
1119
1119 def run(self, result):
1120 def run(self, result):
1120 """Run this test and report results against a TestResult instance."""
1121 """Run this test and report results against a TestResult instance."""
1121 # This function is extremely similar to unittest.TestCase.run(). Once
1122 # This function is extremely similar to unittest.TestCase.run(). Once
1122 # we require Python 2.7 (or at least its version of unittest), this
1123 # we require Python 2.7 (or at least its version of unittest), this
1123 # function can largely go away.
1124 # function can largely go away.
1124 self._result = result
1125 self._result = result
1125 result.startTest(self)
1126 result.startTest(self)
1126 try:
1127 try:
1127 try:
1128 try:
1128 self.setUp()
1129 self.setUp()
1129 except (KeyboardInterrupt, SystemExit):
1130 except (KeyboardInterrupt, SystemExit):
1130 self._aborted = True
1131 self._aborted = True
1131 raise
1132 raise
1132 except Exception:
1133 except Exception:
1133 result.addError(self, sys.exc_info())
1134 result.addError(self, sys.exc_info())
1134 return
1135 return
1135
1136
1136 success = False
1137 success = False
1137 try:
1138 try:
1138 self.runTest()
1139 self.runTest()
1139 except KeyboardInterrupt:
1140 except KeyboardInterrupt:
1140 self._aborted = True
1141 self._aborted = True
1141 raise
1142 raise
1142 except unittest.SkipTest as e:
1143 except unittest.SkipTest as e:
1143 result.addSkip(self, str(e))
1144 result.addSkip(self, str(e))
1144 # The base class will have already counted this as a
1145 # The base class will have already counted this as a
1145 # test we "ran", but we want to exclude skipped tests
1146 # test we "ran", but we want to exclude skipped tests
1146 # from those we count towards those run.
1147 # from those we count towards those run.
1147 result.testsRun -= 1
1148 result.testsRun -= 1
1148 except self.failureException as e:
1149 except self.failureException as e:
1149 # This differs from unittest in that we don't capture
1150 # This differs from unittest in that we don't capture
1150 # the stack trace. This is for historical reasons and
1151 # the stack trace. This is for historical reasons and
1151 # this decision could be revisited in the future,
1152 # this decision could be revisited in the future,
1152 # especially for PythonTest instances.
1153 # especially for PythonTest instances.
1153 if result.addFailure(self, str(e)):
1154 if result.addFailure(self, str(e)):
1154 success = True
1155 success = True
1155 except Exception:
1156 except Exception:
1156 result.addError(self, sys.exc_info())
1157 result.addError(self, sys.exc_info())
1157 else:
1158 else:
1158 success = True
1159 success = True
1159
1160
1160 try:
1161 try:
1161 self.tearDown()
1162 self.tearDown()
1162 except (KeyboardInterrupt, SystemExit):
1163 except (KeyboardInterrupt, SystemExit):
1163 self._aborted = True
1164 self._aborted = True
1164 raise
1165 raise
1165 except Exception:
1166 except Exception:
1166 result.addError(self, sys.exc_info())
1167 result.addError(self, sys.exc_info())
1167 success = False
1168 success = False
1168
1169
1169 if success:
1170 if success:
1170 result.addSuccess(self)
1171 result.addSuccess(self)
1171 finally:
1172 finally:
1172 result.stopTest(self, interrupted=self._aborted)
1173 result.stopTest(self, interrupted=self._aborted)
1173
1174
1174 def runTest(self):
1175 def runTest(self):
1175 """Run this test instance.
1176 """Run this test instance.
1176
1177
1177 This will return a tuple describing the result of the test.
1178 This will return a tuple describing the result of the test.
1178 """
1179 """
1179 env = self._getenv()
1180 env = self._getenv()
1180 self._genrestoreenv(env)
1181 self._genrestoreenv(env)
1181 self._daemonpids.append(env['DAEMON_PIDS'])
1182 self._daemonpids.append(env['DAEMON_PIDS'])
1182 self._createhgrc(env['HGRCPATH'])
1183 self._createhgrc(env['HGRCPATH'])
1183
1184
1184 vlog('# Test', self.name)
1185 vlog('# Test', self.name)
1185
1186
1186 ret, out = self._run(env)
1187 ret, out = self._run(env)
1187 self._finished = True
1188 self._finished = True
1188 self._ret = ret
1189 self._ret = ret
1189 self._out = out
1190 self._out = out
1190
1191
1191 def describe(ret):
1192 def describe(ret):
1192 if ret < 0:
1193 if ret < 0:
1193 return 'killed by signal: %d' % -ret
1194 return 'killed by signal: %d' % -ret
1194 return 'returned error code %d' % ret
1195 return 'returned error code %d' % ret
1195
1196
1196 self._skipped = False
1197 self._skipped = False
1197
1198
1198 if ret == self.SKIPPED_STATUS:
1199 if ret == self.SKIPPED_STATUS:
1199 if out is None: # Debug mode, nothing to parse.
1200 if out is None: # Debug mode, nothing to parse.
1200 missing = ['unknown']
1201 missing = ['unknown']
1201 failed = None
1202 failed = None
1202 else:
1203 else:
1203 missing, failed = TTest.parsehghaveoutput(out)
1204 missing, failed = TTest.parsehghaveoutput(out)
1204
1205
1205 if not missing:
1206 if not missing:
1206 missing = ['skipped']
1207 missing = ['skipped']
1207
1208
1208 if failed:
1209 if failed:
1209 self.fail('hg have failed checking for %s' % failed[-1])
1210 self.fail('hg have failed checking for %s' % failed[-1])
1210 else:
1211 else:
1211 self._skipped = True
1212 self._skipped = True
1212 raise unittest.SkipTest(missing[-1])
1213 raise unittest.SkipTest(missing[-1])
1213 elif ret == 'timeout':
1214 elif ret == 'timeout':
1214 self.fail('timed out')
1215 self.fail('timed out')
1215 elif ret is False:
1216 elif ret is False:
1216 self.fail('no result code from test')
1217 self.fail('no result code from test')
1217 elif out != self._refout:
1218 elif out != self._refout:
1218 # Diff generation may rely on written .err file.
1219 # Diff generation may rely on written .err file.
1219 if (
1220 if (
1220 (ret != 0 or out != self._refout)
1221 (ret != 0 or out != self._refout)
1221 and not self._skipped
1222 and not self._skipped
1222 and not self._debug
1223 and not self._debug
1223 ):
1224 ):
1224 with open(self.errpath, 'wb') as f:
1225 with open(self.errpath, 'wb') as f:
1225 for line in out:
1226 for line in out:
1226 f.write(line)
1227 f.write(line)
1227
1228
1228 # The result object handles diff calculation for us.
1229 # The result object handles diff calculation for us.
1229 with firstlock:
1230 with firstlock:
1230 if self._result.addOutputMismatch(self, ret, out, self._refout):
1231 if self._result.addOutputMismatch(self, ret, out, self._refout):
1231 # change was accepted, skip failing
1232 # change was accepted, skip failing
1232 return
1233 return
1233 if self._first:
1234 if self._first:
1234 global firsterror
1235 global firsterror
1235 firsterror = True
1236 firsterror = True
1236
1237
1237 if ret:
1238 if ret:
1238 msg = 'output changed and ' + describe(ret)
1239 msg = 'output changed and ' + describe(ret)
1239 else:
1240 else:
1240 msg = 'output changed'
1241 msg = 'output changed'
1241
1242
1242 self.fail(msg)
1243 self.fail(msg)
1243 elif ret:
1244 elif ret:
1244 self.fail(describe(ret))
1245 self.fail(describe(ret))
1245
1246
1246 def tearDown(self):
1247 def tearDown(self):
1247 """Tasks to perform after run()."""
1248 """Tasks to perform after run()."""
1248 for entry in self._daemonpids:
1249 for entry in self._daemonpids:
1249 killdaemons(entry)
1250 killdaemons(entry)
1250 self._daemonpids = []
1251 self._daemonpids = []
1251
1252
1252 if self._keeptmpdir:
1253 if self._keeptmpdir:
1253 log(
1254 log(
1254 '\nKeeping testtmp dir: %s\nKeeping threadtmp dir: %s'
1255 '\nKeeping testtmp dir: %s\nKeeping threadtmp dir: %s'
1255 % (
1256 % (
1256 _bytes2sys(self._testtmp),
1257 _bytes2sys(self._testtmp),
1257 _bytes2sys(self._threadtmp),
1258 _bytes2sys(self._threadtmp),
1258 )
1259 )
1259 )
1260 )
1260 else:
1261 else:
1261 try:
1262 try:
1262 shutil.rmtree(self._testtmp)
1263 shutil.rmtree(self._testtmp)
1263 except OSError:
1264 except OSError:
1264 # unreadable directory may be left in $TESTTMP; fix permission
1265 # unreadable directory may be left in $TESTTMP; fix permission
1265 # and try again
1266 # and try again
1266 makecleanable(self._testtmp)
1267 makecleanable(self._testtmp)
1267 shutil.rmtree(self._testtmp, True)
1268 shutil.rmtree(self._testtmp, True)
1268 shutil.rmtree(self._threadtmp, True)
1269 shutil.rmtree(self._threadtmp, True)
1269
1270
1270 if self._usechg:
1271 if self._usechg:
1271 # chgservers will stop automatically after they find the socket
1272 # chgservers will stop automatically after they find the socket
1272 # files are deleted
1273 # files are deleted
1273 shutil.rmtree(self._chgsockdir, True)
1274 shutil.rmtree(self._chgsockdir, True)
1274
1275
1275 if (
1276 if (
1276 (self._ret != 0 or self._out != self._refout)
1277 (self._ret != 0 or self._out != self._refout)
1277 and not self._skipped
1278 and not self._skipped
1278 and not self._debug
1279 and not self._debug
1279 and self._out
1280 and self._out
1280 ):
1281 ):
1281 with open(self.errpath, 'wb') as f:
1282 with open(self.errpath, 'wb') as f:
1282 for line in self._out:
1283 for line in self._out:
1283 f.write(line)
1284 f.write(line)
1284
1285
1285 vlog("# Ret was:", self._ret, '(%s)' % self.name)
1286 vlog("# Ret was:", self._ret, '(%s)' % self.name)
1286
1287
1287 def _run(self, env):
1288 def _run(self, env):
1288 # This should be implemented in child classes to run tests.
1289 # This should be implemented in child classes to run tests.
1289 raise unittest.SkipTest('unknown test type')
1290 raise unittest.SkipTest('unknown test type')
1290
1291
1291 def abort(self):
1292 def abort(self):
1292 """Terminate execution of this test."""
1293 """Terminate execution of this test."""
1293 self._aborted = True
1294 self._aborted = True
1294
1295
1295 def _portmap(self, i):
1296 def _portmap(self, i):
1296 offset = b'' if i == 0 else b'%d' % i
1297 offset = b'' if i == 0 else b'%d' % i
1297 return (br':%d\b' % (self._startport + i), b':$HGPORT%s' % offset)
1298 return (br':%d\b' % (self._startport + i), b':$HGPORT%s' % offset)
1298
1299
1299 def _getreplacements(self):
1300 def _getreplacements(self):
1300 """Obtain a mapping of text replacements to apply to test output.
1301 """Obtain a mapping of text replacements to apply to test output.
1301
1302
1302 Test output needs to be normalized so it can be compared to expected
1303 Test output needs to be normalized so it can be compared to expected
1303 output. This function defines how some of that normalization will
1304 output. This function defines how some of that normalization will
1304 occur.
1305 occur.
1305 """
1306 """
1306 r = [
1307 r = [
1307 # This list should be parallel to defineport in _getenv
1308 # This list should be parallel to defineport in _getenv
1308 self._portmap(0),
1309 self._portmap(0),
1309 self._portmap(1),
1310 self._portmap(1),
1310 self._portmap(2),
1311 self._portmap(2),
1311 (br'([^0-9])%s' % re.escape(self._localip()), br'\1$LOCALIP'),
1312 (br'([^0-9])%s' % re.escape(self._localip()), br'\1$LOCALIP'),
1312 (br'\bHG_TXNID=TXN:[a-f0-9]{40}\b', br'HG_TXNID=TXN:$ID$'),
1313 (br'\bHG_TXNID=TXN:[a-f0-9]{40}\b', br'HG_TXNID=TXN:$ID$'),
1313 ]
1314 ]
1314 r.append((self._escapepath(self._testtmp), b'$TESTTMP'))
1315 r.append((self._escapepath(self._testtmp), b'$TESTTMP'))
1315 if WINDOWS:
1316 if WINDOWS:
1316 # JSON output escapes backslashes in Windows paths, so also catch a
1317 # JSON output escapes backslashes in Windows paths, so also catch a
1317 # double-escape.
1318 # double-escape.
1318 replaced = self._testtmp.replace(b'\\', br'\\')
1319 replaced = self._testtmp.replace(b'\\', br'\\')
1319 r.append((self._escapepath(replaced), b'$STR_REPR_TESTTMP'))
1320 r.append((self._escapepath(replaced), b'$STR_REPR_TESTTMP'))
1320
1321
1321 replacementfile = os.path.join(self._testdir, b'common-pattern.py')
1322 replacementfile = os.path.join(self._testdir, b'common-pattern.py')
1322
1323
1323 if os.path.exists(replacementfile):
1324 if os.path.exists(replacementfile):
1324 data = {}
1325 data = {}
1325 with open(replacementfile, mode='rb') as source:
1326 with open(replacementfile, mode='rb') as source:
1326 # the intermediate 'compile' step help with debugging
1327 # the intermediate 'compile' step help with debugging
1327 code = compile(source.read(), replacementfile, 'exec')
1328 code = compile(source.read(), replacementfile, 'exec')
1328 exec(code, data)
1329 exec(code, data)
1329 for value in data.get('substitutions', ()):
1330 for value in data.get('substitutions', ()):
1330 if len(value) != 2:
1331 if len(value) != 2:
1331 msg = 'malformatted substitution in %s: %r'
1332 msg = 'malformatted substitution in %s: %r'
1332 msg %= (replacementfile, value)
1333 msg %= (replacementfile, value)
1333 raise ValueError(msg)
1334 raise ValueError(msg)
1334 r.append(value)
1335 r.append(value)
1335 return r
1336 return r
1336
1337
1337 def _escapepath(self, p):
1338 def _escapepath(self, p):
1338 if WINDOWS:
1339 if WINDOWS:
1339 return b''.join(
1340 return b''.join(
1340 c.isalpha()
1341 c.isalpha()
1341 and b'[%s%s]' % (c.lower(), c.upper())
1342 and b'[%s%s]' % (c.lower(), c.upper())
1342 or c in b'/\\'
1343 or c in b'/\\'
1343 and br'[/\\]'
1344 and br'[/\\]'
1344 or c.isdigit()
1345 or c.isdigit()
1345 and c
1346 and c
1346 or b'\\' + c
1347 or b'\\' + c
1347 for c in [p[i : i + 1] for i in range(len(p))]
1348 for c in [p[i : i + 1] for i in range(len(p))]
1348 )
1349 )
1349 else:
1350 else:
1350 return re.escape(p)
1351 return re.escape(p)
1351
1352
1352 def _localip(self):
1353 def _localip(self):
1353 if self._useipv6:
1354 if self._useipv6:
1354 return b'::1'
1355 return b'::1'
1355 else:
1356 else:
1356 return b'127.0.0.1'
1357 return b'127.0.0.1'
1357
1358
1358 def _genrestoreenv(self, testenv):
1359 def _genrestoreenv(self, testenv):
1359 """Generate a script that can be used by tests to restore the original
1360 """Generate a script that can be used by tests to restore the original
1360 environment."""
1361 environment."""
1361 # Put the restoreenv script inside self._threadtmp
1362 # Put the restoreenv script inside self._threadtmp
1362 scriptpath = os.path.join(self._threadtmp, b'restoreenv.sh')
1363 scriptpath = os.path.join(self._threadtmp, b'restoreenv.sh')
1363 testenv['HGTEST_RESTOREENV'] = _bytes2sys(scriptpath)
1364 testenv['HGTEST_RESTOREENV'] = _bytes2sys(scriptpath)
1364
1365
1365 # Only restore environment variable names that the shell allows
1366 # Only restore environment variable names that the shell allows
1366 # us to export.
1367 # us to export.
1367 name_regex = re.compile('^[a-zA-Z][a-zA-Z0-9_]*$')
1368 name_regex = re.compile('^[a-zA-Z][a-zA-Z0-9_]*$')
1368
1369
1369 # Do not restore these variables; otherwise tests would fail.
1370 # Do not restore these variables; otherwise tests would fail.
1370 reqnames = {'PYTHON', 'TESTDIR', 'TESTTMP'}
1371 reqnames = {'PYTHON', 'TESTDIR', 'TESTTMP'}
1371
1372
1372 with open(scriptpath, 'w') as envf:
1373 with open(scriptpath, 'w') as envf:
1373 for name, value in origenviron.items():
1374 for name, value in origenviron.items():
1374 if not name_regex.match(name):
1375 if not name_regex.match(name):
1375 # Skip environment variables with unusual names not
1376 # Skip environment variables with unusual names not
1376 # allowed by most shells.
1377 # allowed by most shells.
1377 continue
1378 continue
1378 if name in reqnames:
1379 if name in reqnames:
1379 continue
1380 continue
1380 envf.write('%s=%s\n' % (name, shellquote(value)))
1381 envf.write('%s=%s\n' % (name, shellquote(value)))
1381
1382
1382 for name in testenv:
1383 for name in testenv:
1383 if name in origenviron or name in reqnames:
1384 if name in origenviron or name in reqnames:
1384 continue
1385 continue
1385 envf.write('unset %s\n' % (name,))
1386 envf.write('unset %s\n' % (name,))
1386
1387
1387 def _getenv(self):
1388 def _getenv(self):
1388 """Obtain environment variables to use during test execution."""
1389 """Obtain environment variables to use during test execution."""
1389
1390
1390 def defineport(i):
1391 def defineport(i):
1391 offset = '' if i == 0 else '%s' % i
1392 offset = '' if i == 0 else '%s' % i
1392 env["HGPORT%s" % offset] = '%s' % (self._startport + i)
1393 env["HGPORT%s" % offset] = '%s' % (self._startport + i)
1393
1394
1394 env = os.environ.copy()
1395 env = os.environ.copy()
1395 with sysconfiglock:
1396 with sysconfiglock:
1396 env['PYTHONUSERBASE'] = sysconfig.get_config_var('userbase') or ''
1397 env['PYTHONUSERBASE'] = sysconfig.get_config_var('userbase') or ''
1397 env['HGEMITWARNINGS'] = '1'
1398 env['HGEMITWARNINGS'] = '1'
1398 env['TESTTMP'] = _bytes2sys(self._testtmp)
1399 env['TESTTMP'] = _bytes2sys(self._testtmp)
1399 # the FORWARD_SLASH version is useful when running `sh` on non unix
1400 # the FORWARD_SLASH version is useful when running `sh` on non unix
1400 # system (e.g. Windows)
1401 # system (e.g. Windows)
1401 env['TESTTMP_FORWARD_SLASH'] = env['TESTTMP'].replace(os.sep, '/')
1402 env['TESTTMP_FORWARD_SLASH'] = env['TESTTMP'].replace(os.sep, '/')
1402 uid_file = os.path.join(_bytes2sys(self._testtmp), 'UID')
1403 uid_file = os.path.join(_bytes2sys(self._testtmp), 'UID')
1403 env['HGTEST_UUIDFILE'] = uid_file
1404 env['HGTEST_UUIDFILE'] = uid_file
1404 env['TESTNAME'] = self.name
1405 env['TESTNAME'] = self.name
1405 env['HOME'] = _bytes2sys(self._testtmp)
1406 env['HOME'] = _bytes2sys(self._testtmp)
1406 if WINDOWS:
1407 if WINDOWS:
1407 env['REALUSERPROFILE'] = env['USERPROFILE']
1408 env['REALUSERPROFILE'] = env['USERPROFILE']
1408 # py3.8+ ignores HOME: https://bugs.python.org/issue36264
1409 # py3.8+ ignores HOME: https://bugs.python.org/issue36264
1409 env['USERPROFILE'] = env['HOME']
1410 env['USERPROFILE'] = env['HOME']
1410 formated_timeout = _bytes2sys(b"%d" % default_defaults['timeout'][1])
1411 formated_timeout = _bytes2sys(b"%d" % default_defaults['timeout'][1])
1411 env['HGTEST_TIMEOUT_DEFAULT'] = formated_timeout
1412 env['HGTEST_TIMEOUT_DEFAULT'] = formated_timeout
1412 env['HGTEST_TIMEOUT'] = _bytes2sys(b"%d" % self._timeout)
1413 env['HGTEST_TIMEOUT'] = _bytes2sys(b"%d" % self._timeout)
1413 # This number should match portneeded in _getport
1414 # This number should match portneeded in _getport
1414 for port in range(3):
1415 for port in range(3):
1415 # This list should be parallel to _portmap in _getreplacements
1416 # This list should be parallel to _portmap in _getreplacements
1416 defineport(port)
1417 defineport(port)
1417 env["HGRCPATH"] = _bytes2sys(os.path.join(self._threadtmp, b'.hgrc'))
1418 env["HGRCPATH"] = _bytes2sys(os.path.join(self._threadtmp, b'.hgrc'))
1418 env["DAEMON_PIDS"] = _bytes2sys(
1419 env["DAEMON_PIDS"] = _bytes2sys(
1419 os.path.join(self._threadtmp, b'daemon.pids')
1420 os.path.join(self._threadtmp, b'daemon.pids')
1420 )
1421 )
1421 env["HGEDITOR"] = (
1422 env["HGEDITOR"] = (
1422 '"' + sysexecutable + '"' + ' -c "import sys; sys.exit(0)"'
1423 '"' + sysexecutable + '"' + ' -c "import sys; sys.exit(0)"'
1423 )
1424 )
1424 env["HGUSER"] = "test"
1425 env["HGUSER"] = "test"
1425 env["HGENCODING"] = "ascii"
1426 env["HGENCODING"] = "ascii"
1426 env["HGENCODINGMODE"] = "strict"
1427 env["HGENCODINGMODE"] = "strict"
1427 env["HGHOSTNAME"] = "test-hostname"
1428 env["HGHOSTNAME"] = "test-hostname"
1428 env['HGIPV6'] = str(int(self._useipv6))
1429 env['HGIPV6'] = str(int(self._useipv6))
1429 # See contrib/catapipe.py for how to use this functionality.
1430 # See contrib/catapipe.py for how to use this functionality.
1430 if 'HGTESTCATAPULTSERVERPIPE' not in env:
1431 if 'HGTESTCATAPULTSERVERPIPE' not in env:
1431 # If we don't have HGTESTCATAPULTSERVERPIPE explicitly set, pull the
1432 # If we don't have HGTESTCATAPULTSERVERPIPE explicitly set, pull the
1432 # non-test one in as a default, otherwise set to devnull
1433 # non-test one in as a default, otherwise set to devnull
1433 env['HGTESTCATAPULTSERVERPIPE'] = env.get(
1434 env['HGTESTCATAPULTSERVERPIPE'] = env.get(
1434 'HGCATAPULTSERVERPIPE', os.devnull
1435 'HGCATAPULTSERVERPIPE', os.devnull
1435 )
1436 )
1436
1437
1437 extraextensions = []
1438 extraextensions = []
1438 for opt in self._extraconfigopts:
1439 for opt in self._extraconfigopts:
1439 section, key = opt.split('.', 1)
1440 section, key = opt.split('.', 1)
1440 if section != 'extensions':
1441 if section != 'extensions':
1441 continue
1442 continue
1442 name = key.split('=', 1)[0]
1443 name = key.split('=', 1)[0]
1443 extraextensions.append(name)
1444 extraextensions.append(name)
1444
1445
1445 if extraextensions:
1446 if extraextensions:
1446 env['HGTESTEXTRAEXTENSIONS'] = ' '.join(extraextensions)
1447 env['HGTESTEXTRAEXTENSIONS'] = ' '.join(extraextensions)
1447
1448
1448 # LOCALIP could be ::1 or 127.0.0.1. Useful for tests that require raw
1449 # LOCALIP could be ::1 or 127.0.0.1. Useful for tests that require raw
1449 # IP addresses.
1450 # IP addresses.
1450 env['LOCALIP'] = _bytes2sys(self._localip())
1451 env['LOCALIP'] = _bytes2sys(self._localip())
1451
1452
1452 # This has the same effect as Py_LegacyWindowsStdioFlag in exewrapper.c,
1453 # This has the same effect as Py_LegacyWindowsStdioFlag in exewrapper.c,
1453 # but this is needed for testing python instances like dummyssh,
1454 # but this is needed for testing python instances like dummyssh,
1454 # dummysmtpd.py, and dumbhttp.py.
1455 # dummysmtpd.py, and dumbhttp.py.
1455 if WINDOWS:
1456 if WINDOWS:
1456 env['PYTHONLEGACYWINDOWSSTDIO'] = '1'
1457 env['PYTHONLEGACYWINDOWSSTDIO'] = '1'
1457
1458
1458 # Modified HOME in test environment can confuse Rust tools. So set
1459 # Modified HOME in test environment can confuse Rust tools. So set
1459 # CARGO_HOME and RUSTUP_HOME automatically if a Rust toolchain is
1460 # CARGO_HOME and RUSTUP_HOME automatically if a Rust toolchain is
1460 # present and these variables aren't already defined.
1461 # present and these variables aren't already defined.
1461 cargo_home_path = os.path.expanduser('~/.cargo')
1462 cargo_home_path = os.path.expanduser('~/.cargo')
1462 rustup_home_path = os.path.expanduser('~/.rustup')
1463 rustup_home_path = os.path.expanduser('~/.rustup')
1463
1464
1464 if os.path.exists(cargo_home_path) and b'CARGO_HOME' not in osenvironb:
1465 if os.path.exists(cargo_home_path) and b'CARGO_HOME' not in osenvironb:
1465 env['CARGO_HOME'] = cargo_home_path
1466 env['CARGO_HOME'] = cargo_home_path
1466 if (
1467 if (
1467 os.path.exists(rustup_home_path)
1468 os.path.exists(rustup_home_path)
1468 and b'RUSTUP_HOME' not in osenvironb
1469 and b'RUSTUP_HOME' not in osenvironb
1469 ):
1470 ):
1470 env['RUSTUP_HOME'] = rustup_home_path
1471 env['RUSTUP_HOME'] = rustup_home_path
1471
1472
1472 # Reset some environment variables to well-known values so that
1473 # Reset some environment variables to well-known values so that
1473 # the tests produce repeatable output.
1474 # the tests produce repeatable output.
1474 env['LANG'] = env['LC_ALL'] = env['LANGUAGE'] = 'C'
1475 env['LANG'] = env['LC_ALL'] = env['LANGUAGE'] = 'C'
1475 env['TZ'] = 'GMT'
1476 env['TZ'] = 'GMT'
1476 env["EMAIL"] = "Foo Bar <foo.bar@example.com>"
1477 env["EMAIL"] = "Foo Bar <foo.bar@example.com>"
1477 env['COLUMNS'] = '80'
1478 env['COLUMNS'] = '80'
1478 env['TERM'] = 'xterm'
1479 env['TERM'] = 'xterm'
1479
1480
1480 dropped = [
1481 dropped = [
1481 'CDPATH',
1482 'CDPATH',
1482 'CHGDEBUG',
1483 'CHGDEBUG',
1483 'EDITOR',
1484 'EDITOR',
1484 'GREP_OPTIONS',
1485 'GREP_OPTIONS',
1485 'HG',
1486 'HG',
1486 'HGMERGE',
1487 'HGMERGE',
1487 'HGPLAIN',
1488 'HGPLAIN',
1488 'HGPLAINEXCEPT',
1489 'HGPLAINEXCEPT',
1489 'HGPROF',
1490 'HGPROF',
1490 'http_proxy',
1491 'http_proxy',
1491 'no_proxy',
1492 'no_proxy',
1492 'NO_PROXY',
1493 'NO_PROXY',
1493 'PAGER',
1494 'PAGER',
1494 'VISUAL',
1495 'VISUAL',
1495 ]
1496 ]
1496
1497
1497 for k in dropped:
1498 for k in dropped:
1498 if k in env:
1499 if k in env:
1499 del env[k]
1500 del env[k]
1500
1501
1501 # unset env related to hooks
1502 # unset env related to hooks
1502 for k in list(env):
1503 for k in list(env):
1503 if k.startswith('HG_'):
1504 if k.startswith('HG_'):
1504 del env[k]
1505 del env[k]
1505
1506
1506 if self._usechg:
1507 if self._usechg:
1507 env['CHGSOCKNAME'] = os.path.join(self._chgsockdir, b'server')
1508 env['CHGSOCKNAME'] = os.path.join(self._chgsockdir, b'server')
1508 if self._chgdebug:
1509 if self._chgdebug:
1509 env['CHGDEBUG'] = 'true'
1510 env['CHGDEBUG'] = 'true'
1510
1511
1511 return env
1512 return env
1512
1513
1513 def _createhgrc(self, path):
1514 def _createhgrc(self, path):
1514 """Create an hgrc file for this test."""
1515 """Create an hgrc file for this test."""
1515 with open(path, 'wb') as hgrc:
1516 with open(path, 'wb') as hgrc:
1516 hgrc.write(b'[ui]\n')
1517 hgrc.write(b'[ui]\n')
1517 hgrc.write(b'slash = True\n')
1518 hgrc.write(b'slash = True\n')
1518 hgrc.write(b'interactive = False\n')
1519 hgrc.write(b'interactive = False\n')
1519 hgrc.write(b'detailed-exit-code = True\n')
1520 hgrc.write(b'detailed-exit-code = True\n')
1520 hgrc.write(b'merge = internal:merge\n')
1521 hgrc.write(b'merge = internal:merge\n')
1521 hgrc.write(b'mergemarkers = detailed\n')
1522 hgrc.write(b'mergemarkers = detailed\n')
1522 hgrc.write(b'promptecho = True\n')
1523 hgrc.write(b'promptecho = True\n')
1523 dummyssh = os.path.join(self._testdir, b'dummyssh')
1524 dummyssh = os.path.join(self._testdir, b'dummyssh')
1524 hgrc.write(b'ssh = "%s" "%s"\n' % (PYTHON, dummyssh))
1525 hgrc.write(b'ssh = "%s" "%s"\n' % (PYTHON, dummyssh))
1525 hgrc.write(b'timeout.warn=15\n')
1526 hgrc.write(b'timeout.warn=15\n')
1526 hgrc.write(b'[chgserver]\n')
1527 hgrc.write(b'[chgserver]\n')
1527 hgrc.write(b'idletimeout=60\n')
1528 hgrc.write(b'idletimeout=60\n')
1528 hgrc.write(b'[defaults]\n')
1529 hgrc.write(b'[defaults]\n')
1529 hgrc.write(b'[devel]\n')
1530 hgrc.write(b'[devel]\n')
1530 hgrc.write(b'all-warnings = true\n')
1531 hgrc.write(b'all-warnings = true\n')
1531 hgrc.write(b'default-date = 0 0\n')
1532 hgrc.write(b'default-date = 0 0\n')
1532 hgrc.write(b'[largefiles]\n')
1533 hgrc.write(b'[largefiles]\n')
1533 hgrc.write(
1534 hgrc.write(
1534 b'usercache = %s\n'
1535 b'usercache = %s\n'
1535 % (os.path.join(self._testtmp, b'.cache/largefiles'))
1536 % (os.path.join(self._testtmp, b'.cache/largefiles'))
1536 )
1537 )
1537 hgrc.write(b'[lfs]\n')
1538 hgrc.write(b'[lfs]\n')
1538 hgrc.write(
1539 hgrc.write(
1539 b'usercache = %s\n'
1540 b'usercache = %s\n'
1540 % (os.path.join(self._testtmp, b'.cache/lfs'))
1541 % (os.path.join(self._testtmp, b'.cache/lfs'))
1541 )
1542 )
1542 hgrc.write(b'[web]\n')
1543 hgrc.write(b'[web]\n')
1543 hgrc.write(b'address = localhost\n')
1544 hgrc.write(b'address = localhost\n')
1544 hgrc.write(b'ipv6 = %r\n' % self._useipv6)
1545 hgrc.write(b'ipv6 = %r\n' % self._useipv6)
1545 hgrc.write(b'server-header = testing stub value\n')
1546 hgrc.write(b'server-header = testing stub value\n')
1546
1547
1547 for opt in self._extraconfigopts:
1548 for opt in self._extraconfigopts:
1548 section, key = _sys2bytes(opt).split(b'.', 1)
1549 section, key = _sys2bytes(opt).split(b'.', 1)
1549 assert b'=' in key, (
1550 assert b'=' in key, (
1550 'extra config opt %s must ' 'have an = for assignment' % opt
1551 'extra config opt %s must ' 'have an = for assignment' % opt
1551 )
1552 )
1552 hgrc.write(b'[%s]\n%s\n' % (section, key))
1553 hgrc.write(b'[%s]\n%s\n' % (section, key))
1553
1554
1554 def fail(self, msg):
1555 def fail(self, msg):
1555 # unittest differentiates between errored and failed.
1556 # unittest differentiates between errored and failed.
1556 # Failed is denoted by AssertionError (by default at least).
1557 # Failed is denoted by AssertionError (by default at least).
1557 raise AssertionError(msg)
1558 raise AssertionError(msg)
1558
1559
1559 def _runcommand(self, cmd, env, normalizenewlines=False):
1560 def _runcommand(self, cmd, env, normalizenewlines=False):
1560 """Run command in a sub-process, capturing the output (stdout and
1561 """Run command in a sub-process, capturing the output (stdout and
1561 stderr).
1562 stderr).
1562
1563
1563 Return a tuple (exitcode, output). output is None in debug mode.
1564 Return a tuple (exitcode, output). output is None in debug mode.
1564 """
1565 """
1565 if self._debug:
1566 if self._debug:
1566 proc = subprocess.Popen(
1567 proc = subprocess.Popen(
1567 _bytes2sys(cmd),
1568 _bytes2sys(cmd),
1568 shell=True,
1569 shell=True,
1569 close_fds=closefds,
1570 close_fds=closefds,
1570 cwd=_bytes2sys(self._testtmp),
1571 cwd=_bytes2sys(self._testtmp),
1571 env=env,
1572 env=env,
1572 )
1573 )
1573 ret = proc.wait()
1574 ret = proc.wait()
1574 return (ret, None)
1575 return (ret, None)
1575
1576
1576 proc = Popen4(cmd, self._testtmp, self._timeout, env)
1577 proc = Popen4(cmd, self._testtmp, self._timeout, env)
1577
1578
1578 def cleanup():
1579 def cleanup():
1579 terminate(proc)
1580 terminate(proc)
1580 ret = proc.wait()
1581 ret = proc.wait()
1581 if ret == 0:
1582 if ret == 0:
1582 ret = signal.SIGTERM << 8
1583 ret = signal.SIGTERM << 8
1583 killdaemons(env['DAEMON_PIDS'])
1584 killdaemons(env['DAEMON_PIDS'])
1584 return ret
1585 return ret
1585
1586
1586 proc.tochild.close()
1587 proc.tochild.close()
1587
1588
1588 try:
1589 try:
1589 output = proc.fromchild.read()
1590 output = proc.fromchild.read()
1590 except KeyboardInterrupt:
1591 except KeyboardInterrupt:
1591 vlog('# Handling keyboard interrupt')
1592 vlog('# Handling keyboard interrupt')
1592 cleanup()
1593 cleanup()
1593 raise
1594 raise
1594
1595
1595 ret = proc.wait()
1596 ret = proc.wait()
1596 if wifexited(ret):
1597 if wifexited(ret):
1597 ret = os.WEXITSTATUS(ret)
1598 ret = os.WEXITSTATUS(ret)
1598
1599
1599 if proc.timeout:
1600 if proc.timeout:
1600 ret = 'timeout'
1601 ret = 'timeout'
1601
1602
1602 if ret:
1603 if ret:
1603 killdaemons(env['DAEMON_PIDS'])
1604 killdaemons(env['DAEMON_PIDS'])
1604
1605
1605 for s, r in self._getreplacements():
1606 for s, r in self._getreplacements():
1606 output = re.sub(s, r, output)
1607 output = re.sub(s, r, output)
1607
1608
1608 if normalizenewlines:
1609 if normalizenewlines:
1609 output = output.replace(b'\r\n', b'\n')
1610 output = output.replace(b'\r\n', b'\n')
1610
1611
1611 return ret, output.splitlines(True)
1612 return ret, output.splitlines(True)
1612
1613
1613
1614
1614 class PythonTest(Test):
1615 class PythonTest(Test):
1615 """A Python-based test."""
1616 """A Python-based test."""
1616
1617
1617 @property
1618 @property
1618 def refpath(self):
1619 def refpath(self):
1619 return os.path.join(self._testdir, b'%s.out' % self.bname)
1620 return os.path.join(self._testdir, b'%s.out' % self.bname)
1620
1621
1621 def _run(self, env):
1622 def _run(self, env):
1622 # Quote the python(3) executable for Windows
1623 # Quote the python(3) executable for Windows
1623 cmd = b'"%s" "%s"' % (PYTHON, self.path)
1624 cmd = b'"%s" "%s"' % (PYTHON, self.path)
1624 vlog("# Running", cmd.decode("utf-8"))
1625 vlog("# Running", cmd.decode("utf-8"))
1625 result = self._runcommand(cmd, env, normalizenewlines=WINDOWS)
1626 result = self._runcommand(cmd, env, normalizenewlines=WINDOWS)
1626 if self._aborted:
1627 if self._aborted:
1627 raise KeyboardInterrupt()
1628 raise KeyboardInterrupt()
1628
1629
1629 return result
1630 return result
1630
1631
1631
1632
1632 # Some glob patterns apply only in some circumstances, so the script
1633 # Some glob patterns apply only in some circumstances, so the script
1633 # might want to remove (glob) annotations that otherwise should be
1634 # might want to remove (glob) annotations that otherwise should be
1634 # retained.
1635 # retained.
1635 checkcodeglobpats = [
1636 checkcodeglobpats = [
1636 # On Windows it looks like \ doesn't require a (glob), but we know
1637 # On Windows it looks like \ doesn't require a (glob), but we know
1637 # better.
1638 # better.
1638 re.compile(br'^pushing to \$TESTTMP/.*[^)]$'),
1639 re.compile(br'^pushing to \$TESTTMP/.*[^)]$'),
1639 re.compile(br'^moving \S+/.*[^)]$'),
1640 re.compile(br'^moving \S+/.*[^)]$'),
1640 re.compile(br'^pulling from \$TESTTMP/.*[^)]$'),
1641 re.compile(br'^pulling from \$TESTTMP/.*[^)]$'),
1641 # Not all platforms have 127.0.0.1 as loopback (though most do),
1642 # Not all platforms have 127.0.0.1 as loopback (though most do),
1642 # so we always glob that too.
1643 # so we always glob that too.
1643 re.compile(br'.*\$LOCALIP.*$'),
1644 re.compile(br'.*\$LOCALIP.*$'),
1644 ]
1645 ]
1645
1646
1646 bchr = lambda x: bytes([x])
1647 bchr = lambda x: bytes([x])
1647
1648
1648 WARN_UNDEFINED = 1
1649 WARN_UNDEFINED = 1
1649 WARN_YES = 2
1650 WARN_YES = 2
1650 WARN_NO = 3
1651 WARN_NO = 3
1651
1652
1652 MARK_OPTIONAL = b" (?)\n"
1653 MARK_OPTIONAL = b" (?)\n"
1653
1654
1654
1655
1655 def isoptional(line):
1656 def isoptional(line):
1656 return line.endswith(MARK_OPTIONAL)
1657 return line.endswith(MARK_OPTIONAL)
1657
1658
1658
1659
1659 class TTest(Test):
1660 class TTest(Test):
1660 """A "t test" is a test backed by a .t file."""
1661 """A "t test" is a test backed by a .t file."""
1661
1662
1662 SKIPPED_PREFIX = b'skipped: '
1663 SKIPPED_PREFIX = b'skipped: '
1663 FAILED_PREFIX = b'hghave check failed: '
1664 FAILED_PREFIX = b'hghave check failed: '
1664 NEEDESCAPE = re.compile(br'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
1665 NEEDESCAPE = re.compile(br'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
1665
1666
1666 ESCAPESUB = re.compile(br'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
1667 ESCAPESUB = re.compile(br'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
1667 ESCAPEMAP = {bchr(i): br'\x%02x' % i for i in range(256)}
1668 ESCAPEMAP = {bchr(i): br'\x%02x' % i for i in range(256)}
1668 ESCAPEMAP.update({b'\\': b'\\\\', b'\r': br'\r'})
1669 ESCAPEMAP.update({b'\\': b'\\\\', b'\r': br'\r'})
1669
1670
1670 def __init__(self, path, *args, **kwds):
1671 def __init__(self, path, *args, **kwds):
1671 # accept an extra "case" parameter
1672 # accept an extra "case" parameter
1672 case = kwds.pop('case', [])
1673 case = kwds.pop('case', [])
1673 self._case = case
1674 self._case = case
1674 self._allcases = {x for y in parsettestcases(path) for x in y}
1675 self._allcases = {x for y in parsettestcases(path) for x in y}
1675 super(TTest, self).__init__(path, *args, **kwds)
1676 super(TTest, self).__init__(path, *args, **kwds)
1676 if case:
1677 if case:
1677 casepath = b'#'.join(case)
1678 casepath = b'#'.join(case)
1678 self.name = '%s#%s' % (self.name, _bytes2sys(casepath))
1679 self.name = '%s#%s' % (self.name, _bytes2sys(casepath))
1679 self.errpath = b'%s#%s.err' % (self.errpath[:-4], casepath)
1680 self.errpath = b'%s#%s.err' % (self.errpath[:-4], casepath)
1680 self._tmpname += b'-%s' % casepath.replace(b'#', b'-')
1681 self._tmpname += b'-%s' % casepath.replace(b'#', b'-')
1681 self._have = {}
1682 self._have = {}
1682
1683
1683 @property
1684 @property
1684 def refpath(self):
1685 def refpath(self):
1685 return os.path.join(self._testdir, self.bname)
1686 return os.path.join(self._testdir, self.bname)
1686
1687
1687 def _run(self, env):
1688 def _run(self, env):
1688 with open(self.path, 'rb') as f:
1689 with open(self.path, 'rb') as f:
1689 lines = f.readlines()
1690 lines = f.readlines()
1690
1691
1691 # .t file is both reference output and the test input, keep reference
1692 # .t file is both reference output and the test input, keep reference
1692 # output updated with the the test input. This avoids some race
1693 # output updated with the the test input. This avoids some race
1693 # conditions where the reference output does not match the actual test.
1694 # conditions where the reference output does not match the actual test.
1694 if self._refout is not None:
1695 if self._refout is not None:
1695 self._refout = lines
1696 self._refout = lines
1696
1697
1697 salt, script, after, expected = self._parsetest(lines)
1698 salt, script, after, expected = self._parsetest(lines)
1698
1699
1699 # Write out the generated script.
1700 # Write out the generated script.
1700 fname = b'%s.sh' % self._testtmp
1701 fname = b'%s.sh' % self._testtmp
1701 with open(fname, 'wb') as f:
1702 with open(fname, 'wb') as f:
1702 for l in script:
1703 for l in script:
1703 f.write(l)
1704 f.write(l)
1704
1705
1705 cmd = b'%s "%s"' % (self._shell, fname)
1706 cmd = b'%s "%s"' % (self._shell, fname)
1706 vlog("# Running", cmd.decode("utf-8"))
1707 vlog("# Running", cmd.decode("utf-8"))
1707
1708
1708 exitcode, output = self._runcommand(cmd, env)
1709 exitcode, output = self._runcommand(cmd, env)
1709
1710
1710 if self._aborted:
1711 if self._aborted:
1711 raise KeyboardInterrupt()
1712 raise KeyboardInterrupt()
1712
1713
1713 # Do not merge output if skipped. Return hghave message instead.
1714 # Do not merge output if skipped. Return hghave message instead.
1714 # Similarly, with --debug, output is None.
1715 # Similarly, with --debug, output is None.
1715 if exitcode == self.SKIPPED_STATUS or output is None:
1716 if exitcode == self.SKIPPED_STATUS or output is None:
1716 return exitcode, output
1717 return exitcode, output
1717
1718
1718 return self._processoutput(exitcode, output, salt, after, expected)
1719 return self._processoutput(exitcode, output, salt, after, expected)
1719
1720
1720 def _hghave(self, reqs):
1721 def _hghave(self, reqs):
1721 allreqs = b' '.join(reqs)
1722 allreqs = b' '.join(reqs)
1722
1723
1723 self._detectslow(reqs)
1724 self._detectslow(reqs)
1724
1725
1725 if allreqs in self._have:
1726 if allreqs in self._have:
1726 return self._have.get(allreqs)
1727 return self._have.get(allreqs)
1727
1728
1728 # TODO do something smarter when all other uses of hghave are gone.
1729 # TODO do something smarter when all other uses of hghave are gone.
1729 runtestdir = osenvironb[b'RUNTESTDIR']
1730 runtestdir = osenvironb[b'RUNTESTDIR']
1730 tdir = runtestdir.replace(b'\\', b'/')
1731 tdir = runtestdir.replace(b'\\', b'/')
1731 proc = Popen4(
1732 proc = Popen4(
1732 b'%s -c "%s/hghave %s"' % (self._shell, tdir, allreqs),
1733 b'%s -c "%s/hghave %s"' % (self._shell, tdir, allreqs),
1733 self._testtmp,
1734 self._testtmp,
1734 0,
1735 0,
1735 self._getenv(),
1736 self._getenv(),
1736 )
1737 )
1737 stdout, stderr = proc.communicate()
1738 stdout, stderr = proc.communicate()
1738 ret = proc.wait()
1739 ret = proc.wait()
1739 if wifexited(ret):
1740 if wifexited(ret):
1740 ret = os.WEXITSTATUS(ret)
1741 ret = os.WEXITSTATUS(ret)
1741 if ret == 2:
1742 if ret == 2:
1742 print(stdout.decode('utf-8'))
1743 print(stdout.decode('utf-8'))
1743 sys.exit(1)
1744 sys.exit(1)
1744
1745
1745 if ret != 0:
1746 if ret != 0:
1746 self._have[allreqs] = (False, stdout)
1747 self._have[allreqs] = (False, stdout)
1747 return False, stdout
1748 return False, stdout
1748
1749
1749 self._have[allreqs] = (True, None)
1750 self._have[allreqs] = (True, None)
1750 return True, None
1751 return True, None
1751
1752
1752 def _detectslow(self, reqs):
1753 def _detectslow(self, reqs):
1753 """update the timeout of slow test when appropriate"""
1754 """update the timeout of slow test when appropriate"""
1754 if b'slow' in reqs:
1755 if b'slow' in reqs:
1755 self._timeout = self._slowtimeout
1756 self._timeout = self._slowtimeout
1756
1757
1757 def _iftest(self, args):
1758 def _iftest(self, args):
1758 # implements "#if"
1759 # implements "#if"
1759 reqs = []
1760 reqs = []
1760 for arg in args:
1761 for arg in args:
1761 if arg.startswith(b'no-') and arg[3:] in self._allcases:
1762 if arg.startswith(b'no-') and arg[3:] in self._allcases:
1762 if arg[3:] in self._case:
1763 if arg[3:] in self._case:
1763 return False
1764 return False
1764 elif arg in self._allcases:
1765 elif arg in self._allcases:
1765 if arg not in self._case:
1766 if arg not in self._case:
1766 return False
1767 return False
1767 else:
1768 else:
1768 reqs.append(arg)
1769 reqs.append(arg)
1769 self._detectslow(reqs)
1770 self._detectslow(reqs)
1770 return self._hghave(reqs)[0]
1771 return self._hghave(reqs)[0]
1771
1772
1772 def _parsetest(self, lines):
1773 def _parsetest(self, lines):
1773 # We generate a shell script which outputs unique markers to line
1774 # We generate a shell script which outputs unique markers to line
1774 # up script results with our source. These markers include input
1775 # up script results with our source. These markers include input
1775 # line number and the last return code.
1776 # line number and the last return code.
1776 salt = b"SALT%d" % time.time()
1777 salt = b"SALT%d" % time.time()
1777
1778
1778 def addsalt(line, inpython):
1779 def addsalt(line, inpython):
1779 if inpython:
1780 if inpython:
1780 script.append(b'%s %d 0\n' % (salt, line))
1781 script.append(b'%s %d 0\n' % (salt, line))
1781 else:
1782 else:
1782 script.append(b'echo %s %d $?\n' % (salt, line))
1783 script.append(b'echo %s %d $?\n' % (salt, line))
1783
1784
1784 activetrace = []
1785 activetrace = []
1785 session = str(uuid.uuid4()).encode('ascii')
1786 session = str(uuid.uuid4()).encode('ascii')
1786 hgcatapult = os.getenv('HGTESTCATAPULTSERVERPIPE') or os.getenv(
1787 hgcatapult = os.getenv('HGTESTCATAPULTSERVERPIPE') or os.getenv(
1787 'HGCATAPULTSERVERPIPE'
1788 'HGCATAPULTSERVERPIPE'
1788 )
1789 )
1789
1790
1790 def toggletrace(cmd=None):
1791 def toggletrace(cmd=None):
1791 if not hgcatapult or hgcatapult == os.devnull:
1792 if not hgcatapult or hgcatapult == os.devnull:
1792 return
1793 return
1793
1794
1794 if activetrace:
1795 if activetrace:
1795 script.append(
1796 script.append(
1796 b'echo END %s %s >> "$HGTESTCATAPULTSERVERPIPE"\n'
1797 b'echo END %s %s >> "$HGTESTCATAPULTSERVERPIPE"\n'
1797 % (session, activetrace[0])
1798 % (session, activetrace[0])
1798 )
1799 )
1799 if cmd is None:
1800 if cmd is None:
1800 return
1801 return
1801
1802
1802 if isinstance(cmd, str):
1803 if isinstance(cmd, str):
1803 quoted = shellquote(cmd.strip())
1804 quoted = shellquote(cmd.strip())
1804 else:
1805 else:
1805 quoted = shellquote(cmd.strip().decode('utf8')).encode('utf8')
1806 quoted = shellquote(cmd.strip().decode('utf8')).encode('utf8')
1806 quoted = quoted.replace(b'\\', b'\\\\')
1807 quoted = quoted.replace(b'\\', b'\\\\')
1807 script.append(
1808 script.append(
1808 b'echo START %s %s >> "$HGTESTCATAPULTSERVERPIPE"\n'
1809 b'echo START %s %s >> "$HGTESTCATAPULTSERVERPIPE"\n'
1809 % (session, quoted)
1810 % (session, quoted)
1810 )
1811 )
1811 activetrace[0:] = [quoted]
1812 activetrace[0:] = [quoted]
1812
1813
1813 script = []
1814 script = []
1814
1815
1815 # After we run the shell script, we re-unify the script output
1816 # After we run the shell script, we re-unify the script output
1816 # with non-active parts of the source, with synchronization by our
1817 # with non-active parts of the source, with synchronization by our
1817 # SALT line number markers. The after table contains the non-active
1818 # SALT line number markers. The after table contains the non-active
1818 # components, ordered by line number.
1819 # components, ordered by line number.
1819 after = {}
1820 after = {}
1820
1821
1821 # Expected shell script output.
1822 # Expected shell script output.
1822 expected = {}
1823 expected = {}
1823
1824
1824 pos = prepos = -1
1825 pos = prepos = -1
1825
1826
1826 # The current stack of conditionnal section.
1827 # The current stack of conditionnal section.
1827 # Each relevant conditionnal section can have the following value:
1828 # Each relevant conditionnal section can have the following value:
1828 # - True: we should run this block
1829 # - True: we should run this block
1829 # - False: we should skip this block
1830 # - False: we should skip this block
1830 # - None: The parent block is skipped,
1831 # - None: The parent block is skipped,
1831 # (no branch of this one will ever run)
1832 # (no branch of this one will ever run)
1832 condition_stack = []
1833 condition_stack = []
1833
1834
1834 def run_line():
1835 def run_line():
1835 """return True if the current line should be run"""
1836 """return True if the current line should be run"""
1836 if not condition_stack:
1837 if not condition_stack:
1837 return True
1838 return True
1838 return bool(condition_stack[-1])
1839 return bool(condition_stack[-1])
1839
1840
1840 def push_conditional_block(should_run):
1841 def push_conditional_block(should_run):
1841 """Push a new conditional context, with its initial state
1842 """Push a new conditional context, with its initial state
1842
1843
1843 i.e. entry a #if block"""
1844 i.e. entry a #if block"""
1844 if not run_line():
1845 if not run_line():
1845 condition_stack.append(None)
1846 condition_stack.append(None)
1846 else:
1847 else:
1847 condition_stack.append(should_run)
1848 condition_stack.append(should_run)
1848
1849
1849 def flip_conditional():
1850 def flip_conditional():
1850 """reverse the current condition state
1851 """reverse the current condition state
1851
1852
1852 i.e. enter a #else
1853 i.e. enter a #else
1853 """
1854 """
1854 assert condition_stack
1855 assert condition_stack
1855 if condition_stack[-1] is not None:
1856 if condition_stack[-1] is not None:
1856 condition_stack[-1] = not condition_stack[-1]
1857 condition_stack[-1] = not condition_stack[-1]
1857
1858
1858 def pop_conditional():
1859 def pop_conditional():
1859 """exit the current skipping context
1860 """exit the current skipping context
1860
1861
1861 i.e. reach the #endif"""
1862 i.e. reach the #endif"""
1862 assert condition_stack
1863 assert condition_stack
1863 condition_stack.pop()
1864 condition_stack.pop()
1864
1865
1865 # We keep track of whether or not we're in a Python block so we
1866 # We keep track of whether or not we're in a Python block so we
1866 # can generate the surrounding doctest magic.
1867 # can generate the surrounding doctest magic.
1867 inpython = False
1868 inpython = False
1868
1869
1869 if self._debug:
1870 if self._debug:
1870 script.append(b'set -x\n')
1871 script.append(b'set -x\n')
1871 if os.getenv('MSYSTEM'):
1872 if os.getenv('MSYSTEM'):
1872 script.append(b'alias pwd="pwd -W"\n')
1873 script.append(b'alias pwd="pwd -W"\n')
1873
1874
1874 if hgcatapult and hgcatapult != os.devnull:
1875 if hgcatapult and hgcatapult != os.devnull:
1875 hgcatapult = hgcatapult.encode('utf8')
1876 hgcatapult = hgcatapult.encode('utf8')
1876 cataname = self.name.encode('utf8')
1877 cataname = self.name.encode('utf8')
1877
1878
1878 # Kludge: use a while loop to keep the pipe from getting
1879 # Kludge: use a while loop to keep the pipe from getting
1879 # closed by our echo commands. The still-running file gets
1880 # closed by our echo commands. The still-running file gets
1880 # reaped at the end of the script, which causes the while
1881 # reaped at the end of the script, which causes the while
1881 # loop to exit and closes the pipe. Sigh.
1882 # loop to exit and closes the pipe. Sigh.
1882 script.append(
1883 script.append(
1883 b'rtendtracing() {\n'
1884 b'rtendtracing() {\n'
1884 b' echo END %(session)s %(name)s >> %(catapult)s\n'
1885 b' echo END %(session)s %(name)s >> %(catapult)s\n'
1885 b' rm -f "$TESTTMP/.still-running"\n'
1886 b' rm -f "$TESTTMP/.still-running"\n'
1886 b'}\n'
1887 b'}\n'
1887 b'trap "rtendtracing" 0\n'
1888 b'trap "rtendtracing" 0\n'
1888 b'touch "$TESTTMP/.still-running"\n'
1889 b'touch "$TESTTMP/.still-running"\n'
1889 b'while [ -f "$TESTTMP/.still-running" ]; do sleep 1; done '
1890 b'while [ -f "$TESTTMP/.still-running" ]; do sleep 1; done '
1890 b'> %(catapult)s &\n'
1891 b'> %(catapult)s &\n'
1891 b'HGCATAPULTSESSION=%(session)s ; export HGCATAPULTSESSION\n'
1892 b'HGCATAPULTSESSION=%(session)s ; export HGCATAPULTSESSION\n'
1892 b'echo START %(session)s %(name)s >> %(catapult)s\n'
1893 b'echo START %(session)s %(name)s >> %(catapult)s\n'
1893 % {
1894 % {
1894 b'name': cataname,
1895 b'name': cataname,
1895 b'session': session,
1896 b'session': session,
1896 b'catapult': hgcatapult,
1897 b'catapult': hgcatapult,
1897 }
1898 }
1898 )
1899 )
1899
1900
1900 if self._case:
1901 if self._case:
1901 casestr = b'#'.join(self._case)
1902 casestr = b'#'.join(self._case)
1902 if isinstance(casestr, str):
1903 if isinstance(casestr, str):
1903 quoted = shellquote(casestr)
1904 quoted = shellquote(casestr)
1904 else:
1905 else:
1905 quoted = shellquote(casestr.decode('utf8')).encode('utf8')
1906 quoted = shellquote(casestr.decode('utf8')).encode('utf8')
1906 script.append(b'TESTCASE=%s\n' % quoted)
1907 script.append(b'TESTCASE=%s\n' % quoted)
1907 script.append(b'export TESTCASE\n')
1908 script.append(b'export TESTCASE\n')
1908
1909
1909 n = 0
1910 n = 0
1910 for n, l in enumerate(lines):
1911 for n, l in enumerate(lines):
1911 if not l.endswith(b'\n'):
1912 if not l.endswith(b'\n'):
1912 l += b'\n'
1913 l += b'\n'
1913 if l.startswith(b'#require'):
1914 if l.startswith(b'#require'):
1914 lsplit = l.split()
1915 lsplit = l.split()
1915 if len(lsplit) < 2 or lsplit[0] != b'#require':
1916 if len(lsplit) < 2 or lsplit[0] != b'#require':
1916 after.setdefault(pos, []).append(
1917 after.setdefault(pos, []).append(
1917 b' !!! invalid #require\n'
1918 b' !!! invalid #require\n'
1918 )
1919 )
1919 if run_line():
1920 if run_line():
1920 haveresult, message = self._hghave(lsplit[1:])
1921 haveresult, message = self._hghave(lsplit[1:])
1921 if not haveresult:
1922 if not haveresult:
1922 script = [b'echo "%s"\nexit 80\n' % message]
1923 script = [b'echo "%s"\nexit 80\n' % message]
1923 break
1924 break
1924 after.setdefault(pos, []).append(l)
1925 after.setdefault(pos, []).append(l)
1925 elif l.startswith(b'#if'):
1926 elif l.startswith(b'#if'):
1926 lsplit = l.split()
1927 lsplit = l.split()
1927 if len(lsplit) < 2 or lsplit[0] != b'#if':
1928 if len(lsplit) < 2 or lsplit[0] != b'#if':
1928 after.setdefault(pos, []).append(b' !!! invalid #if\n')
1929 after.setdefault(pos, []).append(b' !!! invalid #if\n')
1929 push_conditional_block(self._iftest(lsplit[1:]))
1930 push_conditional_block(self._iftest(lsplit[1:]))
1930 after.setdefault(pos, []).append(l)
1931 after.setdefault(pos, []).append(l)
1931 elif l.startswith(b'#else'):
1932 elif l.startswith(b'#else'):
1932 if not condition_stack:
1933 if not condition_stack:
1933 after.setdefault(pos, []).append(b' !!! missing #if\n')
1934 after.setdefault(pos, []).append(b' !!! missing #if\n')
1934 flip_conditional()
1935 flip_conditional()
1935 after.setdefault(pos, []).append(l)
1936 after.setdefault(pos, []).append(l)
1936 elif l.startswith(b'#endif'):
1937 elif l.startswith(b'#endif'):
1937 if not condition_stack:
1938 if not condition_stack:
1938 after.setdefault(pos, []).append(b' !!! missing #if\n')
1939 after.setdefault(pos, []).append(b' !!! missing #if\n')
1939 pop_conditional()
1940 pop_conditional()
1940 after.setdefault(pos, []).append(l)
1941 after.setdefault(pos, []).append(l)
1941 elif not run_line():
1942 elif not run_line():
1942 after.setdefault(pos, []).append(l)
1943 after.setdefault(pos, []).append(l)
1943 elif l.startswith(b' >>> '): # python inlines
1944 elif l.startswith(b' >>> '): # python inlines
1944 after.setdefault(pos, []).append(l)
1945 after.setdefault(pos, []).append(l)
1945 prepos = pos
1946 prepos = pos
1946 pos = n
1947 pos = n
1947 if not inpython:
1948 if not inpython:
1948 # We've just entered a Python block. Add the header.
1949 # We've just entered a Python block. Add the header.
1949 inpython = True
1950 inpython = True
1950 addsalt(prepos, False) # Make sure we report the exit code.
1951 addsalt(prepos, False) # Make sure we report the exit code.
1951 script.append(b'"%s" -m heredoctest <<EOF\n' % PYTHON)
1952 script.append(b'"%s" -m heredoctest <<EOF\n' % PYTHON)
1952 addsalt(n, True)
1953 addsalt(n, True)
1953 script.append(l[2:])
1954 script.append(l[2:])
1954 elif l.startswith(b' ... '): # python inlines
1955 elif l.startswith(b' ... '): # python inlines
1955 after.setdefault(prepos, []).append(l)
1956 after.setdefault(prepos, []).append(l)
1956 script.append(l[2:])
1957 script.append(l[2:])
1957 elif l.startswith(b' $ '): # commands
1958 elif l.startswith(b' $ '): # commands
1958 if inpython:
1959 if inpython:
1959 script.append(b'EOF\n')
1960 script.append(b'EOF\n')
1960 inpython = False
1961 inpython = False
1961 after.setdefault(pos, []).append(l)
1962 after.setdefault(pos, []).append(l)
1962 prepos = pos
1963 prepos = pos
1963 pos = n
1964 pos = n
1964 addsalt(n, False)
1965 addsalt(n, False)
1965 rawcmd = l[4:]
1966 rawcmd = l[4:]
1966 cmd = rawcmd.split()
1967 cmd = rawcmd.split()
1967 toggletrace(rawcmd)
1968 toggletrace(rawcmd)
1968 if len(cmd) == 2 and cmd[0] == b'cd':
1969 if len(cmd) == 2 and cmd[0] == b'cd':
1969 rawcmd = b'cd %s || exit 1\n' % cmd[1]
1970 rawcmd = b'cd %s || exit 1\n' % cmd[1]
1970 script.append(rawcmd)
1971 script.append(rawcmd)
1971 elif l.startswith(b' > '): # continuations
1972 elif l.startswith(b' > '): # continuations
1972 after.setdefault(prepos, []).append(l)
1973 after.setdefault(prepos, []).append(l)
1973 script.append(l[4:])
1974 script.append(l[4:])
1974 elif l.startswith(b' '): # results
1975 elif l.startswith(b' '): # results
1975 # Queue up a list of expected results.
1976 # Queue up a list of expected results.
1976 expected.setdefault(pos, []).append(l[2:])
1977 expected.setdefault(pos, []).append(l[2:])
1977 else:
1978 else:
1978 if inpython:
1979 if inpython:
1979 script.append(b'EOF\n')
1980 script.append(b'EOF\n')
1980 inpython = False
1981 inpython = False
1981 # Non-command/result. Queue up for merged output.
1982 # Non-command/result. Queue up for merged output.
1982 after.setdefault(pos, []).append(l)
1983 after.setdefault(pos, []).append(l)
1983
1984
1984 if inpython:
1985 if inpython:
1985 script.append(b'EOF\n')
1986 script.append(b'EOF\n')
1986 if condition_stack:
1987 if condition_stack:
1987 after.setdefault(pos, []).append(b' !!! missing #endif\n')
1988 after.setdefault(pos, []).append(b' !!! missing #endif\n')
1988 addsalt(n + 1, False)
1989 addsalt(n + 1, False)
1989 # Need to end any current per-command trace
1990 # Need to end any current per-command trace
1990 if activetrace:
1991 if activetrace:
1991 toggletrace()
1992 toggletrace()
1992 return salt, script, after, expected
1993 return salt, script, after, expected
1993
1994
1994 def _processoutput(self, exitcode, output, salt, after, expected):
1995 def _processoutput(self, exitcode, output, salt, after, expected):
1995 # Merge the script output back into a unified test.
1996 # Merge the script output back into a unified test.
1996 warnonly = WARN_UNDEFINED # 1: not yet; 2: yes; 3: for sure not
1997 warnonly = WARN_UNDEFINED # 1: not yet; 2: yes; 3: for sure not
1997 if exitcode != 0:
1998 if exitcode != 0:
1998 warnonly = WARN_NO
1999 warnonly = WARN_NO
1999
2000
2000 pos = -1
2001 pos = -1
2001 postout = []
2002 postout = []
2002 for out_rawline in output:
2003 for out_rawline in output:
2003 out_line, cmd_line = out_rawline, None
2004 out_line, cmd_line = out_rawline, None
2004 if salt in out_rawline:
2005 if salt in out_rawline:
2005 out_line, cmd_line = out_rawline.split(salt, 1)
2006 out_line, cmd_line = out_rawline.split(salt, 1)
2006
2007
2007 pos, postout, warnonly = self._process_out_line(
2008 pos, postout, warnonly = self._process_out_line(
2008 out_line, pos, postout, expected, warnonly
2009 out_line, pos, postout, expected, warnonly
2009 )
2010 )
2010 pos, postout = self._process_cmd_line(cmd_line, pos, postout, after)
2011 pos, postout = self._process_cmd_line(cmd_line, pos, postout, after)
2011
2012
2012 if pos in after:
2013 if pos in after:
2013 postout += after.pop(pos)
2014 postout += after.pop(pos)
2014
2015
2015 if warnonly == WARN_YES:
2016 if warnonly == WARN_YES:
2016 exitcode = False # Set exitcode to warned.
2017 exitcode = False # Set exitcode to warned.
2017
2018
2018 return exitcode, postout
2019 return exitcode, postout
2019
2020
2020 def _process_out_line(self, out_line, pos, postout, expected, warnonly):
2021 def _process_out_line(self, out_line, pos, postout, expected, warnonly):
2021 while out_line:
2022 while out_line:
2022 if not out_line.endswith(b'\n'):
2023 if not out_line.endswith(b'\n'):
2023 out_line += b' (no-eol)\n'
2024 out_line += b' (no-eol)\n'
2024
2025
2025 # Find the expected output at the current position.
2026 # Find the expected output at the current position.
2026 els = [None]
2027 els = [None]
2027 if expected.get(pos, None):
2028 if expected.get(pos, None):
2028 els = expected[pos]
2029 els = expected[pos]
2029
2030
2030 optional = []
2031 optional = []
2031 for i, el in enumerate(els):
2032 for i, el in enumerate(els):
2032 r = False
2033 r = False
2033 if el:
2034 if el:
2034 r, exact = self.linematch(el, out_line)
2035 r, exact = self.linematch(el, out_line)
2035 if isinstance(r, str):
2036 if isinstance(r, str):
2036 if r == '-glob':
2037 if r == '-glob':
2037 out_line = ''.join(el.rsplit(' (glob)', 1))
2038 out_line = ''.join(el.rsplit(' (glob)', 1))
2038 r = '' # Warn only this line.
2039 r = '' # Warn only this line.
2039 elif r == "retry":
2040 elif r == "retry":
2040 postout.append(b' ' + el)
2041 postout.append(b' ' + el)
2041 else:
2042 else:
2042 log('\ninfo, unknown linematch result: %r\n' % r)
2043 log('\ninfo, unknown linematch result: %r\n' % r)
2043 r = False
2044 r = False
2044 if r:
2045 if r:
2045 els.pop(i)
2046 els.pop(i)
2046 break
2047 break
2047 if el:
2048 if el:
2048 if isoptional(el):
2049 if isoptional(el):
2049 optional.append(i)
2050 optional.append(i)
2050 else:
2051 else:
2051 m = optline.match(el)
2052 m = optline.match(el)
2052 if m:
2053 if m:
2053 conditions = [c for c in m.group(2).split(b' ')]
2054 conditions = [c for c in m.group(2).split(b' ')]
2054
2055
2055 if not self._iftest(conditions):
2056 if not self._iftest(conditions):
2056 optional.append(i)
2057 optional.append(i)
2057 if exact:
2058 if exact:
2058 # Don't allow line to be matches against a later
2059 # Don't allow line to be matches against a later
2059 # line in the output
2060 # line in the output
2060 els.pop(i)
2061 els.pop(i)
2061 break
2062 break
2062
2063
2063 if r:
2064 if r:
2064 if r == "retry":
2065 if r == "retry":
2065 continue
2066 continue
2066 # clean up any optional leftovers
2067 # clean up any optional leftovers
2067 for i in optional:
2068 for i in optional:
2068 postout.append(b' ' + els[i])
2069 postout.append(b' ' + els[i])
2069 for i in reversed(optional):
2070 for i in reversed(optional):
2070 del els[i]
2071 del els[i]
2071 postout.append(b' ' + el)
2072 postout.append(b' ' + el)
2072 else:
2073 else:
2073 if self.NEEDESCAPE(out_line):
2074 if self.NEEDESCAPE(out_line):
2074 out_line = TTest._stringescape(
2075 out_line = TTest._stringescape(
2075 b'%s (esc)\n' % out_line.rstrip(b'\n')
2076 b'%s (esc)\n' % out_line.rstrip(b'\n')
2076 )
2077 )
2077 postout.append(b' ' + out_line) # Let diff deal with it.
2078 postout.append(b' ' + out_line) # Let diff deal with it.
2078 if r != '': # If line failed.
2079 if r != '': # If line failed.
2079 warnonly = WARN_NO
2080 warnonly = WARN_NO
2080 elif warnonly == WARN_UNDEFINED:
2081 elif warnonly == WARN_UNDEFINED:
2081 warnonly = WARN_YES
2082 warnonly = WARN_YES
2082 break
2083 break
2083 else:
2084 else:
2084 # clean up any optional leftovers
2085 # clean up any optional leftovers
2085 while expected.get(pos, None):
2086 while expected.get(pos, None):
2086 el = expected[pos].pop(0)
2087 el = expected[pos].pop(0)
2087 if el:
2088 if el:
2088 if not isoptional(el):
2089 if not isoptional(el):
2089 m = optline.match(el)
2090 m = optline.match(el)
2090 if m:
2091 if m:
2091 conditions = [c for c in m.group(2).split(b' ')]
2092 conditions = [c for c in m.group(2).split(b' ')]
2092
2093
2093 if self._iftest(conditions):
2094 if self._iftest(conditions):
2094 # Don't append as optional line
2095 # Don't append as optional line
2095 continue
2096 continue
2096 else:
2097 else:
2097 continue
2098 continue
2098 postout.append(b' ' + el)
2099 postout.append(b' ' + el)
2099 return pos, postout, warnonly
2100 return pos, postout, warnonly
2100
2101
2101 def _process_cmd_line(self, cmd_line, pos, postout, after):
2102 def _process_cmd_line(self, cmd_line, pos, postout, after):
2102 """process a "command" part of a line from unified test output"""
2103 """process a "command" part of a line from unified test output"""
2103 if cmd_line:
2104 if cmd_line:
2104 # Add on last return code.
2105 # Add on last return code.
2105 ret = int(cmd_line.split()[1])
2106 ret = int(cmd_line.split()[1])
2106 if ret != 0:
2107 if ret != 0:
2107 postout.append(b' [%d]\n' % ret)
2108 postout.append(b' [%d]\n' % ret)
2108 if pos in after:
2109 if pos in after:
2109 # Merge in non-active test bits.
2110 # Merge in non-active test bits.
2110 postout += after.pop(pos)
2111 postout += after.pop(pos)
2111 pos = int(cmd_line.split()[0])
2112 pos = int(cmd_line.split()[0])
2112 return pos, postout
2113 return pos, postout
2113
2114
2114 @staticmethod
2115 @staticmethod
2115 def rematch(el, l):
2116 def rematch(el, l):
2116 try:
2117 try:
2117 # parse any flags at the beginning of the regex. Only 'i' is
2118 # parse any flags at the beginning of the regex. Only 'i' is
2118 # supported right now, but this should be easy to extend.
2119 # supported right now, but this should be easy to extend.
2119 flags, el = re.match(br'^(\(\?i\))?(.*)', el).groups()[0:2]
2120 flags, el = re.match(br'^(\(\?i\))?(.*)', el).groups()[0:2]
2120 flags = flags or b''
2121 flags = flags or b''
2121 el = flags + b'(?:' + el + b')'
2122 el = flags + b'(?:' + el + b')'
2122 # use \Z to ensure that the regex matches to the end of the string
2123 # use \Z to ensure that the regex matches to the end of the string
2123 if WINDOWS:
2124 if WINDOWS:
2124 return re.match(el + br'\r?\n\Z', l)
2125 return re.match(el + br'\r?\n\Z', l)
2125 return re.match(el + br'\n\Z', l)
2126 return re.match(el + br'\n\Z', l)
2126 except re.error:
2127 except re.error:
2127 # el is an invalid regex
2128 # el is an invalid regex
2128 return False
2129 return False
2129
2130
2130 @staticmethod
2131 @staticmethod
2131 def globmatch(el, l):
2132 def globmatch(el, l):
2132 # The only supported special characters are * and ? plus / which also
2133 # The only supported special characters are * and ? plus / which also
2133 # matches \ on windows. Escaping of these characters is supported.
2134 # matches \ on windows. Escaping of these characters is supported.
2134 if el + b'\n' == l:
2135 if el + b'\n' == l:
2135 if os.altsep:
2136 if os.altsep:
2136 # matching on "/" is not needed for this line
2137 # matching on "/" is not needed for this line
2137 for pat in checkcodeglobpats:
2138 for pat in checkcodeglobpats:
2138 if pat.match(el):
2139 if pat.match(el):
2139 return True
2140 return True
2140 return b'-glob'
2141 return b'-glob'
2141 return True
2142 return True
2142 el = el.replace(b'$LOCALIP', b'*')
2143 el = el.replace(b'$LOCALIP', b'*')
2143 i, n = 0, len(el)
2144 i, n = 0, len(el)
2144 res = b''
2145 res = b''
2145 while i < n:
2146 while i < n:
2146 c = el[i : i + 1]
2147 c = el[i : i + 1]
2147 i += 1
2148 i += 1
2148 if c == b'\\' and i < n and el[i : i + 1] in b'*?\\/':
2149 if c == b'\\' and i < n and el[i : i + 1] in b'*?\\/':
2149 res += el[i - 1 : i + 1]
2150 res += el[i - 1 : i + 1]
2150 i += 1
2151 i += 1
2151 elif c == b'*':
2152 elif c == b'*':
2152 res += b'.*'
2153 res += b'.*'
2153 elif c == b'?':
2154 elif c == b'?':
2154 res += b'.'
2155 res += b'.'
2155 elif c == b'/' and os.altsep:
2156 elif c == b'/' and os.altsep:
2156 res += b'[/\\\\]'
2157 res += b'[/\\\\]'
2157 else:
2158 else:
2158 res += re.escape(c)
2159 res += re.escape(c)
2159 return TTest.rematch(res, l)
2160 return TTest.rematch(res, l)
2160
2161
2161 def linematch(self, el, l):
2162 def linematch(self, el, l):
2162 if el == l: # perfect match (fast)
2163 if el == l: # perfect match (fast)
2163 return True, True
2164 return True, True
2164 retry = False
2165 retry = False
2165 if isoptional(el):
2166 if isoptional(el):
2166 retry = "retry"
2167 retry = "retry"
2167 el = el[: -len(MARK_OPTIONAL)] + b"\n"
2168 el = el[: -len(MARK_OPTIONAL)] + b"\n"
2168 else:
2169 else:
2169 m = optline.match(el)
2170 m = optline.match(el)
2170 if m:
2171 if m:
2171 conditions = [c for c in m.group(2).split(b' ')]
2172 conditions = [c for c in m.group(2).split(b' ')]
2172
2173
2173 el = m.group(1) + b"\n"
2174 el = m.group(1) + b"\n"
2174 if not self._iftest(conditions):
2175 if not self._iftest(conditions):
2175 # listed feature missing, should not match
2176 # listed feature missing, should not match
2176 return "retry", False
2177 return "retry", False
2177
2178
2178 if el.endswith(b" (esc)\n"):
2179 if el.endswith(b" (esc)\n"):
2179 el = el[:-7].decode('unicode_escape') + '\n'
2180 el = el[:-7].decode('unicode_escape') + '\n'
2180 el = el.encode('latin-1')
2181 el = el.encode('latin-1')
2181 if el == l or WINDOWS and el[:-1] + b'\r\n' == l:
2182 if el == l or WINDOWS and el[:-1] + b'\r\n' == l:
2182 return True, True
2183 return True, True
2183 if el.endswith(b" (re)\n"):
2184 if el.endswith(b" (re)\n"):
2184 return (TTest.rematch(el[:-6], l) or retry), False
2185 return (TTest.rematch(el[:-6], l) or retry), False
2185 if el.endswith(b" (glob)\n"):
2186 if el.endswith(b" (glob)\n"):
2186 # ignore '(glob)' added to l by 'replacements'
2187 # ignore '(glob)' added to l by 'replacements'
2187 if l.endswith(b" (glob)\n"):
2188 if l.endswith(b" (glob)\n"):
2188 l = l[:-8] + b"\n"
2189 l = l[:-8] + b"\n"
2189 return (TTest.globmatch(el[:-8], l) or retry), False
2190 return (TTest.globmatch(el[:-8], l) or retry), False
2190 if os.altsep:
2191 if os.altsep:
2191 _l = l.replace(b'\\', b'/')
2192 _l = l.replace(b'\\', b'/')
2192 if el == _l or WINDOWS and el[:-1] + b'\r\n' == _l:
2193 if el == _l or WINDOWS and el[:-1] + b'\r\n' == _l:
2193 return True, True
2194 return True, True
2194 return retry, True
2195 return retry, True
2195
2196
2196 @staticmethod
2197 @staticmethod
2197 def parsehghaveoutput(lines):
2198 def parsehghaveoutput(lines):
2198 """Parse hghave log lines.
2199 """Parse hghave log lines.
2199
2200
2200 Return tuple of lists (missing, failed):
2201 Return tuple of lists (missing, failed):
2201 * the missing/unknown features
2202 * the missing/unknown features
2202 * the features for which existence check failed"""
2203 * the features for which existence check failed"""
2203 missing = []
2204 missing = []
2204 failed = []
2205 failed = []
2205 for line in lines:
2206 for line in lines:
2206 if line.startswith(TTest.SKIPPED_PREFIX):
2207 if line.startswith(TTest.SKIPPED_PREFIX):
2207 line = line.splitlines()[0]
2208 line = line.splitlines()[0]
2208 missing.append(_bytes2sys(line[len(TTest.SKIPPED_PREFIX) :]))
2209 missing.append(_bytes2sys(line[len(TTest.SKIPPED_PREFIX) :]))
2209 elif line.startswith(TTest.FAILED_PREFIX):
2210 elif line.startswith(TTest.FAILED_PREFIX):
2210 line = line.splitlines()[0]
2211 line = line.splitlines()[0]
2211 failed.append(_bytes2sys(line[len(TTest.FAILED_PREFIX) :]))
2212 failed.append(_bytes2sys(line[len(TTest.FAILED_PREFIX) :]))
2212
2213
2213 return missing, failed
2214 return missing, failed
2214
2215
2215 @staticmethod
2216 @staticmethod
2216 def _escapef(m):
2217 def _escapef(m):
2217 return TTest.ESCAPEMAP[m.group(0)]
2218 return TTest.ESCAPEMAP[m.group(0)]
2218
2219
2219 @staticmethod
2220 @staticmethod
2220 def _stringescape(s):
2221 def _stringescape(s):
2221 return TTest.ESCAPESUB(TTest._escapef, s)
2222 return TTest.ESCAPESUB(TTest._escapef, s)
2222
2223
2223
2224
2224 iolock = threading.RLock()
2225 iolock = threading.RLock()
2225 firstlock = threading.RLock()
2226 firstlock = threading.RLock()
2226 firsterror = False
2227 firsterror = False
2227
2228
2228 base_class = unittest.TextTestResult
2229 base_class = unittest.TextTestResult
2229
2230
2230
2231
2231 class TestResult(base_class):
2232 class TestResult(base_class):
2232 """Holds results when executing via unittest."""
2233 """Holds results when executing via unittest."""
2233
2234
2234 def __init__(self, options, *args, **kwargs):
2235 def __init__(self, options, *args, **kwargs):
2235 super(TestResult, self).__init__(*args, **kwargs)
2236 super(TestResult, self).__init__(*args, **kwargs)
2236
2237
2237 self._options = options
2238 self._options = options
2238
2239
2239 # unittest.TestResult didn't have skipped until 2.7. We need to
2240 # unittest.TestResult didn't have skipped until 2.7. We need to
2240 # polyfill it.
2241 # polyfill it.
2241 self.skipped = []
2242 self.skipped = []
2242
2243
2243 # We have a custom "ignored" result that isn't present in any Python
2244 # We have a custom "ignored" result that isn't present in any Python
2244 # unittest implementation. It is very similar to skipped. It may make
2245 # unittest implementation. It is very similar to skipped. It may make
2245 # sense to map it into skip some day.
2246 # sense to map it into skip some day.
2246 self.ignored = []
2247 self.ignored = []
2247
2248
2248 self.times = []
2249 self.times = []
2249 self._firststarttime = None
2250 self._firststarttime = None
2250 # Data stored for the benefit of generating xunit reports.
2251 # Data stored for the benefit of generating xunit reports.
2251 self.successes = []
2252 self.successes = []
2252 self.faildata = {}
2253 self.faildata = {}
2253
2254
2254 if options.color == 'auto':
2255 if options.color == 'auto':
2255 isatty = self.stream.isatty()
2256 isatty = self.stream.isatty()
2256 # For some reason, redirecting stdout on Windows disables the ANSI
2257 # For some reason, redirecting stdout on Windows disables the ANSI
2257 # color processing of stderr, which is what is used to print the
2258 # color processing of stderr, which is what is used to print the
2258 # output. Therefore, both must be tty on Windows to enable color.
2259 # output. Therefore, both must be tty on Windows to enable color.
2259 if WINDOWS:
2260 if WINDOWS:
2260 isatty = isatty and sys.stdout.isatty()
2261 isatty = isatty and sys.stdout.isatty()
2261 self.color = pygmentspresent and isatty
2262 self.color = pygmentspresent and isatty
2262 elif options.color == 'never':
2263 elif options.color == 'never':
2263 self.color = False
2264 self.color = False
2264 else: # 'always', for testing purposes
2265 else: # 'always', for testing purposes
2265 self.color = pygmentspresent
2266 self.color = pygmentspresent
2266
2267
2267 def onStart(self, test):
2268 def onStart(self, test):
2268 """Can be overriden by custom TestResult"""
2269 """Can be overriden by custom TestResult"""
2269
2270
2270 def onEnd(self):
2271 def onEnd(self):
2271 """Can be overriden by custom TestResult"""
2272 """Can be overriden by custom TestResult"""
2272
2273
2273 def addFailure(self, test, reason):
2274 def addFailure(self, test, reason):
2274 self.failures.append((test, reason))
2275 self.failures.append((test, reason))
2275
2276
2276 if self._options.first:
2277 if self._options.first:
2277 self.stop()
2278 self.stop()
2278 else:
2279 else:
2279 with iolock:
2280 with iolock:
2280 if reason == "timed out":
2281 if reason == "timed out":
2281 self.stream.write('t')
2282 self.stream.write('t')
2282 else:
2283 else:
2283 if not self._options.nodiff:
2284 if not self._options.nodiff:
2284 self.stream.write('\n')
2285 self.stream.write('\n')
2285 # Exclude the '\n' from highlighting to lex correctly
2286 # Exclude the '\n' from highlighting to lex correctly
2286 formatted = 'ERROR: %s output changed\n' % test
2287 formatted = 'ERROR: %s output changed\n' % test
2287 self.stream.write(highlightmsg(formatted, self.color))
2288 self.stream.write(highlightmsg(formatted, self.color))
2288 self.stream.write('!')
2289 self.stream.write('!')
2289
2290
2290 self.stream.flush()
2291 self.stream.flush()
2291
2292
2292 def addSuccess(self, test):
2293 def addSuccess(self, test):
2293 with iolock:
2294 with iolock:
2294 super(TestResult, self).addSuccess(test)
2295 super(TestResult, self).addSuccess(test)
2295 self.successes.append(test)
2296 self.successes.append(test)
2296
2297
2297 def addError(self, test, err):
2298 def addError(self, test, err):
2298 super(TestResult, self).addError(test, err)
2299 super(TestResult, self).addError(test, err)
2299 if self._options.first:
2300 if self._options.first:
2300 self.stop()
2301 self.stop()
2301
2302
2302 # Polyfill.
2303 # Polyfill.
2303 def addSkip(self, test, reason):
2304 def addSkip(self, test, reason):
2304 self.skipped.append((test, reason))
2305 self.skipped.append((test, reason))
2305 with iolock:
2306 with iolock:
2306 if self.showAll:
2307 if self.showAll:
2307 self.stream.writeln('skipped %s' % reason)
2308 self.stream.writeln('skipped %s' % reason)
2308 else:
2309 else:
2309 self.stream.write('s')
2310 self.stream.write('s')
2310 self.stream.flush()
2311 self.stream.flush()
2311
2312
2312 def addIgnore(self, test, reason):
2313 def addIgnore(self, test, reason):
2313 self.ignored.append((test, reason))
2314 self.ignored.append((test, reason))
2314 with iolock:
2315 with iolock:
2315 if self.showAll:
2316 if self.showAll:
2316 self.stream.writeln('ignored %s' % reason)
2317 self.stream.writeln('ignored %s' % reason)
2317 else:
2318 else:
2318 if reason not in ('not retesting', "doesn't match keyword"):
2319 if reason not in ('not retesting', "doesn't match keyword"):
2319 self.stream.write('i')
2320 self.stream.write('i')
2320 else:
2321 else:
2321 self.testsRun += 1
2322 self.testsRun += 1
2322 self.stream.flush()
2323 self.stream.flush()
2323
2324
2324 def addOutputMismatch(self, test, ret, got, expected):
2325 def addOutputMismatch(self, test, ret, got, expected):
2325 """Record a mismatch in test output for a particular test."""
2326 """Record a mismatch in test output for a particular test."""
2326 if self.shouldStop or firsterror:
2327 if self.shouldStop or firsterror:
2327 # don't print, some other test case already failed and
2328 # don't print, some other test case already failed and
2328 # printed, we're just stale and probably failed due to our
2329 # printed, we're just stale and probably failed due to our
2329 # temp dir getting cleaned up.
2330 # temp dir getting cleaned up.
2330 return
2331 return
2331
2332
2332 accepted = False
2333 accepted = False
2333 lines = []
2334 lines = []
2334
2335
2335 with iolock:
2336 with iolock:
2336 if self._options.nodiff:
2337 if self._options.nodiff:
2337 pass
2338 pass
2338 elif self._options.view:
2339 elif self._options.view:
2339 v = self._options.view
2340 v = self._options.view
2340 subprocess.call(
2341 subprocess.call(
2341 r'"%s" "%s" "%s"'
2342 r'"%s" "%s" "%s"'
2342 % (v, _bytes2sys(test.refpath), _bytes2sys(test.errpath)),
2343 % (v, _bytes2sys(test.refpath), _bytes2sys(test.errpath)),
2343 shell=True,
2344 shell=True,
2344 )
2345 )
2345 else:
2346 else:
2346 servefail, lines = getdiff(
2347 servefail, lines = getdiff(
2347 expected, got, test.refpath, test.errpath
2348 expected, got, test.refpath, test.errpath
2348 )
2349 )
2349 self.stream.write('\n')
2350 self.stream.write('\n')
2350 for line in lines:
2351 for line in lines:
2351 line = highlightdiff(line, self.color)
2352 line = highlightdiff(line, self.color)
2352 self.stream.flush()
2353 self.stream.flush()
2353 self.stream.buffer.write(line)
2354 self.stream.buffer.write(line)
2354 self.stream.buffer.flush()
2355 self.stream.buffer.flush()
2355
2356
2356 if servefail:
2357 if servefail:
2357 raise test.failureException(
2358 raise test.failureException(
2358 'server failed to start (HGPORT=%s)' % test._startport
2359 'server failed to start (HGPORT=%s)' % test._startport
2359 )
2360 )
2360
2361
2361 # handle interactive prompt without releasing iolock
2362 # handle interactive prompt without releasing iolock
2362 if self._options.interactive:
2363 if self._options.interactive:
2363 if test.readrefout() != expected:
2364 if test.readrefout() != expected:
2364 self.stream.write(
2365 self.stream.write(
2365 'Reference output has changed (run again to prompt '
2366 'Reference output has changed (run again to prompt '
2366 'changes)'
2367 'changes)'
2367 )
2368 )
2368 else:
2369 else:
2369 self.stream.write('Accept this change? [y/N] ')
2370 self.stream.write('Accept this change? [y/N] ')
2370 self.stream.flush()
2371 self.stream.flush()
2371 answer = sys.stdin.readline().strip()
2372 answer = sys.stdin.readline().strip()
2372 if answer.lower() in ('y', 'yes'):
2373 if answer.lower() in ('y', 'yes'):
2373 if test.path.endswith(b'.t'):
2374 if test.path.endswith(b'.t'):
2374 rename(test.errpath, test.path)
2375 rename(test.errpath, test.path)
2375 else:
2376 else:
2376 rename(test.errpath, b'%s.out' % test.path)
2377 rename(test.errpath, b'%s.out' % test.path)
2377 accepted = True
2378 accepted = True
2378 if not accepted:
2379 if not accepted:
2379 self.faildata[test.name] = b''.join(lines)
2380 self.faildata[test.name] = b''.join(lines)
2380
2381
2381 return accepted
2382 return accepted
2382
2383
2383 def startTest(self, test):
2384 def startTest(self, test):
2384 super(TestResult, self).startTest(test)
2385 super(TestResult, self).startTest(test)
2385
2386
2386 # os.times module computes the user time and system time spent by
2387 # os.times module computes the user time and system time spent by
2387 # child's processes along with real elapsed time taken by a process.
2388 # child's processes along with real elapsed time taken by a process.
2388 # This module has one limitation. It can only work for Linux user
2389 # This module has one limitation. It can only work for Linux user
2389 # and not for Windows. Hence why we fall back to another function
2390 # and not for Windows. Hence why we fall back to another function
2390 # for wall time calculations.
2391 # for wall time calculations.
2391 test.started_times = os.times()
2392 test.started_times = os.times()
2392 # TODO use a monotonic clock once support for Python 2.7 is dropped.
2393 # TODO use a monotonic clock once support for Python 2.7 is dropped.
2393 test.started_time = time.time()
2394 test.started_time = time.time()
2394 if self._firststarttime is None: # thread racy but irrelevant
2395 if self._firststarttime is None: # thread racy but irrelevant
2395 self._firststarttime = test.started_time
2396 self._firststarttime = test.started_time
2396
2397
2397 def stopTest(self, test, interrupted=False):
2398 def stopTest(self, test, interrupted=False):
2398 super(TestResult, self).stopTest(test)
2399 super(TestResult, self).stopTest(test)
2399
2400
2400 test.stopped_times = os.times()
2401 test.stopped_times = os.times()
2401 stopped_time = time.time()
2402 stopped_time = time.time()
2402
2403
2403 starttime = test.started_times
2404 starttime = test.started_times
2404 endtime = test.stopped_times
2405 endtime = test.stopped_times
2405 origin = self._firststarttime
2406 origin = self._firststarttime
2406 self.times.append(
2407 self.times.append(
2407 (
2408 (
2408 test.name,
2409 test.name,
2409 endtime[2] - starttime[2], # user space CPU time
2410 endtime[2] - starttime[2], # user space CPU time
2410 endtime[3] - starttime[3], # sys space CPU time
2411 endtime[3] - starttime[3], # sys space CPU time
2411 stopped_time - test.started_time, # real time
2412 stopped_time - test.started_time, # real time
2412 test.started_time - origin, # start date in run context
2413 test.started_time - origin, # start date in run context
2413 stopped_time - origin, # end date in run context
2414 stopped_time - origin, # end date in run context
2414 )
2415 )
2415 )
2416 )
2416
2417
2417 if interrupted:
2418 if interrupted:
2418 with iolock:
2419 with iolock:
2419 self.stream.writeln(
2420 self.stream.writeln(
2420 'INTERRUPTED: %s (after %d seconds)'
2421 'INTERRUPTED: %s (after %d seconds)'
2421 % (test.name, self.times[-1][3])
2422 % (test.name, self.times[-1][3])
2422 )
2423 )
2423
2424
2424
2425
2425 def getTestResult():
2426 def getTestResult():
2426 """
2427 """
2427 Returns the relevant test result
2428 Returns the relevant test result
2428 """
2429 """
2429 if "CUSTOM_TEST_RESULT" in os.environ:
2430 if "CUSTOM_TEST_RESULT" in os.environ:
2430 testresultmodule = __import__(os.environ["CUSTOM_TEST_RESULT"])
2431 testresultmodule = __import__(os.environ["CUSTOM_TEST_RESULT"])
2431 return testresultmodule.TestResult
2432 return testresultmodule.TestResult
2432 else:
2433 else:
2433 return TestResult
2434 return TestResult
2434
2435
2435
2436
2436 class TestSuite(unittest.TestSuite):
2437 class TestSuite(unittest.TestSuite):
2437 """Custom unittest TestSuite that knows how to execute Mercurial tests."""
2438 """Custom unittest TestSuite that knows how to execute Mercurial tests."""
2438
2439
2439 def __init__(
2440 def __init__(
2440 self,
2441 self,
2441 testdir,
2442 testdir,
2442 jobs=1,
2443 jobs=1,
2443 whitelist=None,
2444 whitelist=None,
2444 blacklist=None,
2445 blacklist=None,
2445 keywords=None,
2446 keywords=None,
2446 loop=False,
2447 loop=False,
2447 runs_per_test=1,
2448 runs_per_test=1,
2448 loadtest=None,
2449 loadtest=None,
2449 showchannels=False,
2450 showchannels=False,
2450 *args,
2451 *args,
2451 **kwargs
2452 **kwargs
2452 ):
2453 ):
2453 """Create a new instance that can run tests with a configuration.
2454 """Create a new instance that can run tests with a configuration.
2454
2455
2455 testdir specifies the directory where tests are executed from. This
2456 testdir specifies the directory where tests are executed from. This
2456 is typically the ``tests`` directory from Mercurial's source
2457 is typically the ``tests`` directory from Mercurial's source
2457 repository.
2458 repository.
2458
2459
2459 jobs specifies the number of jobs to run concurrently. Each test
2460 jobs specifies the number of jobs to run concurrently. Each test
2460 executes on its own thread. Tests actually spawn new processes, so
2461 executes on its own thread. Tests actually spawn new processes, so
2461 state mutation should not be an issue.
2462 state mutation should not be an issue.
2462
2463
2463 If there is only one job, it will use the main thread.
2464 If there is only one job, it will use the main thread.
2464
2465
2465 whitelist and blacklist denote tests that have been whitelisted and
2466 whitelist and blacklist denote tests that have been whitelisted and
2466 blacklisted, respectively. These arguments don't belong in TestSuite.
2467 blacklisted, respectively. These arguments don't belong in TestSuite.
2467 Instead, whitelist and blacklist should be handled by the thing that
2468 Instead, whitelist and blacklist should be handled by the thing that
2468 populates the TestSuite with tests. They are present to preserve
2469 populates the TestSuite with tests. They are present to preserve
2469 backwards compatible behavior which reports skipped tests as part
2470 backwards compatible behavior which reports skipped tests as part
2470 of the results.
2471 of the results.
2471
2472
2472 keywords denotes key words that will be used to filter which tests
2473 keywords denotes key words that will be used to filter which tests
2473 to execute. This arguably belongs outside of TestSuite.
2474 to execute. This arguably belongs outside of TestSuite.
2474
2475
2475 loop denotes whether to loop over tests forever.
2476 loop denotes whether to loop over tests forever.
2476 """
2477 """
2477 super(TestSuite, self).__init__(*args, **kwargs)
2478 super(TestSuite, self).__init__(*args, **kwargs)
2478
2479
2479 self._jobs = jobs
2480 self._jobs = jobs
2480 self._whitelist = whitelist
2481 self._whitelist = whitelist
2481 self._blacklist = blacklist
2482 self._blacklist = blacklist
2482 self._keywords = keywords
2483 self._keywords = keywords
2483 self._loop = loop
2484 self._loop = loop
2484 self._runs_per_test = runs_per_test
2485 self._runs_per_test = runs_per_test
2485 self._loadtest = loadtest
2486 self._loadtest = loadtest
2486 self._showchannels = showchannels
2487 self._showchannels = showchannels
2487
2488
2488 def run(self, result):
2489 def run(self, result):
2489 # We have a number of filters that need to be applied. We do this
2490 # We have a number of filters that need to be applied. We do this
2490 # here instead of inside Test because it makes the running logic for
2491 # here instead of inside Test because it makes the running logic for
2491 # Test simpler.
2492 # Test simpler.
2492 tests = []
2493 tests = []
2493 num_tests = [0]
2494 num_tests = [0]
2494 for test in self._tests:
2495 for test in self._tests:
2495
2496
2496 def get():
2497 def get():
2497 num_tests[0] += 1
2498 num_tests[0] += 1
2498 if getattr(test, 'should_reload', False):
2499 if getattr(test, 'should_reload', False):
2499 return self._loadtest(test, num_tests[0])
2500 return self._loadtest(test, num_tests[0])
2500 return test
2501 return test
2501
2502
2502 if not os.path.exists(test.path):
2503 if not os.path.exists(test.path):
2503 result.addSkip(test, "Doesn't exist")
2504 result.addSkip(test, "Doesn't exist")
2504 continue
2505 continue
2505
2506
2506 is_whitelisted = self._whitelist and (
2507 is_whitelisted = self._whitelist and (
2507 test.relpath in self._whitelist or test.bname in self._whitelist
2508 test.relpath in self._whitelist or test.bname in self._whitelist
2508 )
2509 )
2509 if not is_whitelisted:
2510 if not is_whitelisted:
2510 is_blacklisted = self._blacklist and (
2511 is_blacklisted = self._blacklist and (
2511 test.relpath in self._blacklist
2512 test.relpath in self._blacklist
2512 or test.bname in self._blacklist
2513 or test.bname in self._blacklist
2513 )
2514 )
2514 if is_blacklisted:
2515 if is_blacklisted:
2515 result.addSkip(test, 'blacklisted')
2516 result.addSkip(test, 'blacklisted')
2516 continue
2517 continue
2517 if self._keywords:
2518 if self._keywords:
2518 with open(test.path, 'rb') as f:
2519 with open(test.path, 'rb') as f:
2519 t = f.read().lower() + test.bname.lower()
2520 t = f.read().lower() + test.bname.lower()
2520 ignored = False
2521 ignored = False
2521 for k in self._keywords.lower().split():
2522 for k in self._keywords.lower().split():
2522 if k not in t:
2523 if k not in t:
2523 result.addIgnore(test, "doesn't match keyword")
2524 result.addIgnore(test, "doesn't match keyword")
2524 ignored = True
2525 ignored = True
2525 break
2526 break
2526
2527
2527 if ignored:
2528 if ignored:
2528 continue
2529 continue
2529 for _ in range(self._runs_per_test):
2530 for _ in range(self._runs_per_test):
2530 tests.append(get())
2531 tests.append(get())
2531
2532
2532 runtests = list(tests)
2533 runtests = list(tests)
2533 done = queue.Queue()
2534 done = queue.Queue()
2534 running = 0
2535 running = 0
2535
2536
2536 channels_lock = threading.Lock()
2537 channels_lock = threading.Lock()
2537 channels = [""] * self._jobs
2538 channels = [""] * self._jobs
2538
2539
2539 def job(test, result):
2540 def job(test, result):
2540 with channels_lock:
2541 with channels_lock:
2541 for n, v in enumerate(channels):
2542 for n, v in enumerate(channels):
2542 if not v:
2543 if not v:
2543 channel = n
2544 channel = n
2544 break
2545 break
2545 else:
2546 else:
2546 raise ValueError('Could not find output channel')
2547 raise ValueError('Could not find output channel')
2547 channels[channel] = "=" + test.name[5:].split(".")[0]
2548 channels[channel] = "=" + test.name[5:].split(".")[0]
2548
2549
2549 r = None
2550 r = None
2550 try:
2551 try:
2551 test(result)
2552 test(result)
2552 except KeyboardInterrupt:
2553 except KeyboardInterrupt:
2553 pass
2554 pass
2554 except: # re-raises
2555 except: # re-raises
2555 r = ('!', test, 'run-test raised an error, see traceback')
2556 r = ('!', test, 'run-test raised an error, see traceback')
2556 raise
2557 raise
2557 finally:
2558 finally:
2558 try:
2559 try:
2559 channels[channel] = ''
2560 channels[channel] = ''
2560 except IndexError:
2561 except IndexError:
2561 pass
2562 pass
2562 done.put(r)
2563 done.put(r)
2563
2564
2564 def stat():
2565 def stat():
2565 count = 0
2566 count = 0
2566 while channels:
2567 while channels:
2567 d = '\n%03s ' % count
2568 d = '\n%03s ' % count
2568 for n, v in enumerate(channels):
2569 for n, v in enumerate(channels):
2569 if v:
2570 if v:
2570 d += v[0]
2571 d += v[0]
2571 channels[n] = v[1:] or '.'
2572 channels[n] = v[1:] or '.'
2572 else:
2573 else:
2573 d += ' '
2574 d += ' '
2574 d += ' '
2575 d += ' '
2575 with iolock:
2576 with iolock:
2576 sys.stdout.write(d + ' ')
2577 sys.stdout.write(d + ' ')
2577 sys.stdout.flush()
2578 sys.stdout.flush()
2578 for x in range(10):
2579 for x in range(10):
2579 if channels:
2580 if channels:
2580 time.sleep(0.1)
2581 time.sleep(0.1)
2581 count += 1
2582 count += 1
2582
2583
2583 stoppedearly = False
2584 stoppedearly = False
2584
2585
2585 if self._showchannels:
2586 if self._showchannels:
2586 statthread = threading.Thread(target=stat, name="stat")
2587 statthread = threading.Thread(target=stat, name="stat")
2587 statthread.start()
2588 statthread.start()
2588
2589
2589 try:
2590 try:
2590 while tests or running:
2591 while tests or running:
2591 if not done.empty() or running == self._jobs or not tests:
2592 if not done.empty() or running == self._jobs or not tests:
2592 try:
2593 try:
2593 done.get(True, 1)
2594 done.get(True, 1)
2594 running -= 1
2595 running -= 1
2595 if result and result.shouldStop:
2596 if result and result.shouldStop:
2596 stoppedearly = True
2597 stoppedearly = True
2597 break
2598 break
2598 except queue.Empty:
2599 except queue.Empty:
2599 continue
2600 continue
2600 if tests and not running == self._jobs:
2601 if tests and not running == self._jobs:
2601 test = tests.pop(0)
2602 test = tests.pop(0)
2602 if self._loop:
2603 if self._loop:
2603 if getattr(test, 'should_reload', False):
2604 if getattr(test, 'should_reload', False):
2604 num_tests[0] += 1
2605 num_tests[0] += 1
2605 tests.append(self._loadtest(test, num_tests[0]))
2606 tests.append(self._loadtest(test, num_tests[0]))
2606 else:
2607 else:
2607 tests.append(test)
2608 tests.append(test)
2608 if self._jobs == 1:
2609 if self._jobs == 1:
2609 job(test, result)
2610 job(test, result)
2610 else:
2611 else:
2611 t = threading.Thread(
2612 t = threading.Thread(
2612 target=job, name=test.name, args=(test, result)
2613 target=job, name=test.name, args=(test, result)
2613 )
2614 )
2614 t.start()
2615 t.start()
2615 running += 1
2616 running += 1
2616
2617
2617 # If we stop early we still need to wait on started tests to
2618 # If we stop early we still need to wait on started tests to
2618 # finish. Otherwise, there is a race between the test completing
2619 # finish. Otherwise, there is a race between the test completing
2619 # and the test's cleanup code running. This could result in the
2620 # and the test's cleanup code running. This could result in the
2620 # test reporting incorrect.
2621 # test reporting incorrect.
2621 if stoppedearly:
2622 if stoppedearly:
2622 while running:
2623 while running:
2623 try:
2624 try:
2624 done.get(True, 1)
2625 done.get(True, 1)
2625 running -= 1
2626 running -= 1
2626 except queue.Empty:
2627 except queue.Empty:
2627 continue
2628 continue
2628 except KeyboardInterrupt:
2629 except KeyboardInterrupt:
2629 for test in runtests:
2630 for test in runtests:
2630 test.abort()
2631 test.abort()
2631
2632
2632 channels = []
2633 channels = []
2633
2634
2634 return result
2635 return result
2635
2636
2636
2637
2637 # Save the most recent 5 wall-clock runtimes of each test to a
2638 # Save the most recent 5 wall-clock runtimes of each test to a
2638 # human-readable text file named .testtimes. Tests are sorted
2639 # human-readable text file named .testtimes. Tests are sorted
2639 # alphabetically, while times for each test are listed from oldest to
2640 # alphabetically, while times for each test are listed from oldest to
2640 # newest.
2641 # newest.
2641
2642
2642
2643
2643 def loadtimes(outputdir):
2644 def loadtimes(outputdir):
2644 times = []
2645 times = []
2645 try:
2646 try:
2646 with open(os.path.join(outputdir, b'.testtimes')) as fp:
2647 with open(os.path.join(outputdir, b'.testtimes')) as fp:
2647 for line in fp:
2648 for line in fp:
2648 m = re.match('(.*?) ([0-9. ]+)', line)
2649 m = re.match('(.*?) ([0-9. ]+)', line)
2649 times.append(
2650 times.append(
2650 (m.group(1), [float(t) for t in m.group(2).split()])
2651 (m.group(1), [float(t) for t in m.group(2).split()])
2651 )
2652 )
2652 except FileNotFoundError:
2653 except FileNotFoundError:
2653 pass
2654 pass
2654 return times
2655 return times
2655
2656
2656
2657
2657 def savetimes(outputdir, result):
2658 def savetimes(outputdir, result):
2658 saved = dict(loadtimes(outputdir))
2659 saved = dict(loadtimes(outputdir))
2659 maxruns = 5
2660 maxruns = 5
2660 skipped = {str(t[0]) for t in result.skipped}
2661 skipped = {str(t[0]) for t in result.skipped}
2661 for tdata in result.times:
2662 for tdata in result.times:
2662 test, real = tdata[0], tdata[3]
2663 test, real = tdata[0], tdata[3]
2663 if test not in skipped:
2664 if test not in skipped:
2664 ts = saved.setdefault(test, [])
2665 ts = saved.setdefault(test, [])
2665 ts.append(real)
2666 ts.append(real)
2666 ts[:] = ts[-maxruns:]
2667 ts[:] = ts[-maxruns:]
2667
2668
2668 fd, tmpname = tempfile.mkstemp(
2669 fd, tmpname = tempfile.mkstemp(
2669 prefix=b'.testtimes', dir=outputdir, text=True
2670 prefix=b'.testtimes', dir=outputdir, text=True
2670 )
2671 )
2671 with os.fdopen(fd, 'w') as fp:
2672 with os.fdopen(fd, 'w') as fp:
2672 for name, ts in sorted(saved.items()):
2673 for name, ts in sorted(saved.items()):
2673 fp.write('%s %s\n' % (name, ' '.join(['%.3f' % (t,) for t in ts])))
2674 fp.write('%s %s\n' % (name, ' '.join(['%.3f' % (t,) for t in ts])))
2674 timepath = os.path.join(outputdir, b'.testtimes')
2675 timepath = os.path.join(outputdir, b'.testtimes')
2675 try:
2676 try:
2676 os.unlink(timepath)
2677 os.unlink(timepath)
2677 except OSError:
2678 except OSError:
2678 pass
2679 pass
2679 try:
2680 try:
2680 os.rename(tmpname, timepath)
2681 os.rename(tmpname, timepath)
2681 except OSError:
2682 except OSError:
2682 pass
2683 pass
2683
2684
2684
2685
2685 class TextTestRunner(unittest.TextTestRunner):
2686 class TextTestRunner(unittest.TextTestRunner):
2686 """Custom unittest test runner that uses appropriate settings."""
2687 """Custom unittest test runner that uses appropriate settings."""
2687
2688
2688 def __init__(self, runner, *args, **kwargs):
2689 def __init__(self, runner, *args, **kwargs):
2689 super(TextTestRunner, self).__init__(*args, **kwargs)
2690 super(TextTestRunner, self).__init__(*args, **kwargs)
2690
2691
2691 self._runner = runner
2692 self._runner = runner
2692
2693
2693 self._result = getTestResult()(
2694 self._result = getTestResult()(
2694 self._runner.options, self.stream, self.descriptions, self.verbosity
2695 self._runner.options, self.stream, self.descriptions, self.verbosity
2695 )
2696 )
2696
2697
2697 def listtests(self, test):
2698 def listtests(self, test):
2698 test = sorted(test, key=lambda t: t.name)
2699 test = sorted(test, key=lambda t: t.name)
2699
2700
2700 self._result.onStart(test)
2701 self._result.onStart(test)
2701
2702
2702 for t in test:
2703 for t in test:
2703 print(t.name)
2704 print(t.name)
2704 self._result.addSuccess(t)
2705 self._result.addSuccess(t)
2705
2706
2706 if self._runner.options.xunit:
2707 if self._runner.options.xunit:
2707 with open(self._runner.options.xunit, "wb") as xuf:
2708 with open(self._runner.options.xunit, "wb") as xuf:
2708 self._writexunit(self._result, xuf)
2709 self._writexunit(self._result, xuf)
2709
2710
2710 if self._runner.options.json:
2711 if self._runner.options.json:
2711 jsonpath = os.path.join(self._runner._outputdir, b'report.json')
2712 jsonpath = os.path.join(self._runner._outputdir, b'report.json')
2712 with open(jsonpath, 'w') as fp:
2713 with open(jsonpath, 'w') as fp:
2713 self._writejson(self._result, fp)
2714 self._writejson(self._result, fp)
2714
2715
2715 return self._result
2716 return self._result
2716
2717
2717 def run(self, test):
2718 def run(self, test):
2718 self._result.onStart(test)
2719 self._result.onStart(test)
2719 test(self._result)
2720 test(self._result)
2720
2721
2721 failed = len(self._result.failures)
2722 failed = len(self._result.failures)
2722 skipped = len(self._result.skipped)
2723 skipped = len(self._result.skipped)
2723 ignored = len(self._result.ignored)
2724 ignored = len(self._result.ignored)
2724
2725
2725 with iolock:
2726 with iolock:
2726 self.stream.writeln('')
2727 self.stream.writeln('')
2727
2728
2728 if not self._runner.options.noskips:
2729 if not self._runner.options.noskips:
2729 for test, msg in sorted(
2730 for test, msg in sorted(
2730 self._result.skipped, key=lambda s: s[0].name
2731 self._result.skipped, key=lambda s: s[0].name
2731 ):
2732 ):
2732 formatted = 'Skipped %s: %s\n' % (test.name, msg)
2733 formatted = 'Skipped %s: %s\n' % (test.name, msg)
2733 msg = highlightmsg(formatted, self._result.color)
2734 msg = highlightmsg(formatted, self._result.color)
2734 self.stream.write(msg)
2735 self.stream.write(msg)
2735 for test, msg in sorted(
2736 for test, msg in sorted(
2736 self._result.failures, key=lambda f: f[0].name
2737 self._result.failures, key=lambda f: f[0].name
2737 ):
2738 ):
2738 formatted = 'Failed %s: %s\n' % (test.name, msg)
2739 formatted = 'Failed %s: %s\n' % (test.name, msg)
2739 self.stream.write(highlightmsg(formatted, self._result.color))
2740 self.stream.write(highlightmsg(formatted, self._result.color))
2740 for test, msg in sorted(
2741 for test, msg in sorted(
2741 self._result.errors, key=lambda e: e[0].name
2742 self._result.errors, key=lambda e: e[0].name
2742 ):
2743 ):
2743 self.stream.writeln('Errored %s: %s' % (test.name, msg))
2744 self.stream.writeln('Errored %s: %s' % (test.name, msg))
2744
2745
2745 if self._runner.options.xunit:
2746 if self._runner.options.xunit:
2746 with open(self._runner.options.xunit, "wb") as xuf:
2747 with open(self._runner.options.xunit, "wb") as xuf:
2747 self._writexunit(self._result, xuf)
2748 self._writexunit(self._result, xuf)
2748
2749
2749 if self._runner.options.json:
2750 if self._runner.options.json:
2750 jsonpath = os.path.join(self._runner._outputdir, b'report.json')
2751 jsonpath = os.path.join(self._runner._outputdir, b'report.json')
2751 with open(jsonpath, 'w') as fp:
2752 with open(jsonpath, 'w') as fp:
2752 self._writejson(self._result, fp)
2753 self._writejson(self._result, fp)
2753
2754
2754 self._runner._checkhglib('Tested')
2755 self._runner._checkhglib('Tested')
2755
2756
2756 savetimes(self._runner._outputdir, self._result)
2757 savetimes(self._runner._outputdir, self._result)
2757
2758
2758 if failed and self._runner.options.known_good_rev:
2759 if failed and self._runner.options.known_good_rev:
2759 self._bisecttests(t for t, m in self._result.failures)
2760 self._bisecttests(t for t, m in self._result.failures)
2760 self.stream.writeln(
2761 self.stream.writeln(
2761 '# Ran %d tests, %d skipped, %d failed.'
2762 '# Ran %d tests, %d skipped, %d failed.'
2762 % (self._result.testsRun, skipped + ignored, failed)
2763 % (self._result.testsRun, skipped + ignored, failed)
2763 )
2764 )
2764 if failed:
2765 if failed:
2765 self.stream.writeln(
2766 self.stream.writeln(
2766 'python hash seed: %s' % os.environ['PYTHONHASHSEED']
2767 'python hash seed: %s' % os.environ['PYTHONHASHSEED']
2767 )
2768 )
2768 if self._runner.options.time:
2769 if self._runner.options.time:
2769 self.printtimes(self._result.times)
2770 self.printtimes(self._result.times)
2770
2771
2771 if self._runner.options.exceptions:
2772 if self._runner.options.exceptions:
2772 exceptions = aggregateexceptions(
2773 exceptions = aggregateexceptions(
2773 os.path.join(self._runner._outputdir, b'exceptions')
2774 os.path.join(self._runner._outputdir, b'exceptions')
2774 )
2775 )
2775
2776
2776 self.stream.writeln('Exceptions Report:')
2777 self.stream.writeln('Exceptions Report:')
2777 self.stream.writeln(
2778 self.stream.writeln(
2778 '%d total from %d frames'
2779 '%d total from %d frames'
2779 % (exceptions['total'], len(exceptions['exceptioncounts']))
2780 % (exceptions['total'], len(exceptions['exceptioncounts']))
2780 )
2781 )
2781 combined = exceptions['combined']
2782 combined = exceptions['combined']
2782 for key in sorted(combined, key=combined.get, reverse=True):
2783 for key in sorted(combined, key=combined.get, reverse=True):
2783 frame, line, exc = key
2784 frame, line, exc = key
2784 totalcount, testcount, leastcount, leasttest = combined[key]
2785 totalcount, testcount, leastcount, leasttest = combined[key]
2785
2786
2786 self.stream.writeln(
2787 self.stream.writeln(
2787 '%d (%d tests)\t%s: %s (%s - %d total)'
2788 '%d (%d tests)\t%s: %s (%s - %d total)'
2788 % (
2789 % (
2789 totalcount,
2790 totalcount,
2790 testcount,
2791 testcount,
2791 frame,
2792 frame,
2792 exc,
2793 exc,
2793 leasttest,
2794 leasttest,
2794 leastcount,
2795 leastcount,
2795 )
2796 )
2796 )
2797 )
2797
2798
2798 self.stream.flush()
2799 self.stream.flush()
2799
2800
2800 return self._result
2801 return self._result
2801
2802
2802 def _bisecttests(self, tests):
2803 def _bisecttests(self, tests):
2803 bisectcmd = ['hg', 'bisect']
2804 bisectcmd = ['hg', 'bisect']
2804 bisectrepo = self._runner.options.bisect_repo
2805 bisectrepo = self._runner.options.bisect_repo
2805 if bisectrepo:
2806 if bisectrepo:
2806 bisectcmd.extend(['-R', os.path.abspath(bisectrepo)])
2807 bisectcmd.extend(['-R', os.path.abspath(bisectrepo)])
2807
2808
2808 def pread(args):
2809 def pread(args):
2809 env = os.environ.copy()
2810 env = os.environ.copy()
2810 env['HGPLAIN'] = '1'
2811 env['HGPLAIN'] = '1'
2811 p = subprocess.Popen(
2812 p = subprocess.Popen(
2812 args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, env=env
2813 args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, env=env
2813 )
2814 )
2814 data = p.stdout.read()
2815 data = p.stdout.read()
2815 p.wait()
2816 p.wait()
2816 return data
2817 return data
2817
2818
2818 for test in tests:
2819 for test in tests:
2819 pread(bisectcmd + ['--reset']),
2820 pread(bisectcmd + ['--reset']),
2820 pread(bisectcmd + ['--bad', '.'])
2821 pread(bisectcmd + ['--bad', '.'])
2821 pread(bisectcmd + ['--good', self._runner.options.known_good_rev])
2822 pread(bisectcmd + ['--good', self._runner.options.known_good_rev])
2822 # TODO: we probably need to forward more options
2823 # TODO: we probably need to forward more options
2823 # that alter hg's behavior inside the tests.
2824 # that alter hg's behavior inside the tests.
2824 opts = ''
2825 opts = ''
2825 withhg = self._runner.options.with_hg
2826 withhg = self._runner.options.with_hg
2826 if withhg:
2827 if withhg:
2827 opts += ' --with-hg=%s ' % shellquote(_bytes2sys(withhg))
2828 opts += ' --with-hg=%s ' % shellquote(_bytes2sys(withhg))
2828 rtc = '%s %s %s %s' % (sysexecutable, sys.argv[0], opts, test)
2829 rtc = '%s %s %s %s' % (sysexecutable, sys.argv[0], opts, test)
2829 data = pread(bisectcmd + ['--command', rtc])
2830 data = pread(bisectcmd + ['--command', rtc])
2830 m = re.search(
2831 m = re.search(
2831 (
2832 (
2832 br'\nThe first (?P<goodbad>bad|good) revision '
2833 br'\nThe first (?P<goodbad>bad|good) revision '
2833 br'is:\nchangeset: +\d+:(?P<node>[a-f0-9]+)\n.*\n'
2834 br'is:\nchangeset: +\d+:(?P<node>[a-f0-9]+)\n.*\n'
2834 br'summary: +(?P<summary>[^\n]+)\n'
2835 br'summary: +(?P<summary>[^\n]+)\n'
2835 ),
2836 ),
2836 data,
2837 data,
2837 (re.MULTILINE | re.DOTALL),
2838 (re.MULTILINE | re.DOTALL),
2838 )
2839 )
2839 if m is None:
2840 if m is None:
2840 self.stream.writeln(
2841 self.stream.writeln(
2841 'Failed to identify failure point for %s' % test
2842 'Failed to identify failure point for %s' % test
2842 )
2843 )
2843 continue
2844 continue
2844 dat = m.groupdict()
2845 dat = m.groupdict()
2845 verb = 'broken' if dat['goodbad'] == b'bad' else 'fixed'
2846 verb = 'broken' if dat['goodbad'] == b'bad' else 'fixed'
2846 self.stream.writeln(
2847 self.stream.writeln(
2847 '%s %s by %s (%s)'
2848 '%s %s by %s (%s)'
2848 % (
2849 % (
2849 test,
2850 test,
2850 verb,
2851 verb,
2851 dat['node'].decode('ascii'),
2852 dat['node'].decode('ascii'),
2852 dat['summary'].decode('utf8', 'ignore'),
2853 dat['summary'].decode('utf8', 'ignore'),
2853 )
2854 )
2854 )
2855 )
2855
2856
2856 def printtimes(self, times):
2857 def printtimes(self, times):
2857 # iolock held by run
2858 # iolock held by run
2858 self.stream.writeln('# Producing time report')
2859 self.stream.writeln('# Producing time report')
2859 times.sort(key=lambda t: (t[3]))
2860 times.sort(key=lambda t: (t[3]))
2860 cols = '%7.3f %7.3f %7.3f %7.3f %7.3f %s'
2861 cols = '%7.3f %7.3f %7.3f %7.3f %7.3f %s'
2861 self.stream.writeln(
2862 self.stream.writeln(
2862 '%-7s %-7s %-7s %-7s %-7s %s'
2863 '%-7s %-7s %-7s %-7s %-7s %s'
2863 % ('start', 'end', 'cuser', 'csys', 'real', 'Test')
2864 % ('start', 'end', 'cuser', 'csys', 'real', 'Test')
2864 )
2865 )
2865 for tdata in times:
2866 for tdata in times:
2866 test = tdata[0]
2867 test = tdata[0]
2867 cuser, csys, real, start, end = tdata[1:6]
2868 cuser, csys, real, start, end = tdata[1:6]
2868 self.stream.writeln(cols % (start, end, cuser, csys, real, test))
2869 self.stream.writeln(cols % (start, end, cuser, csys, real, test))
2869
2870
2870 @staticmethod
2871 @staticmethod
2871 def _writexunit(result, outf):
2872 def _writexunit(result, outf):
2872 # See http://llg.cubic.org/docs/junit/ for a reference.
2873 # See http://llg.cubic.org/docs/junit/ for a reference.
2873 timesd = {t[0]: t[3] for t in result.times}
2874 timesd = {t[0]: t[3] for t in result.times}
2874 doc = minidom.Document()
2875 doc = minidom.Document()
2875 s = doc.createElement('testsuite')
2876 s = doc.createElement('testsuite')
2876 s.setAttribute('errors', "0") # TODO
2877 s.setAttribute('errors', "0") # TODO
2877 s.setAttribute('failures', str(len(result.failures)))
2878 s.setAttribute('failures', str(len(result.failures)))
2878 s.setAttribute('name', 'run-tests')
2879 s.setAttribute('name', 'run-tests')
2879 s.setAttribute(
2880 s.setAttribute(
2880 'skipped', str(len(result.skipped) + len(result.ignored))
2881 'skipped', str(len(result.skipped) + len(result.ignored))
2881 )
2882 )
2882 s.setAttribute('tests', str(result.testsRun))
2883 s.setAttribute('tests', str(result.testsRun))
2883 doc.appendChild(s)
2884 doc.appendChild(s)
2884 for tc in result.successes:
2885 for tc in result.successes:
2885 t = doc.createElement('testcase')
2886 t = doc.createElement('testcase')
2886 t.setAttribute('name', tc.name)
2887 t.setAttribute('name', tc.name)
2887 tctime = timesd.get(tc.name)
2888 tctime = timesd.get(tc.name)
2888 if tctime is not None:
2889 if tctime is not None:
2889 t.setAttribute('time', '%.3f' % tctime)
2890 t.setAttribute('time', '%.3f' % tctime)
2890 s.appendChild(t)
2891 s.appendChild(t)
2891 for tc, err in sorted(result.faildata.items()):
2892 for tc, err in sorted(result.faildata.items()):
2892 t = doc.createElement('testcase')
2893 t = doc.createElement('testcase')
2893 t.setAttribute('name', tc)
2894 t.setAttribute('name', tc)
2894 tctime = timesd.get(tc)
2895 tctime = timesd.get(tc)
2895 if tctime is not None:
2896 if tctime is not None:
2896 t.setAttribute('time', '%.3f' % tctime)
2897 t.setAttribute('time', '%.3f' % tctime)
2897 # createCDATASection expects a unicode or it will
2898 # createCDATASection expects a unicode or it will
2898 # convert using default conversion rules, which will
2899 # convert using default conversion rules, which will
2899 # fail if string isn't ASCII.
2900 # fail if string isn't ASCII.
2900 err = cdatasafe(err).decode('utf-8', 'replace')
2901 err = cdatasafe(err).decode('utf-8', 'replace')
2901 cd = doc.createCDATASection(err)
2902 cd = doc.createCDATASection(err)
2902 # Use 'failure' here instead of 'error' to match errors = 0,
2903 # Use 'failure' here instead of 'error' to match errors = 0,
2903 # failures = len(result.failures) in the testsuite element.
2904 # failures = len(result.failures) in the testsuite element.
2904 failelem = doc.createElement('failure')
2905 failelem = doc.createElement('failure')
2905 failelem.setAttribute('message', 'output changed')
2906 failelem.setAttribute('message', 'output changed')
2906 failelem.setAttribute('type', 'output-mismatch')
2907 failelem.setAttribute('type', 'output-mismatch')
2907 failelem.appendChild(cd)
2908 failelem.appendChild(cd)
2908 t.appendChild(failelem)
2909 t.appendChild(failelem)
2909 s.appendChild(t)
2910 s.appendChild(t)
2910 for tc, message in result.skipped:
2911 for tc, message in result.skipped:
2911 # According to the schema, 'skipped' has no attributes. So store
2912 # According to the schema, 'skipped' has no attributes. So store
2912 # the skip message as a text node instead.
2913 # the skip message as a text node instead.
2913 t = doc.createElement('testcase')
2914 t = doc.createElement('testcase')
2914 t.setAttribute('name', tc.name)
2915 t.setAttribute('name', tc.name)
2915 binmessage = message.encode('utf-8')
2916 binmessage = message.encode('utf-8')
2916 message = cdatasafe(binmessage).decode('utf-8', 'replace')
2917 message = cdatasafe(binmessage).decode('utf-8', 'replace')
2917 cd = doc.createCDATASection(message)
2918 cd = doc.createCDATASection(message)
2918 skipelem = doc.createElement('skipped')
2919 skipelem = doc.createElement('skipped')
2919 skipelem.appendChild(cd)
2920 skipelem.appendChild(cd)
2920 t.appendChild(skipelem)
2921 t.appendChild(skipelem)
2921 s.appendChild(t)
2922 s.appendChild(t)
2922 outf.write(doc.toprettyxml(indent=' ', encoding='utf-8'))
2923 outf.write(doc.toprettyxml(indent=' ', encoding='utf-8'))
2923
2924
2924 @staticmethod
2925 @staticmethod
2925 def _writejson(result, outf):
2926 def _writejson(result, outf):
2926 timesd = {}
2927 timesd = {}
2927 for tdata in result.times:
2928 for tdata in result.times:
2928 test = tdata[0]
2929 test = tdata[0]
2929 timesd[test] = tdata[1:]
2930 timesd[test] = tdata[1:]
2930
2931
2931 outcome = {}
2932 outcome = {}
2932 groups = [
2933 groups = [
2933 ('success', ((tc, None) for tc in result.successes)),
2934 ('success', ((tc, None) for tc in result.successes)),
2934 ('failure', result.failures),
2935 ('failure', result.failures),
2935 ('skip', result.skipped),
2936 ('skip', result.skipped),
2936 ]
2937 ]
2937 for res, testcases in groups:
2938 for res, testcases in groups:
2938 for tc, __ in testcases:
2939 for tc, __ in testcases:
2939 if tc.name in timesd:
2940 if tc.name in timesd:
2940 diff = result.faildata.get(tc.name, b'')
2941 diff = result.faildata.get(tc.name, b'')
2941 try:
2942 try:
2942 diff = diff.decode('unicode_escape')
2943 diff = diff.decode('unicode_escape')
2943 except UnicodeDecodeError as e:
2944 except UnicodeDecodeError as e:
2944 diff = '%r decoding diff, sorry' % e
2945 diff = '%r decoding diff, sorry' % e
2945 tres = {
2946 tres = {
2946 'result': res,
2947 'result': res,
2947 'time': ('%0.3f' % timesd[tc.name][2]),
2948 'time': ('%0.3f' % timesd[tc.name][2]),
2948 'cuser': ('%0.3f' % timesd[tc.name][0]),
2949 'cuser': ('%0.3f' % timesd[tc.name][0]),
2949 'csys': ('%0.3f' % timesd[tc.name][1]),
2950 'csys': ('%0.3f' % timesd[tc.name][1]),
2950 'start': ('%0.3f' % timesd[tc.name][3]),
2951 'start': ('%0.3f' % timesd[tc.name][3]),
2951 'end': ('%0.3f' % timesd[tc.name][4]),
2952 'end': ('%0.3f' % timesd[tc.name][4]),
2952 'diff': diff,
2953 'diff': diff,
2953 }
2954 }
2954 else:
2955 else:
2955 # blacklisted test
2956 # blacklisted test
2956 tres = {'result': res}
2957 tres = {'result': res}
2957
2958
2958 outcome[tc.name] = tres
2959 outcome[tc.name] = tres
2959 jsonout = json.dumps(
2960 jsonout = json.dumps(
2960 outcome, sort_keys=True, indent=4, separators=(',', ': ')
2961 outcome, sort_keys=True, indent=4, separators=(',', ': ')
2961 )
2962 )
2962 outf.writelines(("testreport =", jsonout))
2963 outf.writelines(("testreport =", jsonout))
2963
2964
2964
2965
2965 def sorttests(testdescs, previoustimes, shuffle=False):
2966 def sorttests(testdescs, previoustimes, shuffle=False):
2966 """Do an in-place sort of tests."""
2967 """Do an in-place sort of tests."""
2967 if shuffle:
2968 if shuffle:
2968 random.shuffle(testdescs)
2969 random.shuffle(testdescs)
2969 return
2970 return
2970
2971
2971 if previoustimes:
2972 if previoustimes:
2972
2973
2973 def sortkey(f):
2974 def sortkey(f):
2974 f = f['path']
2975 f = f['path']
2975 if f in previoustimes:
2976 if f in previoustimes:
2976 # Use most recent time as estimate
2977 # Use most recent time as estimate
2977 return -(previoustimes[f][-1])
2978 return -(previoustimes[f][-1])
2978 else:
2979 else:
2979 # Default to a rather arbitrary value of 1 second for new tests
2980 # Default to a rather arbitrary value of 1 second for new tests
2980 return -1.0
2981 return -1.0
2981
2982
2982 else:
2983 else:
2983 # keywords for slow tests
2984 # keywords for slow tests
2984 slow = {
2985 slow = {
2985 b'svn': 10,
2986 b'svn': 10,
2986 b'cvs': 10,
2987 b'cvs': 10,
2987 b'hghave': 10,
2988 b'hghave': 10,
2988 b'largefiles-update': 10,
2989 b'largefiles-update': 10,
2989 b'run-tests': 10,
2990 b'run-tests': 10,
2990 b'corruption': 10,
2991 b'corruption': 10,
2991 b'race': 10,
2992 b'race': 10,
2992 b'i18n': 10,
2993 b'i18n': 10,
2993 b'check': 100,
2994 b'check': 100,
2994 b'gendoc': 100,
2995 b'gendoc': 100,
2995 b'contrib-perf': 200,
2996 b'contrib-perf': 200,
2996 b'merge-combination': 100,
2997 b'merge-combination': 100,
2997 }
2998 }
2998 perf = {}
2999 perf = {}
2999
3000
3000 def sortkey(f):
3001 def sortkey(f):
3001 # run largest tests first, as they tend to take the longest
3002 # run largest tests first, as they tend to take the longest
3002 f = f['path']
3003 f = f['path']
3003 try:
3004 try:
3004 return perf[f]
3005 return perf[f]
3005 except KeyError:
3006 except KeyError:
3006 try:
3007 try:
3007 val = -os.stat(f).st_size
3008 val = -os.stat(f).st_size
3008 except FileNotFoundError:
3009 except FileNotFoundError:
3009 perf[f] = -1e9 # file does not exist, tell early
3010 perf[f] = -1e9 # file does not exist, tell early
3010 return -1e9
3011 return -1e9
3011 for kw, mul in slow.items():
3012 for kw, mul in slow.items():
3012 if kw in f:
3013 if kw in f:
3013 val *= mul
3014 val *= mul
3014 if f.endswith(b'.py'):
3015 if f.endswith(b'.py'):
3015 val /= 10.0
3016 val /= 10.0
3016 perf[f] = val / 1000.0
3017 perf[f] = val / 1000.0
3017 return perf[f]
3018 return perf[f]
3018
3019
3019 testdescs.sort(key=sortkey)
3020 testdescs.sort(key=sortkey)
3020
3021
3021
3022
3022 class TestRunner:
3023 class TestRunner:
3023 """Holds context for executing tests.
3024 """Holds context for executing tests.
3024
3025
3025 Tests rely on a lot of state. This object holds it for them.
3026 Tests rely on a lot of state. This object holds it for them.
3026 """
3027 """
3027
3028
3028 # Programs required to run tests.
3029 # Programs required to run tests.
3029 REQUIREDTOOLS = [
3030 REQUIREDTOOLS = [
3030 b'diff',
3031 b'diff',
3031 b'grep',
3032 b'grep',
3032 b'unzip',
3033 b'unzip',
3033 b'gunzip',
3034 b'gunzip',
3034 b'bunzip2',
3035 b'bunzip2',
3035 b'sed',
3036 b'sed',
3036 ]
3037 ]
3037
3038
3038 # Maps file extensions to test class.
3039 # Maps file extensions to test class.
3039 TESTTYPES = [
3040 TESTTYPES = [
3040 (b'.py', PythonTest),
3041 (b'.py', PythonTest),
3041 (b'.t', TTest),
3042 (b'.t', TTest),
3042 ]
3043 ]
3043
3044
3044 def __init__(self):
3045 def __init__(self):
3045 self.options = None
3046 self.options = None
3046 self._hgroot = None
3047 self._hgroot = None
3047 self._testdir = None
3048 self._testdir = None
3048 self._outputdir = None
3049 self._outputdir = None
3049 self._hgtmp = None
3050 self._hgtmp = None
3050 self._installdir = None
3051 self._installdir = None
3051 self._bindir = None
3052 self._bindir = None
3052 # a place for run-tests.py to generate executable it needs
3053 # a place for run-tests.py to generate executable it needs
3053 self._custom_bin_dir = None
3054 self._custom_bin_dir = None
3054 self._pythondir = None
3055 self._pythondir = None
3055 # True if we had to infer the pythondir from --with-hg
3056 # True if we had to infer the pythondir from --with-hg
3056 self._pythondir_inferred = False
3057 self._pythondir_inferred = False
3057 self._coveragefile = None
3058 self._coveragefile = None
3058 self._createdfiles = []
3059 self._createdfiles = []
3059 self._hgcommand = None
3060 self._hgcommand = None
3060 self._hgpath = None
3061 self._hgpath = None
3061 self._portoffset = 0
3062 self._portoffset = 0
3062 self._ports = {}
3063 self._ports = {}
3063
3064
3064 def run(self, args, parser=None):
3065 def run(self, args, parser=None):
3065 """Run the test suite."""
3066 """Run the test suite."""
3066 oldmask = os.umask(0o22)
3067 oldmask = os.umask(0o22)
3067 try:
3068 try:
3068 parser = parser or getparser()
3069 parser = parser or getparser()
3069 options = parseargs(args, parser)
3070 options = parseargs(args, parser)
3070 tests = [_sys2bytes(a) for a in options.tests]
3071 tests = [_sys2bytes(a) for a in options.tests]
3071 if options.test_list is not None:
3072 if options.test_list is not None:
3072 for listfile in options.test_list:
3073 for listfile in options.test_list:
3073 with open(listfile, 'rb') as f:
3074 with open(listfile, 'rb') as f:
3074 tests.extend(t for t in f.read().splitlines() if t)
3075 tests.extend(t for t in f.read().splitlines() if t)
3075 self.options = options
3076 self.options = options
3076
3077
3077 self._checktools()
3078 self._checktools()
3078 testdescs = self.findtests(tests)
3079 testdescs = self.findtests(tests)
3079 if options.profile_runner:
3080 if options.profile_runner:
3080 import statprof
3081 import statprof
3081
3082
3082 statprof.start()
3083 statprof.start()
3083 result = self._run(testdescs)
3084 result = self._run(testdescs)
3084 if options.profile_runner:
3085 if options.profile_runner:
3085 statprof.stop()
3086 statprof.stop()
3086 statprof.display()
3087 statprof.display()
3087 return result
3088 return result
3088
3089
3089 finally:
3090 finally:
3090 os.umask(oldmask)
3091 os.umask(oldmask)
3091
3092
3092 def _run(self, testdescs):
3093 def _run(self, testdescs):
3093 testdir = getcwdb()
3094 testdir = getcwdb()
3094 # assume all tests in same folder for now
3095 # assume all tests in same folder for now
3095 if testdescs:
3096 if testdescs:
3096 pathname = os.path.dirname(testdescs[0]['path'])
3097 pathname = os.path.dirname(testdescs[0]['path'])
3097 if pathname:
3098 if pathname:
3098 testdir = os.path.join(testdir, pathname)
3099 testdir = os.path.join(testdir, pathname)
3099 self._testdir = osenvironb[b'TESTDIR'] = testdir
3100 self._testdir = osenvironb[b'TESTDIR'] = testdir
3100 osenvironb[b'TESTDIR_FORWARD_SLASH'] = osenvironb[b'TESTDIR'].replace(
3101 osenvironb[b'TESTDIR_FORWARD_SLASH'] = osenvironb[b'TESTDIR'].replace(
3101 os.sep.encode('ascii'), b'/'
3102 os.sep.encode('ascii'), b'/'
3102 )
3103 )
3103
3104
3104 if self.options.outputdir:
3105 if self.options.outputdir:
3105 self._outputdir = canonpath(_sys2bytes(self.options.outputdir))
3106 self._outputdir = canonpath(_sys2bytes(self.options.outputdir))
3106 else:
3107 else:
3107 self._outputdir = getcwdb()
3108 self._outputdir = getcwdb()
3108 if testdescs and pathname:
3109 if testdescs and pathname:
3109 self._outputdir = os.path.join(self._outputdir, pathname)
3110 self._outputdir = os.path.join(self._outputdir, pathname)
3110 previoustimes = {}
3111 previoustimes = {}
3111 if self.options.order_by_runtime:
3112 if self.options.order_by_runtime:
3112 previoustimes = dict(loadtimes(self._outputdir))
3113 previoustimes = dict(loadtimes(self._outputdir))
3113 sorttests(testdescs, previoustimes, shuffle=self.options.random)
3114 sorttests(testdescs, previoustimes, shuffle=self.options.random)
3114
3115
3115 if 'PYTHONHASHSEED' not in os.environ:
3116 if 'PYTHONHASHSEED' not in os.environ:
3116 # use a random python hash seed all the time
3117 # use a random python hash seed all the time
3117 # we do the randomness ourself to know what seed is used
3118 # we do the randomness ourself to know what seed is used
3118 os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
3119 os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
3119
3120
3120 # Rayon (Rust crate for multi-threading) will use all logical CPU cores
3121 # Rayon (Rust crate for multi-threading) will use all logical CPU cores
3121 # by default, causing thrashing on high-cpu-count systems.
3122 # by default, causing thrashing on high-cpu-count systems.
3122 # Setting its limit to 3 during tests should still let us uncover
3123 # Setting its limit to 3 during tests should still let us uncover
3123 # multi-threading bugs while keeping the thrashing reasonable.
3124 # multi-threading bugs while keeping the thrashing reasonable.
3124 os.environ.setdefault("RAYON_NUM_THREADS", "3")
3125 os.environ.setdefault("RAYON_NUM_THREADS", "3")
3125
3126
3126 if self.options.tmpdir:
3127 if self.options.tmpdir:
3127 self.options.keep_tmpdir = True
3128 self.options.keep_tmpdir = True
3128 tmpdir = _sys2bytes(self.options.tmpdir)
3129 tmpdir = _sys2bytes(self.options.tmpdir)
3129 if os.path.exists(tmpdir):
3130 if os.path.exists(tmpdir):
3130 # Meaning of tmpdir has changed since 1.3: we used to create
3131 # Meaning of tmpdir has changed since 1.3: we used to create
3131 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
3132 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
3132 # tmpdir already exists.
3133 # tmpdir already exists.
3133 print("error: temp dir %r already exists" % tmpdir)
3134 print("error: temp dir %r already exists" % tmpdir)
3134 return 1
3135 return 1
3135
3136
3136 os.makedirs(tmpdir)
3137 os.makedirs(tmpdir)
3137 else:
3138 else:
3138 d = None
3139 d = None
3139 if WINDOWS:
3140 if WINDOWS:
3140 # without this, we get the default temp dir location, but
3141 # without this, we get the default temp dir location, but
3141 # in all lowercase, which causes troubles with paths (issue3490)
3142 # in all lowercase, which causes troubles with paths (issue3490)
3142 d = osenvironb.get(b'TMP', None)
3143 d = osenvironb.get(b'TMP', None)
3143 tmpdir = tempfile.mkdtemp(b'', b'hgtests.', d)
3144 tmpdir = tempfile.mkdtemp(b'', b'hgtests.', d)
3144
3145
3145 self._hgtmp = osenvironb[b'HGTMP'] = os.path.realpath(tmpdir)
3146 self._hgtmp = osenvironb[b'HGTMP'] = os.path.realpath(tmpdir)
3146
3147
3147 self._custom_bin_dir = os.path.join(self._hgtmp, b'custom-bin')
3148 self._custom_bin_dir = os.path.join(self._hgtmp, b'custom-bin')
3148 os.makedirs(self._custom_bin_dir)
3149 os.makedirs(self._custom_bin_dir)
3149
3150
3150 # detect and enforce an alternative way to specify rust extension usage
3151 # detect and enforce an alternative way to specify rust extension usage
3151 if (
3152 if (
3152 not (self.options.pure or self.options.rust or self.options.no_rust)
3153 not (self.options.pure or self.options.rust or self.options.no_rust)
3153 and os.environ.get("HGWITHRUSTEXT") == "cpython"
3154 and os.environ.get("HGWITHRUSTEXT") == "cpython"
3154 ):
3155 ):
3155 self.options.rust = True
3156 self.options.rust = True
3156
3157
3157 if self.options.with_hg:
3158 if self.options.with_hg:
3158 self._installdir = None
3159 self._installdir = None
3159 whg = self.options.with_hg
3160 whg = self.options.with_hg
3160 self._bindir = os.path.dirname(os.path.realpath(whg))
3161 self._bindir = os.path.dirname(os.path.realpath(whg))
3161 assert isinstance(self._bindir, bytes)
3162 assert isinstance(self._bindir, bytes)
3162 self._hgcommand = os.path.basename(whg)
3163 self._hgcommand = os.path.basename(whg)
3163
3164
3164 normbin = os.path.normpath(os.path.abspath(whg))
3165 normbin = os.path.normpath(os.path.abspath(whg))
3165 normbin = normbin.replace(_sys2bytes(os.sep), b'/')
3166 normbin = normbin.replace(_sys2bytes(os.sep), b'/')
3166
3167
3167 # Other Python scripts in the test harness need to
3168 # Other Python scripts in the test harness need to
3168 # `import mercurial`. If `hg` is a Python script, we assume
3169 # `import mercurial`. If `hg` is a Python script, we assume
3169 # the Mercurial modules are relative to its path and tell the tests
3170 # the Mercurial modules are relative to its path and tell the tests
3170 # to load Python modules from its directory.
3171 # to load Python modules from its directory.
3171 with open(whg, 'rb') as fh:
3172 with open(whg, 'rb') as fh:
3172 initial = fh.read(1024)
3173 initial = fh.read(1024)
3173
3174
3174 if re.match(b'#!.*python', initial):
3175 if re.match(b'#!.*python', initial):
3175 self._pythondir = self._bindir
3176 self._pythondir = self._bindir
3176 # If it looks like our in-repo Rust binary, use the source root.
3177 # If it looks like our in-repo Rust binary, use the source root.
3177 # This is a bit hacky. But rhg is still not supported outside the
3178 # This is a bit hacky. But rhg is still not supported outside the
3178 # source directory. So until it is, do the simple thing.
3179 # source directory. So until it is, do the simple thing.
3179 elif re.search(b'/rust/target/[^/]+/hg', normbin):
3180 elif re.search(b'/rust/target/[^/]+/hg', normbin):
3180 self._pythondir = os.path.dirname(self._testdir)
3181 self._pythondir = os.path.dirname(self._testdir)
3181 # Fall back to the legacy behavior.
3182 # Fall back to the legacy behavior.
3182 else:
3183 else:
3183 self._pythondir = self._bindir
3184 self._pythondir = self._bindir
3184 self._pythondir_inferred = True
3185 self._pythondir_inferred = True
3185
3186
3186 else:
3187 else:
3187 self._installdir = os.path.join(self._hgtmp, b"install")
3188 self._installdir = os.path.join(self._hgtmp, b"install")
3188 self._bindir = os.path.join(self._installdir, b"bin")
3189 self._bindir = os.path.join(self._installdir, b"bin")
3189 self._hgcommand = b'hg'
3190 self._hgcommand = b'hg'
3190 self._pythondir = os.path.join(self._installdir, b"lib", b"python")
3191 self._pythondir = os.path.join(self._installdir, b"lib", b"python")
3191
3192
3192 # Force the use of hg.exe instead of relying on MSYS to recognize hg is
3193 # Force the use of hg.exe instead of relying on MSYS to recognize hg is
3193 # a python script and feed it to python.exe. Legacy stdio is force
3194 # a python script and feed it to python.exe. Legacy stdio is force
3194 # enabled by hg.exe, and this is a more realistic way to launch hg
3195 # enabled by hg.exe, and this is a more realistic way to launch hg
3195 # anyway.
3196 # anyway.
3196 if WINDOWS and not self._hgcommand.endswith(b'.exe'):
3197 if WINDOWS and not self._hgcommand.endswith(b'.exe'):
3197 self._hgcommand += b'.exe'
3198 self._hgcommand += b'.exe'
3198
3199
3199 real_hg = os.path.join(self._bindir, self._hgcommand)
3200 real_hg = os.path.join(self._bindir, self._hgcommand)
3200 osenvironb[b'HGTEST_REAL_HG'] = real_hg
3201 osenvironb[b'HGTEST_REAL_HG'] = real_hg
3201 # set CHGHG, then replace "hg" command by "chg"
3202 # set CHGHG, then replace "hg" command by "chg"
3202 chgbindir = self._bindir
3203 chgbindir = self._bindir
3203 if self.options.chg or self.options.with_chg:
3204 if self.options.chg or self.options.with_chg:
3204 osenvironb[b'CHG_INSTALLED_AS_HG'] = b'1'
3205 osenvironb[b'CHG_INSTALLED_AS_HG'] = b'1'
3205 osenvironb[b'CHGHG'] = real_hg
3206 osenvironb[b'CHGHG'] = real_hg
3206 else:
3207 else:
3207 # drop flag for hghave
3208 # drop flag for hghave
3208 osenvironb.pop(b'CHG_INSTALLED_AS_HG', None)
3209 osenvironb.pop(b'CHG_INSTALLED_AS_HG', None)
3209 if self.options.chg:
3210 if self.options.chg:
3210 self._hgcommand = b'chg'
3211 self._hgcommand = b'chg'
3211 elif self.options.with_chg:
3212 elif self.options.with_chg:
3212 chgbindir = os.path.dirname(os.path.realpath(self.options.with_chg))
3213 chgbindir = os.path.dirname(os.path.realpath(self.options.with_chg))
3213 self._hgcommand = os.path.basename(self.options.with_chg)
3214 self._hgcommand = os.path.basename(self.options.with_chg)
3214
3215
3215 # configure fallback and replace "hg" command by "rhg"
3216 # configure fallback and replace "hg" command by "rhg"
3216 rhgbindir = self._bindir
3217 rhgbindir = self._bindir
3217 if self.options.rhg or self.options.with_rhg:
3218 if self.options.rhg or self.options.with_rhg:
3218 # Affects hghave.py
3219 # Affects hghave.py
3219 osenvironb[b'RHG_INSTALLED_AS_HG'] = b'1'
3220 osenvironb[b'RHG_INSTALLED_AS_HG'] = b'1'
3220 # Affects configuration. Alternatives would be setting configuration through
3221 # Affects configuration. Alternatives would be setting configuration through
3221 # `$HGRCPATH` but some tests override that, or changing `_hgcommand` to include
3222 # `$HGRCPATH` but some tests override that, or changing `_hgcommand` to include
3222 # `--config` but that disrupts tests that print command lines and check expected
3223 # `--config` but that disrupts tests that print command lines and check expected
3223 # output.
3224 # output.
3224 osenvironb[b'RHG_ON_UNSUPPORTED'] = b'fallback'
3225 osenvironb[b'RHG_ON_UNSUPPORTED'] = b'fallback'
3225 osenvironb[b'RHG_FALLBACK_EXECUTABLE'] = real_hg
3226 osenvironb[b'RHG_FALLBACK_EXECUTABLE'] = real_hg
3226 else:
3227 else:
3227 # drop flag for hghave
3228 # drop flag for hghave
3228 osenvironb.pop(b'RHG_INSTALLED_AS_HG', None)
3229 osenvironb.pop(b'RHG_INSTALLED_AS_HG', None)
3229 if self.options.rhg:
3230 if self.options.rhg:
3230 self._hgcommand = b'rhg'
3231 self._hgcommand = b'rhg'
3231 elif self.options.with_rhg:
3232 elif self.options.with_rhg:
3232 rhgbindir = os.path.dirname(os.path.realpath(self.options.with_rhg))
3233 rhgbindir = os.path.dirname(os.path.realpath(self.options.with_rhg))
3233 self._hgcommand = os.path.basename(self.options.with_rhg)
3234 self._hgcommand = os.path.basename(self.options.with_rhg)
3234
3235
3235 if self.options.pyoxidized:
3236 if self.options.pyoxidized:
3236 testdir = os.path.dirname(_sys2bytes(canonpath(sys.argv[0])))
3237 testdir = os.path.dirname(_sys2bytes(canonpath(sys.argv[0])))
3237 reporootdir = os.path.dirname(testdir)
3238 reporootdir = os.path.dirname(testdir)
3238 # XXX we should ideally install stuff instead of using the local build
3239 # XXX we should ideally install stuff instead of using the local build
3239
3240
3240 exe = b'hg'
3241 exe = b'hg'
3241 triple = b''
3242 triple = b''
3242
3243
3243 if WINDOWS:
3244 if WINDOWS:
3244 triple = b'x86_64-pc-windows-msvc'
3245 triple = b'x86_64-pc-windows-msvc'
3245 exe = b'hg.exe'
3246 exe = b'hg.exe'
3246 elif MACOS:
3247 elif MACOS:
3247 # TODO: support Apple silicon too
3248 # TODO: support Apple silicon too
3248 triple = b'x86_64-apple-darwin'
3249 triple = b'x86_64-apple-darwin'
3249
3250
3250 bin_path = b'build/pyoxidizer/%s/release/app/%s' % (triple, exe)
3251 bin_path = b'build/pyoxidizer/%s/release/app/%s' % (triple, exe)
3251 full_path = os.path.join(reporootdir, bin_path)
3252 full_path = os.path.join(reporootdir, bin_path)
3252 self._hgcommand = full_path
3253 self._hgcommand = full_path
3253 # Affects hghave.py
3254 # Affects hghave.py
3254 osenvironb[b'PYOXIDIZED_INSTALLED_AS_HG'] = b'1'
3255 osenvironb[b'PYOXIDIZED_INSTALLED_AS_HG'] = b'1'
3255 else:
3256 else:
3256 osenvironb.pop(b'PYOXIDIZED_INSTALLED_AS_HG', None)
3257 osenvironb.pop(b'PYOXIDIZED_INSTALLED_AS_HG', None)
3257
3258
3258 osenvironb[b"BINDIR"] = self._bindir
3259 osenvironb[b"BINDIR"] = self._bindir
3259 osenvironb[b"PYTHON"] = PYTHON
3260 osenvironb[b"PYTHON"] = PYTHON
3260
3261
3261 fileb = _sys2bytes(__file__)
3262 fileb = _sys2bytes(__file__)
3262 runtestdir = os.path.abspath(os.path.dirname(fileb))
3263 runtestdir = os.path.abspath(os.path.dirname(fileb))
3263 osenvironb[b'RUNTESTDIR'] = runtestdir
3264 osenvironb[b'RUNTESTDIR'] = runtestdir
3264 osenvironb[b'RUNTESTDIR_FORWARD_SLASH'] = runtestdir.replace(
3265 osenvironb[b'RUNTESTDIR_FORWARD_SLASH'] = runtestdir.replace(
3265 os.sep.encode('ascii'), b'/'
3266 os.sep.encode('ascii'), b'/'
3266 )
3267 )
3267 sepb = _sys2bytes(os.pathsep)
3268 sepb = _sys2bytes(os.pathsep)
3268 path = [self._bindir, runtestdir] + osenvironb[b"PATH"].split(sepb)
3269 path = [self._bindir, runtestdir] + osenvironb[b"PATH"].split(sepb)
3269 if os.path.islink(__file__):
3270 if os.path.islink(__file__):
3270 # test helper will likely be at the end of the symlink
3271 # test helper will likely be at the end of the symlink
3271 realfile = os.path.realpath(fileb)
3272 realfile = os.path.realpath(fileb)
3272 realdir = os.path.abspath(os.path.dirname(realfile))
3273 realdir = os.path.abspath(os.path.dirname(realfile))
3273 path.insert(2, realdir)
3274 path.insert(2, realdir)
3274 if chgbindir != self._bindir:
3275 if chgbindir != self._bindir:
3275 path.insert(1, chgbindir)
3276 path.insert(1, chgbindir)
3276 if rhgbindir != self._bindir:
3277 if rhgbindir != self._bindir:
3277 path.insert(1, rhgbindir)
3278 path.insert(1, rhgbindir)
3278 if self._testdir != runtestdir:
3279 if self._testdir != runtestdir:
3279 path = [self._testdir] + path
3280 path = [self._testdir] + path
3280 path = [self._custom_bin_dir] + path
3281 path = [self._custom_bin_dir] + path
3281 osenvironb[b"PATH"] = sepb.join(path)
3282 osenvironb[b"PATH"] = sepb.join(path)
3282
3283
3283 # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
3284 # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
3284 # can run .../tests/run-tests.py test-foo where test-foo
3285 # can run .../tests/run-tests.py test-foo where test-foo
3285 # adds an extension to HGRC. Also include run-test.py directory to
3286 # adds an extension to HGRC. Also include run-test.py directory to
3286 # import modules like heredoctest.
3287 # import modules like heredoctest.
3287 pypath = [self._pythondir, self._testdir, runtestdir]
3288 pypath = [self._pythondir, self._testdir, runtestdir]
3288
3289
3289 # Setting PYTHONPATH with an activated venv causes the modules installed
3290 # Setting PYTHONPATH with an activated venv causes the modules installed
3290 # in it to be ignored. Therefore, include the related paths in sys.path
3291 # in it to be ignored. Therefore, include the related paths in sys.path
3291 # in PYTHONPATH.
3292 # in PYTHONPATH.
3292 virtual_env = osenvironb.get(b"VIRTUAL_ENV")
3293 virtual_env = osenvironb.get(b"VIRTUAL_ENV")
3293 if virtual_env:
3294 if virtual_env:
3294 virtual_env = os.path.join(virtual_env, b'')
3295 virtual_env = os.path.join(virtual_env, b'')
3295 for p in sys.path:
3296 for p in sys.path:
3296 p = _sys2bytes(p)
3297 p = _sys2bytes(p)
3297 if p.startswith(virtual_env):
3298 if p.startswith(virtual_env):
3298 pypath.append(p)
3299 pypath.append(p)
3299
3300
3300 # We have to augment PYTHONPATH, rather than simply replacing
3301 # We have to augment PYTHONPATH, rather than simply replacing
3301 # it, in case external libraries are only available via current
3302 # it, in case external libraries are only available via current
3302 # PYTHONPATH. (In particular, the Subversion bindings on OS X
3303 # PYTHONPATH. (In particular, the Subversion bindings on OS X
3303 # are in /opt/subversion.)
3304 # are in /opt/subversion.)
3304 oldpypath = osenvironb.get(IMPL_PATH)
3305 oldpypath = osenvironb.get(IMPL_PATH)
3305 if oldpypath:
3306 if oldpypath:
3306 pypath.append(oldpypath)
3307 pypath.append(oldpypath)
3307 osenvironb[IMPL_PATH] = sepb.join(pypath)
3308 osenvironb[IMPL_PATH] = sepb.join(pypath)
3308
3309
3309 if self.options.pure:
3310 if self.options.pure:
3310 os.environ["HGTEST_RUN_TESTS_PURE"] = "--pure"
3311 os.environ["HGTEST_RUN_TESTS_PURE"] = "--pure"
3311 os.environ["HGMODULEPOLICY"] = "py"
3312 os.environ["HGMODULEPOLICY"] = "py"
3312 if self.options.rust:
3313 if self.options.rust:
3313 os.environ["HGMODULEPOLICY"] = "rust+c"
3314 os.environ["HGMODULEPOLICY"] = "rust+c"
3314 if self.options.no_rust:
3315 if self.options.no_rust:
3315 current_policy = os.environ.get("HGMODULEPOLICY", "")
3316 current_policy = os.environ.get("HGMODULEPOLICY", "")
3316 if current_policy.startswith("rust+"):
3317 if current_policy.startswith("rust+"):
3317 os.environ["HGMODULEPOLICY"] = current_policy[len("rust+") :]
3318 os.environ["HGMODULEPOLICY"] = current_policy[len("rust+") :]
3318 os.environ.pop("HGWITHRUSTEXT", None)
3319 os.environ.pop("HGWITHRUSTEXT", None)
3319
3320
3320 if self.options.allow_slow_tests:
3321 if self.options.allow_slow_tests:
3321 os.environ["HGTEST_SLOW"] = "slow"
3322 os.environ["HGTEST_SLOW"] = "slow"
3322 elif 'HGTEST_SLOW' in os.environ:
3323 elif 'HGTEST_SLOW' in os.environ:
3323 del os.environ['HGTEST_SLOW']
3324 del os.environ['HGTEST_SLOW']
3324
3325
3325 self._coveragefile = os.path.join(self._testdir, b'.coverage')
3326 self._coveragefile = os.path.join(self._testdir, b'.coverage')
3326
3327
3327 if self.options.exceptions:
3328 if self.options.exceptions:
3328 exceptionsdir = os.path.join(self._outputdir, b'exceptions')
3329 exceptionsdir = os.path.join(self._outputdir, b'exceptions')
3329 try:
3330 try:
3330 os.makedirs(exceptionsdir)
3331 os.makedirs(exceptionsdir)
3331 except FileExistsError:
3332 except FileExistsError:
3332 pass
3333 pass
3333
3334
3334 # Remove all existing exception reports.
3335 # Remove all existing exception reports.
3335 for f in os.listdir(exceptionsdir):
3336 for f in os.listdir(exceptionsdir):
3336 os.unlink(os.path.join(exceptionsdir, f))
3337 os.unlink(os.path.join(exceptionsdir, f))
3337
3338
3338 osenvironb[b'HGEXCEPTIONSDIR'] = exceptionsdir
3339 osenvironb[b'HGEXCEPTIONSDIR'] = exceptionsdir
3339 logexceptions = os.path.join(self._testdir, b'logexceptions.py')
3340 logexceptions = os.path.join(self._testdir, b'logexceptions.py')
3340 self.options.extra_config_opt.append(
3341 self.options.extra_config_opt.append(
3341 'extensions.logexceptions=%s' % logexceptions.decode('utf-8')
3342 'extensions.logexceptions=%s' % logexceptions.decode('utf-8')
3342 )
3343 )
3343
3344
3344 vlog("# Using TESTDIR", _bytes2sys(self._testdir))
3345 vlog("# Using TESTDIR", _bytes2sys(self._testdir))
3345 vlog("# Using RUNTESTDIR", _bytes2sys(osenvironb[b'RUNTESTDIR']))
3346 vlog("# Using RUNTESTDIR", _bytes2sys(osenvironb[b'RUNTESTDIR']))
3346 vlog("# Using HGTMP", _bytes2sys(self._hgtmp))
3347 vlog("# Using HGTMP", _bytes2sys(self._hgtmp))
3347 vlog("# Using PATH", os.environ["PATH"])
3348 vlog("# Using PATH", os.environ["PATH"])
3348 vlog(
3349 vlog(
3349 "# Using",
3350 "# Using",
3350 _bytes2sys(IMPL_PATH),
3351 _bytes2sys(IMPL_PATH),
3351 _bytes2sys(osenvironb[IMPL_PATH]),
3352 _bytes2sys(osenvironb[IMPL_PATH]),
3352 )
3353 )
3353 vlog("# Writing to directory", _bytes2sys(self._outputdir))
3354 vlog("# Writing to directory", _bytes2sys(self._outputdir))
3354
3355
3355 try:
3356 try:
3356 return self._runtests(testdescs) or 0
3357 return self._runtests(testdescs) or 0
3357 finally:
3358 finally:
3358 time.sleep(0.1)
3359 time.sleep(0.1)
3359 self._cleanup()
3360 self._cleanup()
3360
3361
3361 def findtests(self, args):
3362 def findtests(self, args):
3362 """Finds possible test files from arguments.
3363 """Finds possible test files from arguments.
3363
3364
3364 If you wish to inject custom tests into the test harness, this would
3365 If you wish to inject custom tests into the test harness, this would
3365 be a good function to monkeypatch or override in a derived class.
3366 be a good function to monkeypatch or override in a derived class.
3366 """
3367 """
3367 if not args:
3368 if not args:
3368 if self.options.changed:
3369 if self.options.changed:
3369 proc = Popen4(
3370 proc = Popen4(
3370 b'hg st --rev "%s" -man0 .'
3371 b'hg st --rev "%s" -man0 .'
3371 % _sys2bytes(self.options.changed),
3372 % _sys2bytes(self.options.changed),
3372 None,
3373 None,
3373 0,
3374 0,
3374 )
3375 )
3375 stdout, stderr = proc.communicate()
3376 stdout, stderr = proc.communicate()
3376 args = stdout.strip(b'\0').split(b'\0')
3377 args = stdout.strip(b'\0').split(b'\0')
3377 else:
3378 else:
3378 args = os.listdir(b'.')
3379 args = os.listdir(b'.')
3379
3380
3380 expanded_args = []
3381 expanded_args = []
3381 for arg in args:
3382 for arg in args:
3382 if os.path.isdir(arg):
3383 if os.path.isdir(arg):
3383 if not arg.endswith(b'/'):
3384 if not arg.endswith(b'/'):
3384 arg += b'/'
3385 arg += b'/'
3385 expanded_args.extend([arg + a for a in os.listdir(arg)])
3386 expanded_args.extend([arg + a for a in os.listdir(arg)])
3386 else:
3387 else:
3387 expanded_args.append(arg)
3388 expanded_args.append(arg)
3388 args = expanded_args
3389 args = expanded_args
3389
3390
3390 testcasepattern = re.compile(br'([\w-]+\.t|py)(?:#([a-zA-Z0-9_\-.#]+))')
3391 testcasepattern = re.compile(br'([\w-]+\.t|py)(?:#([a-zA-Z0-9_\-.#]+))')
3391 tests = []
3392 tests = []
3392 for t in args:
3393 for t in args:
3393 case = []
3394 case = []
3394
3395
3395 if not (
3396 if not (
3396 os.path.basename(t).startswith(b'test-')
3397 os.path.basename(t).startswith(b'test-')
3397 and (t.endswith(b'.py') or t.endswith(b'.t'))
3398 and (t.endswith(b'.py') or t.endswith(b'.t'))
3398 ):
3399 ):
3399
3400
3400 m = testcasepattern.match(os.path.basename(t))
3401 m = testcasepattern.match(os.path.basename(t))
3401 if m is not None:
3402 if m is not None:
3402 t_basename, casestr = m.groups()
3403 t_basename, casestr = m.groups()
3403 t = os.path.join(os.path.dirname(t), t_basename)
3404 t = os.path.join(os.path.dirname(t), t_basename)
3404 if casestr:
3405 if casestr:
3405 case = casestr.split(b'#')
3406 case = casestr.split(b'#')
3406 else:
3407 else:
3407 continue
3408 continue
3408
3409
3409 if t.endswith(b'.t'):
3410 if t.endswith(b'.t'):
3410 # .t file may contain multiple test cases
3411 # .t file may contain multiple test cases
3411 casedimensions = parsettestcases(t)
3412 casedimensions = parsettestcases(t)
3412 if casedimensions:
3413 if casedimensions:
3413 cases = []
3414 cases = []
3414
3415
3415 def addcases(case, casedimensions):
3416 def addcases(case, casedimensions):
3416 if not casedimensions:
3417 if not casedimensions:
3417 cases.append(case)
3418 cases.append(case)
3418 else:
3419 else:
3419 for c in casedimensions[0]:
3420 for c in casedimensions[0]:
3420 addcases(case + [c], casedimensions[1:])
3421 addcases(case + [c], casedimensions[1:])
3421
3422
3422 addcases([], casedimensions)
3423 addcases([], casedimensions)
3423 if case and case in cases:
3424 if case and case in cases:
3424 cases = [case]
3425 cases = [case]
3425 elif case:
3426 elif case:
3426 # Ignore invalid cases
3427 # Ignore invalid cases
3427 cases = []
3428 cases = []
3428 else:
3429 else:
3429 pass
3430 pass
3430 tests += [{'path': t, 'case': c} for c in sorted(cases)]
3431 tests += [{'path': t, 'case': c} for c in sorted(cases)]
3431 else:
3432 else:
3432 tests.append({'path': t})
3433 tests.append({'path': t})
3433 else:
3434 else:
3434 tests.append({'path': t})
3435 tests.append({'path': t})
3435
3436
3436 if self.options.retest:
3437 if self.options.retest:
3437 retest_args = []
3438 retest_args = []
3438 for test in tests:
3439 for test in tests:
3439 errpath = self._geterrpath(test)
3440 errpath = self._geterrpath(test)
3440 if os.path.exists(errpath):
3441 if os.path.exists(errpath):
3441 retest_args.append(test)
3442 retest_args.append(test)
3442 tests = retest_args
3443 tests = retest_args
3443 return tests
3444 return tests
3444
3445
3445 def _runtests(self, testdescs):
3446 def _runtests(self, testdescs):
3446 def _reloadtest(test, i):
3447 def _reloadtest(test, i):
3447 # convert a test back to its description dict
3448 # convert a test back to its description dict
3448 desc = {'path': test.path}
3449 desc = {'path': test.path}
3449 case = getattr(test, '_case', [])
3450 case = getattr(test, '_case', [])
3450 if case:
3451 if case:
3451 desc['case'] = case
3452 desc['case'] = case
3452 return self._gettest(desc, i)
3453 return self._gettest(desc, i)
3453
3454
3454 try:
3455 try:
3455 if self.options.restart:
3456 if self.options.restart:
3456 orig = list(testdescs)
3457 orig = list(testdescs)
3457 while testdescs:
3458 while testdescs:
3458 desc = testdescs[0]
3459 desc = testdescs[0]
3459 errpath = self._geterrpath(desc)
3460 errpath = self._geterrpath(desc)
3460 if os.path.exists(errpath):
3461 if os.path.exists(errpath):
3461 break
3462 break
3462 testdescs.pop(0)
3463 testdescs.pop(0)
3463 if not testdescs:
3464 if not testdescs:
3464 print("running all tests")
3465 print("running all tests")
3465 testdescs = orig
3466 testdescs = orig
3466
3467
3467 tests = [self._gettest(d, i) for i, d in enumerate(testdescs)]
3468 tests = [self._gettest(d, i) for i, d in enumerate(testdescs)]
3468 num_tests = len(tests) * self.options.runs_per_test
3469 num_tests = len(tests) * self.options.runs_per_test
3469
3470
3470 jobs = min(num_tests, self.options.jobs)
3471 jobs = min(num_tests, self.options.jobs)
3471
3472
3472 failed = False
3473 failed = False
3473 kws = self.options.keywords
3474 kws = self.options.keywords
3474 if kws is not None:
3475 if kws is not None:
3475 kws = kws.encode('utf-8')
3476 kws = kws.encode('utf-8')
3476
3477
3477 suite = TestSuite(
3478 suite = TestSuite(
3478 self._testdir,
3479 self._testdir,
3479 jobs=jobs,
3480 jobs=jobs,
3480 whitelist=self.options.whitelisted,
3481 whitelist=self.options.whitelisted,
3481 blacklist=self.options.blacklist,
3482 blacklist=self.options.blacklist,
3482 keywords=kws,
3483 keywords=kws,
3483 loop=self.options.loop,
3484 loop=self.options.loop,
3484 runs_per_test=self.options.runs_per_test,
3485 runs_per_test=self.options.runs_per_test,
3485 showchannels=self.options.showchannels,
3486 showchannels=self.options.showchannels,
3486 tests=tests,
3487 tests=tests,
3487 loadtest=_reloadtest,
3488 loadtest=_reloadtest,
3488 )
3489 )
3489 verbosity = 1
3490 verbosity = 1
3490 if self.options.list_tests:
3491 if self.options.list_tests:
3491 verbosity = 0
3492 verbosity = 0
3492 elif self.options.verbose:
3493 elif self.options.verbose:
3493 verbosity = 2
3494 verbosity = 2
3494 runner = TextTestRunner(self, verbosity=verbosity)
3495 runner = TextTestRunner(self, verbosity=verbosity)
3495
3496
3496 osenvironb.pop(b'PYOXIDIZED_IN_MEMORY_RSRC', None)
3497 osenvironb.pop(b'PYOXIDIZED_IN_MEMORY_RSRC', None)
3497 osenvironb.pop(b'PYOXIDIZED_FILESYSTEM_RSRC', None)
3498 osenvironb.pop(b'PYOXIDIZED_FILESYSTEM_RSRC', None)
3498
3499
3499 if self.options.list_tests:
3500 if self.options.list_tests:
3500 result = runner.listtests(suite)
3501 result = runner.listtests(suite)
3501 else:
3502 else:
3502 install_start_time = time.monotonic()
3503 install_start_time = time.monotonic()
3503 self._usecorrectpython()
3504 self._usecorrectpython()
3504 if self._installdir:
3505 if self._installdir:
3505 self._installhg()
3506 self._installhg()
3506 self._checkhglib("Testing")
3507 self._checkhglib("Testing")
3507 if self.options.chg:
3508 if self.options.chg:
3508 assert self._installdir
3509 assert self._installdir
3509 self._installchg()
3510 self._installchg()
3510 if self.options.rhg:
3511 if self.options.rhg:
3511 assert self._installdir
3512 assert self._installdir
3512 self._installrhg()
3513 self._installrhg()
3513 elif self.options.pyoxidized:
3514 elif self.options.pyoxidized:
3514 self._build_pyoxidized()
3515 self._build_pyoxidized()
3515 self._use_correct_mercurial()
3516 self._use_correct_mercurial()
3516 install_end_time = time.monotonic()
3517 install_end_time = time.monotonic()
3517 if self._installdir:
3518 if self._installdir:
3518 msg = 'installed Mercurial in %.2f seconds'
3519 msg = 'installed Mercurial in %.2f seconds'
3519 msg %= install_end_time - install_start_time
3520 msg %= install_end_time - install_start_time
3520 log(msg)
3521 log(msg)
3521
3522
3522 log(
3523 log(
3523 'running %d tests using %d parallel processes'
3524 'running %d tests using %d parallel processes'
3524 % (num_tests, jobs)
3525 % (num_tests, jobs)
3525 )
3526 )
3526
3527
3527 result = runner.run(suite)
3528 result = runner.run(suite)
3528
3529
3529 if result.failures or result.errors:
3530 if result.failures or result.errors:
3530 failed = True
3531 failed = True
3531
3532
3532 result.onEnd()
3533 result.onEnd()
3533
3534
3534 if self.options.anycoverage:
3535 if self.options.anycoverage:
3535 self._outputcoverage()
3536 self._outputcoverage()
3536 except KeyboardInterrupt:
3537 except KeyboardInterrupt:
3537 failed = True
3538 failed = True
3538 print("\ninterrupted!")
3539 print("\ninterrupted!")
3539
3540
3540 if failed:
3541 if failed:
3541 return 1
3542 return 1
3542
3543
3543 def _geterrpath(self, test):
3544 def _geterrpath(self, test):
3544 # test['path'] is a relative path
3545 # test['path'] is a relative path
3545 if 'case' in test:
3546 if 'case' in test:
3546 # for multiple dimensions test cases
3547 # for multiple dimensions test cases
3547 casestr = b'#'.join(test['case'])
3548 casestr = b'#'.join(test['case'])
3548 errpath = b'%s#%s.err' % (test['path'], casestr)
3549 errpath = b'%s#%s.err' % (test['path'], casestr)
3549 else:
3550 else:
3550 errpath = b'%s.err' % test['path']
3551 errpath = b'%s.err' % test['path']
3551 if self.options.outputdir:
3552 if self.options.outputdir:
3552 self._outputdir = canonpath(_sys2bytes(self.options.outputdir))
3553 self._outputdir = canonpath(_sys2bytes(self.options.outputdir))
3553 errpath = os.path.join(self._outputdir, errpath)
3554 errpath = os.path.join(self._outputdir, errpath)
3554 return errpath
3555 return errpath
3555
3556
3556 def _getport(self, count):
3557 def _getport(self, count):
3557 port = self._ports.get(count) # do we have a cached entry?
3558 port = self._ports.get(count) # do we have a cached entry?
3558 if port is None:
3559 if port is None:
3559 portneeded = 3
3560 portneeded = 3
3560 # above 100 tries we just give up and let test reports failure
3561 # above 100 tries we just give up and let test reports failure
3561 for tries in range(100):
3562 for tries in range(100):
3562 allfree = True
3563 allfree = True
3563 port = self.options.port + self._portoffset
3564 port = self.options.port + self._portoffset
3564 for idx in range(portneeded):
3565 for idx in range(portneeded):
3565 if not checkportisavailable(port + idx):
3566 if not checkportisavailable(port + idx):
3566 allfree = False
3567 allfree = False
3567 break
3568 break
3568 self._portoffset += portneeded
3569 self._portoffset += portneeded
3569 if allfree:
3570 if allfree:
3570 break
3571 break
3571 self._ports[count] = port
3572 self._ports[count] = port
3572 return port
3573 return port
3573
3574
3574 def _gettest(self, testdesc, count):
3575 def _gettest(self, testdesc, count):
3575 """Obtain a Test by looking at its filename.
3576 """Obtain a Test by looking at its filename.
3576
3577
3577 Returns a Test instance. The Test may not be runnable if it doesn't
3578 Returns a Test instance. The Test may not be runnable if it doesn't
3578 map to a known type.
3579 map to a known type.
3579 """
3580 """
3580 path = testdesc['path']
3581 path = testdesc['path']
3581 lctest = path.lower()
3582 lctest = path.lower()
3582 testcls = Test
3583 testcls = Test
3583
3584
3584 for ext, cls in self.TESTTYPES:
3585 for ext, cls in self.TESTTYPES:
3585 if lctest.endswith(ext):
3586 if lctest.endswith(ext):
3586 testcls = cls
3587 testcls = cls
3587 break
3588 break
3588
3589
3589 refpath = os.path.join(getcwdb(), path)
3590 refpath = os.path.join(getcwdb(), path)
3590 tmpdir = os.path.join(self._hgtmp, b'child%d' % count)
3591 tmpdir = os.path.join(self._hgtmp, b'child%d' % count)
3591
3592
3592 # extra keyword parameters. 'case' is used by .t tests
3593 # extra keyword parameters. 'case' is used by .t tests
3593 kwds = {k: testdesc[k] for k in ['case'] if k in testdesc}
3594 kwds = {k: testdesc[k] for k in ['case'] if k in testdesc}
3594
3595
3595 t = testcls(
3596 t = testcls(
3596 refpath,
3597 refpath,
3597 self._outputdir,
3598 self._outputdir,
3598 tmpdir,
3599 tmpdir,
3599 keeptmpdir=self.options.keep_tmpdir,
3600 keeptmpdir=self.options.keep_tmpdir,
3600 debug=self.options.debug,
3601 debug=self.options.debug,
3601 first=self.options.first,
3602 first=self.options.first,
3602 timeout=self.options.timeout,
3603 timeout=self.options.timeout,
3603 startport=self._getport(count),
3604 startport=self._getport(count),
3604 extraconfigopts=self.options.extra_config_opt,
3605 extraconfigopts=self.options.extra_config_opt,
3605 shell=self.options.shell,
3606 shell=self.options.shell,
3606 hgcommand=self._hgcommand,
3607 hgcommand=self._hgcommand,
3607 usechg=bool(self.options.with_chg or self.options.chg),
3608 usechg=bool(self.options.with_chg or self.options.chg),
3608 chgdebug=self.options.chg_debug,
3609 chgdebug=self.options.chg_debug,
3609 useipv6=useipv6,
3610 useipv6=useipv6,
3610 **kwds
3611 **kwds
3611 )
3612 )
3612 t.should_reload = True
3613 t.should_reload = True
3613 return t
3614 return t
3614
3615
3615 def _cleanup(self):
3616 def _cleanup(self):
3616 """Clean up state from this test invocation."""
3617 """Clean up state from this test invocation."""
3617 if self.options.keep_tmpdir:
3618 if self.options.keep_tmpdir:
3618 return
3619 return
3619
3620
3620 vlog("# Cleaning up HGTMP", _bytes2sys(self._hgtmp))
3621 vlog("# Cleaning up HGTMP", _bytes2sys(self._hgtmp))
3621 shutil.rmtree(self._hgtmp, True)
3622 shutil.rmtree(self._hgtmp, True)
3622 for f in self._createdfiles:
3623 for f in self._createdfiles:
3623 try:
3624 try:
3624 os.remove(f)
3625 os.remove(f)
3625 except OSError:
3626 except OSError:
3626 pass
3627 pass
3627
3628
3628 def _usecorrectpython(self):
3629 def _usecorrectpython(self):
3629 """Configure the environment to use the appropriate Python in tests."""
3630 """Configure the environment to use the appropriate Python in tests."""
3630 # Tests must use the same interpreter as us or bad things will happen.
3631 # Tests must use the same interpreter as us or bad things will happen.
3631 if WINDOWS:
3632 if WINDOWS:
3632 pyexe_names = [b'python', b'python3', b'python.exe']
3633 pyexe_names = [b'python', b'python3', b'python.exe']
3633 else:
3634 else:
3634 pyexe_names = [b'python', b'python3']
3635 pyexe_names = [b'python', b'python3']
3635
3636
3636 # os.symlink() is a thing with py3 on Windows, but it requires
3637 # os.symlink() is a thing with py3 on Windows, but it requires
3637 # Administrator rights.
3638 # Administrator rights.
3638 if not WINDOWS and getattr(os, 'symlink', None):
3639 if not WINDOWS and getattr(os, 'symlink', None):
3639 msg = "# Making python executable in test path a symlink to '%s'"
3640 msg = "# Making python executable in test path a symlink to '%s'"
3640 msg %= sysexecutable
3641 msg %= sysexecutable
3641 vlog(msg)
3642 vlog(msg)
3642 for pyexename in pyexe_names:
3643 for pyexename in pyexe_names:
3643 mypython = os.path.join(self._custom_bin_dir, pyexename)
3644 mypython = os.path.join(self._custom_bin_dir, pyexename)
3644 try:
3645 try:
3645 if os.readlink(mypython) == sysexecutable:
3646 if os.readlink(mypython) == sysexecutable:
3646 continue
3647 continue
3647 os.unlink(mypython)
3648 os.unlink(mypython)
3648 except FileNotFoundError:
3649 except FileNotFoundError:
3649 pass
3650 pass
3650 if self._findprogram(pyexename) != sysexecutable:
3651 if self._findprogram(pyexename) != sysexecutable:
3651 try:
3652 try:
3652 os.symlink(sysexecutable, mypython)
3653 os.symlink(sysexecutable, mypython)
3653 self._createdfiles.append(mypython)
3654 self._createdfiles.append(mypython)
3654 except FileExistsError:
3655 except FileExistsError:
3655 # child processes may race, which is harmless
3656 # child processes may race, which is harmless
3656 pass
3657 pass
3657 elif WINDOWS and not os.getenv('MSYSTEM'):
3658 elif WINDOWS and not os.getenv('MSYSTEM'):
3658 raise AssertionError('cannot run test on Windows without MSYSTEM')
3659 raise AssertionError('cannot run test on Windows without MSYSTEM')
3659 else:
3660 else:
3660 # Generate explicit file instead of symlink
3661 # Generate explicit file instead of symlink
3661 #
3662 #
3662 # This is especially important as Windows doesn't have
3663 # This is especially important as Windows doesn't have
3663 # `python3.exe`, and MSYS cannot understand the reparse point with
3664 # `python3.exe`, and MSYS cannot understand the reparse point with
3664 # that name provided by Microsoft. Create a simple script on PATH
3665 # that name provided by Microsoft. Create a simple script on PATH
3665 # with that name that delegates to the py3 launcher so the shebang
3666 # with that name that delegates to the py3 launcher so the shebang
3666 # lines work.
3667 # lines work.
3667 esc_executable = _sys2bytes(shellquote(sysexecutable))
3668 esc_executable = _sys2bytes(shellquote(sysexecutable))
3668 for pyexename in pyexe_names:
3669 for pyexename in pyexe_names:
3669 stub_exec_path = os.path.join(self._custom_bin_dir, pyexename)
3670 stub_exec_path = os.path.join(self._custom_bin_dir, pyexename)
3670 with open(stub_exec_path, 'wb') as f:
3671 with open(stub_exec_path, 'wb') as f:
3671 f.write(b'#!/bin/sh\n')
3672 f.write(b'#!/bin/sh\n')
3672 f.write(b'%s "$@"\n' % esc_executable)
3673 f.write(b'%s "$@"\n' % esc_executable)
3673
3674
3674 if WINDOWS:
3675 if WINDOWS:
3675 # adjust the path to make sur the main python finds it own dll
3676 # adjust the path to make sur the main python finds it own dll
3676 path = os.environ['PATH'].split(os.pathsep)
3677 path = os.environ['PATH'].split(os.pathsep)
3677 main_exec_dir = os.path.dirname(sysexecutable)
3678 main_exec_dir = os.path.dirname(sysexecutable)
3678 extra_paths = [_bytes2sys(self._custom_bin_dir), main_exec_dir]
3679 extra_paths = [_bytes2sys(self._custom_bin_dir), main_exec_dir]
3679
3680
3680 # Binaries installed by pip into the user area like pylint.exe may
3681 # Binaries installed by pip into the user area like pylint.exe may
3681 # not be in PATH by default.
3682 # not be in PATH by default.
3682 appdata = os.environ.get('APPDATA')
3683 appdata = os.environ.get('APPDATA')
3683 vi = sys.version_info
3684 vi = sys.version_info
3684 if appdata is not None:
3685 if appdata is not None:
3685 python_dir = 'Python%d%d' % (vi[0], vi[1])
3686 python_dir = 'Python%d%d' % (vi[0], vi[1])
3686 scripts_path = [appdata, 'Python', python_dir, 'Scripts']
3687 scripts_path = [appdata, 'Python', python_dir, 'Scripts']
3687 scripts_dir = os.path.join(*scripts_path)
3688 scripts_dir = os.path.join(*scripts_path)
3688 extra_paths.append(scripts_dir)
3689 extra_paths.append(scripts_dir)
3689
3690
3690 os.environ['PATH'] = os.pathsep.join(extra_paths + path)
3691 os.environ['PATH'] = os.pathsep.join(extra_paths + path)
3691
3692
3692 def _use_correct_mercurial(self):
3693 def _use_correct_mercurial(self):
3693 target_exec = os.path.join(self._custom_bin_dir, b'hg')
3694 target_exec = os.path.join(self._custom_bin_dir, b'hg')
3694 if self._hgcommand != b'hg':
3695 if self._hgcommand != b'hg':
3695 # shutil.which only accept bytes from 3.8
3696 # shutil.which only accept bytes from 3.8
3696 real_exec = which(self._hgcommand)
3697 real_exec = which(self._hgcommand)
3697 if real_exec is None:
3698 if real_exec is None:
3698 raise ValueError('could not find exec path for "%s"', real_exec)
3699 raise ValueError('could not find exec path for "%s"', real_exec)
3699 if real_exec == target_exec:
3700 if real_exec == target_exec:
3700 # do not overwrite something with itself
3701 # do not overwrite something with itself
3701 return
3702 return
3702 if WINDOWS:
3703 if WINDOWS:
3703 with open(target_exec, 'wb') as f:
3704 with open(target_exec, 'wb') as f:
3704 f.write(b'#!/bin/sh\n')
3705 f.write(b'#!/bin/sh\n')
3705 escaped_exec = shellquote(_bytes2sys(real_exec))
3706 escaped_exec = shellquote(_bytes2sys(real_exec))
3706 f.write(b'%s "$@"\n' % _sys2bytes(escaped_exec))
3707 f.write(b'%s "$@"\n' % _sys2bytes(escaped_exec))
3707 else:
3708 else:
3708 os.symlink(real_exec, target_exec)
3709 os.symlink(real_exec, target_exec)
3709 self._createdfiles.append(target_exec)
3710 self._createdfiles.append(target_exec)
3710
3711
3711 def _installhg(self):
3712 def _installhg(self):
3712 """Install hg into the test environment.
3713 """Install hg into the test environment.
3713
3714
3714 This will also configure hg with the appropriate testing settings.
3715 This will also configure hg with the appropriate testing settings.
3715 """
3716 """
3716 vlog("# Performing temporary installation of HG")
3717 vlog("# Performing temporary installation of HG")
3717 installerrs = os.path.join(self._hgtmp, b"install.err")
3718 installerrs = os.path.join(self._hgtmp, b"install.err")
3718 compiler = ''
3719 compiler = ''
3719 if self.options.compiler:
3720 if self.options.compiler:
3720 compiler = '--compiler ' + self.options.compiler
3721 compiler = '--compiler ' + self.options.compiler
3721 setup_opts = b""
3722 setup_opts = b""
3722 if self.options.pure:
3723 if self.options.pure:
3723 setup_opts = b"--pure"
3724 setup_opts = b"--pure"
3724 elif self.options.rust:
3725 elif self.options.rust:
3725 setup_opts = b"--rust"
3726 setup_opts = b"--rust"
3726 elif self.options.no_rust:
3727 elif self.options.no_rust:
3727 setup_opts = b"--no-rust"
3728 setup_opts = b"--no-rust"
3728
3729
3729 # Run installer in hg root
3730 # Run installer in hg root
3730 compiler = _sys2bytes(compiler)
3731 compiler = _sys2bytes(compiler)
3731 script = _sys2bytes(os.path.realpath(sys.argv[0]))
3732 script = _sys2bytes(os.path.realpath(sys.argv[0]))
3732 exe = _sys2bytes(sysexecutable)
3733 exe = _sys2bytes(sysexecutable)
3733 hgroot = os.path.dirname(os.path.dirname(script))
3734 hgroot = os.path.dirname(os.path.dirname(script))
3734 self._hgroot = hgroot
3735 self._hgroot = hgroot
3735 os.chdir(hgroot)
3736 os.chdir(hgroot)
3736 nohome = b'--home=""'
3737 nohome = b'--home=""'
3737 if WINDOWS:
3738 if WINDOWS:
3738 # The --home="" trick works only on OS where os.sep == '/'
3739 # The --home="" trick works only on OS where os.sep == '/'
3739 # because of a distutils convert_path() fast-path. Avoid it at
3740 # because of a distutils convert_path() fast-path. Avoid it at
3740 # least on Windows for now, deal with .pydistutils.cfg bugs
3741 # least on Windows for now, deal with .pydistutils.cfg bugs
3741 # when they happen.
3742 # when they happen.
3742 nohome = b''
3743 nohome = b''
3743 cmd = (
3744 cmd = (
3744 b'"%(exe)s" setup.py %(setup_opts)s clean --all'
3745 b'"%(exe)s" setup.py %(setup_opts)s clean --all'
3745 b' build %(compiler)s --build-base="%(base)s"'
3746 b' build %(compiler)s --build-base="%(base)s"'
3746 b' install --force --prefix="%(prefix)s"'
3747 b' install --force --prefix="%(prefix)s"'
3747 b' --install-lib="%(libdir)s"'
3748 b' --install-lib="%(libdir)s"'
3748 b' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
3749 b' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
3749 % {
3750 % {
3750 b'exe': exe,
3751 b'exe': exe,
3751 b'setup_opts': setup_opts,
3752 b'setup_opts': setup_opts,
3752 b'compiler': compiler,
3753 b'compiler': compiler,
3753 b'base': os.path.join(self._hgtmp, b"build"),
3754 b'base': os.path.join(self._hgtmp, b"build"),
3754 b'prefix': self._installdir,
3755 b'prefix': self._installdir,
3755 b'libdir': self._pythondir,
3756 b'libdir': self._pythondir,
3756 b'bindir': self._bindir,
3757 b'bindir': self._bindir,
3757 b'nohome': nohome,
3758 b'nohome': nohome,
3758 b'logfile': installerrs,
3759 b'logfile': installerrs,
3759 }
3760 }
3760 )
3761 )
3761
3762
3762 # setuptools requires install directories to exist.
3763 # setuptools requires install directories to exist.
3763 def makedirs(p):
3764 def makedirs(p):
3764 try:
3765 try:
3765 os.makedirs(p)
3766 os.makedirs(p)
3766 except FileExistsError:
3767 except FileExistsError:
3767 pass
3768 pass
3768
3769
3769 makedirs(self._pythondir)
3770 makedirs(self._pythondir)
3770 makedirs(self._bindir)
3771 makedirs(self._bindir)
3771
3772
3772 vlog("# Running", cmd.decode("utf-8"))
3773 vlog("# Running", cmd.decode("utf-8"))
3773 if subprocess.call(_bytes2sys(cmd), shell=True) == 0:
3774 if subprocess.call(_bytes2sys(cmd), shell=True, env=original_env) == 0:
3774 if not self.options.verbose:
3775 if not self.options.verbose:
3775 try:
3776 try:
3776 os.remove(installerrs)
3777 os.remove(installerrs)
3777 except FileNotFoundError:
3778 except FileNotFoundError:
3778 pass
3779 pass
3779 else:
3780 else:
3780 with open(installerrs, 'rb') as f:
3781 with open(installerrs, 'rb') as f:
3781 for line in f:
3782 for line in f:
3782 sys.stdout.buffer.write(line)
3783 sys.stdout.buffer.write(line)
3783 sys.exit(1)
3784 sys.exit(1)
3784 os.chdir(self._testdir)
3785 os.chdir(self._testdir)
3785
3786
3786 hgbat = os.path.join(self._bindir, b'hg.bat')
3787 hgbat = os.path.join(self._bindir, b'hg.bat')
3787 if os.path.isfile(hgbat):
3788 if os.path.isfile(hgbat):
3788 # hg.bat expects to be put in bin/scripts while run-tests.py
3789 # hg.bat expects to be put in bin/scripts while run-tests.py
3789 # installation layout put it in bin/ directly. Fix it
3790 # installation layout put it in bin/ directly. Fix it
3790 with open(hgbat, 'rb') as f:
3791 with open(hgbat, 'rb') as f:
3791 data = f.read()
3792 data = f.read()
3792 if br'"%~dp0..\python" "%~dp0hg" %*' in data:
3793 if br'"%~dp0..\python" "%~dp0hg" %*' in data:
3793 data = data.replace(
3794 data = data.replace(
3794 br'"%~dp0..\python" "%~dp0hg" %*',
3795 br'"%~dp0..\python" "%~dp0hg" %*',
3795 b'"%~dp0python" "%~dp0hg" %*',
3796 b'"%~dp0python" "%~dp0hg" %*',
3796 )
3797 )
3797 with open(hgbat, 'wb') as f:
3798 with open(hgbat, 'wb') as f:
3798 f.write(data)
3799 f.write(data)
3799 else:
3800 else:
3800 print('WARNING: cannot fix hg.bat reference to python.exe')
3801 print('WARNING: cannot fix hg.bat reference to python.exe')
3801
3802
3802 if self.options.anycoverage:
3803 if self.options.anycoverage:
3803 custom = os.path.join(
3804 custom = os.path.join(
3804 osenvironb[b'RUNTESTDIR'], b'sitecustomize.py'
3805 osenvironb[b'RUNTESTDIR'], b'sitecustomize.py'
3805 )
3806 )
3806 target = os.path.join(self._pythondir, b'sitecustomize.py')
3807 target = os.path.join(self._pythondir, b'sitecustomize.py')
3807 vlog('# Installing coverage trigger to %s' % target)
3808 vlog('# Installing coverage trigger to %s' % target)
3808 shutil.copyfile(custom, target)
3809 shutil.copyfile(custom, target)
3809 rc = os.path.join(self._testdir, b'.coveragerc')
3810 rc = os.path.join(self._testdir, b'.coveragerc')
3810 vlog('# Installing coverage rc to %s' % rc)
3811 vlog('# Installing coverage rc to %s' % rc)
3811 osenvironb[b'COVERAGE_PROCESS_START'] = rc
3812 osenvironb[b'COVERAGE_PROCESS_START'] = rc
3812 covdir = os.path.join(self._installdir, b'..', b'coverage')
3813 covdir = os.path.join(self._installdir, b'..', b'coverage')
3813 try:
3814 try:
3814 os.mkdir(covdir)
3815 os.mkdir(covdir)
3815 except FileExistsError:
3816 except FileExistsError:
3816 pass
3817 pass
3817
3818
3818 osenvironb[b'COVERAGE_DIR'] = covdir
3819 osenvironb[b'COVERAGE_DIR'] = covdir
3819
3820
3820 def _checkhglib(self, verb):
3821 def _checkhglib(self, verb):
3821 """Ensure that the 'mercurial' package imported by python is
3822 """Ensure that the 'mercurial' package imported by python is
3822 the one we expect it to be. If not, print a warning to stderr."""
3823 the one we expect it to be. If not, print a warning to stderr."""
3823 if self._pythondir_inferred:
3824 if self._pythondir_inferred:
3824 # The pythondir has been inferred from --with-hg flag.
3825 # The pythondir has been inferred from --with-hg flag.
3825 # We cannot expect anything sensible here.
3826 # We cannot expect anything sensible here.
3826 return
3827 return
3827 expecthg = os.path.join(self._pythondir, b'mercurial')
3828 expecthg = os.path.join(self._pythondir, b'mercurial')
3828 actualhg = self._gethgpath()
3829 actualhg = self._gethgpath()
3829 if os.path.abspath(actualhg) != os.path.abspath(expecthg):
3830 if os.path.abspath(actualhg) != os.path.abspath(expecthg):
3830 sys.stderr.write(
3831 sys.stderr.write(
3831 'warning: %s with unexpected mercurial lib: %s\n'
3832 'warning: %s with unexpected mercurial lib: %s\n'
3832 ' (expected %s)\n' % (verb, actualhg, expecthg)
3833 ' (expected %s)\n' % (verb, actualhg, expecthg)
3833 )
3834 )
3834
3835
3835 def _gethgpath(self):
3836 def _gethgpath(self):
3836 """Return the path to the mercurial package that is actually found by
3837 """Return the path to the mercurial package that is actually found by
3837 the current Python interpreter."""
3838 the current Python interpreter."""
3838 if self._hgpath is not None:
3839 if self._hgpath is not None:
3839 return self._hgpath
3840 return self._hgpath
3840
3841
3841 cmd = b'"%s" -c "import mercurial; print (mercurial.__path__[0])"'
3842 cmd = b'"%s" -c "import mercurial; print (mercurial.__path__[0])"'
3842 cmd = _bytes2sys(cmd % PYTHON)
3843 cmd = _bytes2sys(cmd % PYTHON)
3843
3844
3844 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
3845 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
3845 out, err = p.communicate()
3846 out, err = p.communicate()
3846
3847
3847 self._hgpath = out.strip()
3848 self._hgpath = out.strip()
3848
3849
3849 return self._hgpath
3850 return self._hgpath
3850
3851
3851 def _installchg(self):
3852 def _installchg(self):
3852 """Install chg into the test environment"""
3853 """Install chg into the test environment"""
3853 vlog('# Performing temporary installation of CHG')
3854 vlog('# Performing temporary installation of CHG')
3854 assert os.path.dirname(self._bindir) == self._installdir
3855 assert os.path.dirname(self._bindir) == self._installdir
3855 assert self._hgroot, 'must be called after _installhg()'
3856 assert self._hgroot, 'must be called after _installhg()'
3856 cmd = b'"%(make)s" clean install PREFIX="%(prefix)s"' % {
3857 cmd = b'"%(make)s" clean install PREFIX="%(prefix)s"' % {
3857 b'make': b'make', # TODO: switch by option or environment?
3858 b'make': b'make', # TODO: switch by option or environment?
3858 b'prefix': self._installdir,
3859 b'prefix': self._installdir,
3859 }
3860 }
3860 cwd = os.path.join(self._hgroot, b'contrib', b'chg')
3861 cwd = os.path.join(self._hgroot, b'contrib', b'chg')
3861 vlog("# Running", cmd)
3862 vlog("# Running", cmd)
3862 proc = subprocess.Popen(
3863 proc = subprocess.Popen(
3863 cmd,
3864 cmd,
3864 shell=True,
3865 shell=True,
3865 cwd=cwd,
3866 cwd=cwd,
3866 stdin=subprocess.PIPE,
3867 stdin=subprocess.PIPE,
3867 stdout=subprocess.PIPE,
3868 stdout=subprocess.PIPE,
3868 stderr=subprocess.STDOUT,
3869 stderr=subprocess.STDOUT,
3869 )
3870 )
3870 out, _err = proc.communicate()
3871 out, _err = proc.communicate()
3871 if proc.returncode != 0:
3872 if proc.returncode != 0:
3872 sys.stdout.buffer.write(out)
3873 sys.stdout.buffer.write(out)
3873 sys.exit(1)
3874 sys.exit(1)
3874
3875
3875 def _installrhg(self):
3876 def _installrhg(self):
3876 """Install rhg into the test environment"""
3877 """Install rhg into the test environment"""
3877 vlog('# Performing temporary installation of rhg')
3878 vlog('# Performing temporary installation of rhg')
3878 assert os.path.dirname(self._bindir) == self._installdir
3879 assert os.path.dirname(self._bindir) == self._installdir
3879 assert self._hgroot, 'must be called after _installhg()'
3880 assert self._hgroot, 'must be called after _installhg()'
3880 cmd = b'"%(make)s" install-rhg PREFIX="%(prefix)s"' % {
3881 cmd = b'"%(make)s" install-rhg PREFIX="%(prefix)s"' % {
3881 b'make': b'make', # TODO: switch by option or environment?
3882 b'make': b'make', # TODO: switch by option or environment?
3882 b'prefix': self._installdir,
3883 b'prefix': self._installdir,
3883 }
3884 }
3884 cwd = self._hgroot
3885 cwd = self._hgroot
3885 vlog("# Running", cmd)
3886 vlog("# Running", cmd)
3886 proc = subprocess.Popen(
3887 proc = subprocess.Popen(
3887 cmd,
3888 cmd,
3888 shell=True,
3889 shell=True,
3889 cwd=cwd,
3890 cwd=cwd,
3890 stdin=subprocess.PIPE,
3891 stdin=subprocess.PIPE,
3891 stdout=subprocess.PIPE,
3892 stdout=subprocess.PIPE,
3892 stderr=subprocess.STDOUT,
3893 stderr=subprocess.STDOUT,
3893 )
3894 )
3894 out, _err = proc.communicate()
3895 out, _err = proc.communicate()
3895 if proc.returncode != 0:
3896 if proc.returncode != 0:
3896 sys.stdout.buffer.write(out)
3897 sys.stdout.buffer.write(out)
3897 sys.exit(1)
3898 sys.exit(1)
3898
3899
3899 def _build_pyoxidized(self):
3900 def _build_pyoxidized(self):
3900 """build a pyoxidized version of mercurial into the test environment
3901 """build a pyoxidized version of mercurial into the test environment
3901
3902
3902 Ideally this function would be `install_pyoxidier` and would both build
3903 Ideally this function would be `install_pyoxidier` and would both build
3903 and install pyoxidier. However we are starting small to get pyoxidizer
3904 and install pyoxidier. However we are starting small to get pyoxidizer
3904 build binary to testing quickly.
3905 build binary to testing quickly.
3905 """
3906 """
3906 vlog('# build a pyoxidized version of Mercurial')
3907 vlog('# build a pyoxidized version of Mercurial')
3907 assert os.path.dirname(self._bindir) == self._installdir
3908 assert os.path.dirname(self._bindir) == self._installdir
3908 assert self._hgroot, 'must be called after _installhg()'
3909 assert self._hgroot, 'must be called after _installhg()'
3909 target = b''
3910 target = b''
3910 if WINDOWS:
3911 if WINDOWS:
3911 target = b'windows'
3912 target = b'windows'
3912 elif MACOS:
3913 elif MACOS:
3913 target = b'macos'
3914 target = b'macos'
3914
3915
3915 cmd = b'"%(make)s" pyoxidizer-%(platform)s-tests' % {
3916 cmd = b'"%(make)s" pyoxidizer-%(platform)s-tests' % {
3916 b'make': b'make',
3917 b'make': b'make',
3917 b'platform': target,
3918 b'platform': target,
3918 }
3919 }
3919 cwd = self._hgroot
3920 cwd = self._hgroot
3920 vlog("# Running", cmd)
3921 vlog("# Running", cmd)
3921 proc = subprocess.Popen(
3922 proc = subprocess.Popen(
3922 _bytes2sys(cmd),
3923 _bytes2sys(cmd),
3923 shell=True,
3924 shell=True,
3924 cwd=_bytes2sys(cwd),
3925 cwd=_bytes2sys(cwd),
3925 stdin=subprocess.PIPE,
3926 stdin=subprocess.PIPE,
3926 stdout=subprocess.PIPE,
3927 stdout=subprocess.PIPE,
3927 stderr=subprocess.STDOUT,
3928 stderr=subprocess.STDOUT,
3928 )
3929 )
3929 out, _err = proc.communicate()
3930 out, _err = proc.communicate()
3930 if proc.returncode != 0:
3931 if proc.returncode != 0:
3931 sys.stdout.buffer.write(out)
3932 sys.stdout.buffer.write(out)
3932 sys.exit(1)
3933 sys.exit(1)
3933
3934
3934 cmd = _bytes2sys(b"%s debuginstall -Tjson" % self._hgcommand)
3935 cmd = _bytes2sys(b"%s debuginstall -Tjson" % self._hgcommand)
3935 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
3936 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
3936 out, err = p.communicate()
3937 out, err = p.communicate()
3937
3938
3938 props = json.loads(out)[0]
3939 props = json.loads(out)[0]
3939
3940
3940 # Affects hghave.py
3941 # Affects hghave.py
3941 osenvironb.pop(b'PYOXIDIZED_IN_MEMORY_RSRC', None)
3942 osenvironb.pop(b'PYOXIDIZED_IN_MEMORY_RSRC', None)
3942 osenvironb.pop(b'PYOXIDIZED_FILESYSTEM_RSRC', None)
3943 osenvironb.pop(b'PYOXIDIZED_FILESYSTEM_RSRC', None)
3943 if props["hgmodules"] == props["pythonexe"]:
3944 if props["hgmodules"] == props["pythonexe"]:
3944 osenvironb[b'PYOXIDIZED_IN_MEMORY_RSRC'] = b'1'
3945 osenvironb[b'PYOXIDIZED_IN_MEMORY_RSRC'] = b'1'
3945 else:
3946 else:
3946 osenvironb[b'PYOXIDIZED_FILESYSTEM_RSRC'] = b'1'
3947 osenvironb[b'PYOXIDIZED_FILESYSTEM_RSRC'] = b'1'
3947
3948
3948 def _outputcoverage(self):
3949 def _outputcoverage(self):
3949 """Produce code coverage output."""
3950 """Produce code coverage output."""
3950 import coverage
3951 import coverage
3951
3952
3952 coverage = coverage.coverage
3953 coverage = coverage.coverage
3953
3954
3954 vlog('# Producing coverage report')
3955 vlog('# Producing coverage report')
3955 # chdir is the easiest way to get short, relative paths in the
3956 # chdir is the easiest way to get short, relative paths in the
3956 # output.
3957 # output.
3957 os.chdir(self._hgroot)
3958 os.chdir(self._hgroot)
3958 covdir = os.path.join(_bytes2sys(self._installdir), '..', 'coverage')
3959 covdir = os.path.join(_bytes2sys(self._installdir), '..', 'coverage')
3959 cov = coverage(data_file=os.path.join(covdir, 'cov'))
3960 cov = coverage(data_file=os.path.join(covdir, 'cov'))
3960
3961
3961 # Map install directory paths back to source directory.
3962 # Map install directory paths back to source directory.
3962 cov.config.paths['srcdir'] = ['.', _bytes2sys(self._pythondir)]
3963 cov.config.paths['srcdir'] = ['.', _bytes2sys(self._pythondir)]
3963
3964
3964 cov.combine()
3965 cov.combine()
3965
3966
3966 omit = [
3967 omit = [
3967 _bytes2sys(os.path.join(x, b'*'))
3968 _bytes2sys(os.path.join(x, b'*'))
3968 for x in [self._bindir, self._testdir]
3969 for x in [self._bindir, self._testdir]
3969 ]
3970 ]
3970 cov.report(ignore_errors=True, omit=omit)
3971 cov.report(ignore_errors=True, omit=omit)
3971
3972
3972 if self.options.htmlcov:
3973 if self.options.htmlcov:
3973 htmldir = os.path.join(_bytes2sys(self._outputdir), 'htmlcov')
3974 htmldir = os.path.join(_bytes2sys(self._outputdir), 'htmlcov')
3974 cov.html_report(directory=htmldir, omit=omit)
3975 cov.html_report(directory=htmldir, omit=omit)
3975 if self.options.annotate:
3976 if self.options.annotate:
3976 adir = os.path.join(_bytes2sys(self._outputdir), 'annotated')
3977 adir = os.path.join(_bytes2sys(self._outputdir), 'annotated')
3977 if not os.path.isdir(adir):
3978 if not os.path.isdir(adir):
3978 os.mkdir(adir)
3979 os.mkdir(adir)
3979 cov.annotate(directory=adir, omit=omit)
3980 cov.annotate(directory=adir, omit=omit)
3980
3981
3981 def _findprogram(self, program):
3982 def _findprogram(self, program):
3982 """Search PATH for a executable program"""
3983 """Search PATH for a executable program"""
3983 dpb = _sys2bytes(os.defpath)
3984 dpb = _sys2bytes(os.defpath)
3984 sepb = _sys2bytes(os.pathsep)
3985 sepb = _sys2bytes(os.pathsep)
3985 for p in osenvironb.get(b'PATH', dpb).split(sepb):
3986 for p in osenvironb.get(b'PATH', dpb).split(sepb):
3986 name = os.path.join(p, program)
3987 name = os.path.join(p, program)
3987 if WINDOWS or os.access(name, os.X_OK):
3988 if WINDOWS or os.access(name, os.X_OK):
3988 return _bytes2sys(name)
3989 return _bytes2sys(name)
3989 return None
3990 return None
3990
3991
3991 def _checktools(self):
3992 def _checktools(self):
3992 """Ensure tools required to run tests are present."""
3993 """Ensure tools required to run tests are present."""
3993 for p in self.REQUIREDTOOLS:
3994 for p in self.REQUIREDTOOLS:
3994 if WINDOWS and not p.endswith(b'.exe'):
3995 if WINDOWS and not p.endswith(b'.exe'):
3995 p += b'.exe'
3996 p += b'.exe'
3996 found = self._findprogram(p)
3997 found = self._findprogram(p)
3997 p = p.decode("utf-8")
3998 p = p.decode("utf-8")
3998 if found:
3999 if found:
3999 vlog("# Found prerequisite", p, "at", found)
4000 vlog("# Found prerequisite", p, "at", found)
4000 else:
4001 else:
4001 print("WARNING: Did not find prerequisite tool: %s " % p)
4002 print("WARNING: Did not find prerequisite tool: %s " % p)
4002
4003
4003
4004
4004 def aggregateexceptions(path):
4005 def aggregateexceptions(path):
4005 exceptioncounts = collections.Counter()
4006 exceptioncounts = collections.Counter()
4006 testsbyfailure = collections.defaultdict(set)
4007 testsbyfailure = collections.defaultdict(set)
4007 failuresbytest = collections.defaultdict(set)
4008 failuresbytest = collections.defaultdict(set)
4008
4009
4009 for f in os.listdir(path):
4010 for f in os.listdir(path):
4010 with open(os.path.join(path, f), 'rb') as fh:
4011 with open(os.path.join(path, f), 'rb') as fh:
4011 data = fh.read().split(b'\0')
4012 data = fh.read().split(b'\0')
4012 if len(data) != 5:
4013 if len(data) != 5:
4013 continue
4014 continue
4014
4015
4015 exc, mainframe, hgframe, hgline, testname = data
4016 exc, mainframe, hgframe, hgline, testname = data
4016 exc = exc.decode('utf-8')
4017 exc = exc.decode('utf-8')
4017 mainframe = mainframe.decode('utf-8')
4018 mainframe = mainframe.decode('utf-8')
4018 hgframe = hgframe.decode('utf-8')
4019 hgframe = hgframe.decode('utf-8')
4019 hgline = hgline.decode('utf-8')
4020 hgline = hgline.decode('utf-8')
4020 testname = testname.decode('utf-8')
4021 testname = testname.decode('utf-8')
4021
4022
4022 key = (hgframe, hgline, exc)
4023 key = (hgframe, hgline, exc)
4023 exceptioncounts[key] += 1
4024 exceptioncounts[key] += 1
4024 testsbyfailure[key].add(testname)
4025 testsbyfailure[key].add(testname)
4025 failuresbytest[testname].add(key)
4026 failuresbytest[testname].add(key)
4026
4027
4027 # Find test having fewest failures for each failure.
4028 # Find test having fewest failures for each failure.
4028 leastfailing = {}
4029 leastfailing = {}
4029 for key, tests in testsbyfailure.items():
4030 for key, tests in testsbyfailure.items():
4030 fewesttest = None
4031 fewesttest = None
4031 fewestcount = 99999999
4032 fewestcount = 99999999
4032 for test in sorted(tests):
4033 for test in sorted(tests):
4033 if len(failuresbytest[test]) < fewestcount:
4034 if len(failuresbytest[test]) < fewestcount:
4034 fewesttest = test
4035 fewesttest = test
4035 fewestcount = len(failuresbytest[test])
4036 fewestcount = len(failuresbytest[test])
4036
4037
4037 leastfailing[key] = (fewestcount, fewesttest)
4038 leastfailing[key] = (fewestcount, fewesttest)
4038
4039
4039 # Create a combined counter so we can sort by total occurrences and
4040 # Create a combined counter so we can sort by total occurrences and
4040 # impacted tests.
4041 # impacted tests.
4041 combined = {}
4042 combined = {}
4042 for key in exceptioncounts:
4043 for key in exceptioncounts:
4043 combined[key] = (
4044 combined[key] = (
4044 exceptioncounts[key],
4045 exceptioncounts[key],
4045 len(testsbyfailure[key]),
4046 len(testsbyfailure[key]),
4046 leastfailing[key][0],
4047 leastfailing[key][0],
4047 leastfailing[key][1],
4048 leastfailing[key][1],
4048 )
4049 )
4049
4050
4050 return {
4051 return {
4051 'exceptioncounts': exceptioncounts,
4052 'exceptioncounts': exceptioncounts,
4052 'total': sum(exceptioncounts.values()),
4053 'total': sum(exceptioncounts.values()),
4053 'combined': combined,
4054 'combined': combined,
4054 'leastfailing': leastfailing,
4055 'leastfailing': leastfailing,
4055 'byfailure': testsbyfailure,
4056 'byfailure': testsbyfailure,
4056 'bytest': failuresbytest,
4057 'bytest': failuresbytest,
4057 }
4058 }
4058
4059
4059
4060
4060 if __name__ == '__main__':
4061 if __name__ == '__main__':
4061 if WINDOWS and not os.getenv('MSYSTEM'):
4062 if WINDOWS and not os.getenv('MSYSTEM'):
4062 print('cannot run test on Windows without MSYSTEM', file=sys.stderr)
4063 print('cannot run test on Windows without MSYSTEM', file=sys.stderr)
4063 print(
4064 print(
4064 '(if you need to do so contact the mercurial devs: '
4065 '(if you need to do so contact the mercurial devs: '
4065 'mercurial@mercurial-scm.org)',
4066 'mercurial@mercurial-scm.org)',
4066 file=sys.stderr,
4067 file=sys.stderr,
4067 )
4068 )
4068 sys.exit(255)
4069 sys.exit(255)
4069
4070
4070 runner = TestRunner()
4071 runner = TestRunner()
4071
4072
4072 try:
4073 try:
4073 import msvcrt
4074 import msvcrt
4074
4075
4075 msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
4076 msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
4076 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
4077 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
4077 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
4078 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
4078 except ImportError:
4079 except ImportError:
4079 pass
4080 pass
4080
4081
4081 sys.exit(runner.run(sys.argv[1:]))
4082 sys.exit(runner.run(sys.argv[1:]))
General Comments 0
You need to be logged in to leave comments. Login now