##// END OF EJS Templates
merge with stable
Pulkit Goyal -
r45152:e147748f merge default
parent child Browse files
Show More
@@ -1,195 +1,196 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,208 +1,209 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
@@ -1,2644 +1,2644 b''
1 # histedit.py - interactive history editing for mercurial
1 # histedit.py - interactive history editing for mercurial
2 #
2 #
3 # Copyright 2009 Augie Fackler <raf@durin42.com>
3 # Copyright 2009 Augie Fackler <raf@durin42.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 """interactive history editing
7 """interactive history editing
8
8
9 With this extension installed, Mercurial gains one new command: histedit. Usage
9 With this extension installed, Mercurial gains one new command: histedit. Usage
10 is as follows, assuming the following history::
10 is as follows, assuming the following history::
11
11
12 @ 3[tip] 7c2fd3b9020c 2009-04-27 18:04 -0500 durin42
12 @ 3[tip] 7c2fd3b9020c 2009-04-27 18:04 -0500 durin42
13 | Add delta
13 | Add delta
14 |
14 |
15 o 2 030b686bedc4 2009-04-27 18:04 -0500 durin42
15 o 2 030b686bedc4 2009-04-27 18:04 -0500 durin42
16 | Add gamma
16 | Add gamma
17 |
17 |
18 o 1 c561b4e977df 2009-04-27 18:04 -0500 durin42
18 o 1 c561b4e977df 2009-04-27 18:04 -0500 durin42
19 | Add beta
19 | Add beta
20 |
20 |
21 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
21 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
22 Add alpha
22 Add alpha
23
23
24 If you were to run ``hg histedit c561b4e977df``, you would see the following
24 If you were to run ``hg histedit c561b4e977df``, you would see the following
25 file open in your editor::
25 file open in your editor::
26
26
27 pick c561b4e977df Add beta
27 pick c561b4e977df Add beta
28 pick 030b686bedc4 Add gamma
28 pick 030b686bedc4 Add gamma
29 pick 7c2fd3b9020c Add delta
29 pick 7c2fd3b9020c Add delta
30
30
31 # Edit history between c561b4e977df and 7c2fd3b9020c
31 # Edit history between c561b4e977df and 7c2fd3b9020c
32 #
32 #
33 # Commits are listed from least to most recent
33 # Commits are listed from least to most recent
34 #
34 #
35 # Commands:
35 # Commands:
36 # p, pick = use commit
36 # p, pick = use commit
37 # e, edit = use commit, but stop for amending
37 # e, edit = use commit, but stop for amending
38 # f, fold = use commit, but combine it with the one above
38 # f, fold = use commit, but combine it with the one above
39 # r, roll = like fold, but discard this commit's description and date
39 # r, roll = like fold, but discard this commit's description and date
40 # d, drop = remove commit from history
40 # d, drop = remove commit from history
41 # m, mess = edit commit message without changing commit content
41 # m, mess = edit commit message without changing commit content
42 # b, base = checkout changeset and apply further changesets from there
42 # b, base = checkout changeset and apply further changesets from there
43 #
43 #
44
44
45 In this file, lines beginning with ``#`` are ignored. You must specify a rule
45 In this file, lines beginning with ``#`` are ignored. You must specify a rule
46 for each revision in your history. For example, if you had meant to add gamma
46 for each revision in your history. For example, if you had meant to add gamma
47 before beta, and then wanted to add delta in the same revision as beta, you
47 before beta, and then wanted to add delta in the same revision as beta, you
48 would reorganize the file to look like this::
48 would reorganize the file to look like this::
49
49
50 pick 030b686bedc4 Add gamma
50 pick 030b686bedc4 Add gamma
51 pick c561b4e977df Add beta
51 pick c561b4e977df Add beta
52 fold 7c2fd3b9020c Add delta
52 fold 7c2fd3b9020c Add delta
53
53
54 # Edit history between c561b4e977df and 7c2fd3b9020c
54 # Edit history between c561b4e977df and 7c2fd3b9020c
55 #
55 #
56 # Commits are listed from least to most recent
56 # Commits are listed from least to most recent
57 #
57 #
58 # Commands:
58 # Commands:
59 # p, pick = use commit
59 # p, pick = use commit
60 # e, edit = use commit, but stop for amending
60 # e, edit = use commit, but stop for amending
61 # f, fold = use commit, but combine it with the one above
61 # f, fold = use commit, but combine it with the one above
62 # r, roll = like fold, but discard this commit's description and date
62 # r, roll = like fold, but discard this commit's description and date
63 # d, drop = remove commit from history
63 # d, drop = remove commit from history
64 # m, mess = edit commit message without changing commit content
64 # m, mess = edit commit message without changing commit content
65 # b, base = checkout changeset and apply further changesets from there
65 # b, base = checkout changeset and apply further changesets from there
66 #
66 #
67
67
68 At which point you close the editor and ``histedit`` starts working. When you
68 At which point you close the editor and ``histedit`` starts working. When you
69 specify a ``fold`` operation, ``histedit`` will open an editor when it folds
69 specify a ``fold`` operation, ``histedit`` will open an editor when it folds
70 those revisions together, offering you a chance to clean up the commit message::
70 those revisions together, offering you a chance to clean up the commit message::
71
71
72 Add beta
72 Add beta
73 ***
73 ***
74 Add delta
74 Add delta
75
75
76 Edit the commit message to your liking, then close the editor. The date used
76 Edit the commit message to your liking, then close the editor. The date used
77 for the commit will be the later of the two commits' dates. For this example,
77 for the commit will be the later of the two commits' dates. For this example,
78 let's assume that the commit message was changed to ``Add beta and delta.``
78 let's assume that the commit message was changed to ``Add beta and delta.``
79 After histedit has run and had a chance to remove any old or temporary
79 After histedit has run and had a chance to remove any old or temporary
80 revisions it needed, the history looks like this::
80 revisions it needed, the history looks like this::
81
81
82 @ 2[tip] 989b4d060121 2009-04-27 18:04 -0500 durin42
82 @ 2[tip] 989b4d060121 2009-04-27 18:04 -0500 durin42
83 | Add beta and delta.
83 | Add beta and delta.
84 |
84 |
85 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
85 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
86 | Add gamma
86 | Add gamma
87 |
87 |
88 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
88 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
89 Add alpha
89 Add alpha
90
90
91 Note that ``histedit`` does *not* remove any revisions (even its own temporary
91 Note that ``histedit`` does *not* remove any revisions (even its own temporary
92 ones) until after it has completed all the editing operations, so it will
92 ones) until after it has completed all the editing operations, so it will
93 probably perform several strip operations when it's done. For the above example,
93 probably perform several strip operations when it's done. For the above example,
94 it had to run strip twice. Strip can be slow depending on a variety of factors,
94 it had to run strip twice. Strip can be slow depending on a variety of factors,
95 so you might need to be a little patient. You can choose to keep the original
95 so you might need to be a little patient. You can choose to keep the original
96 revisions by passing the ``--keep`` flag.
96 revisions by passing the ``--keep`` flag.
97
97
98 The ``edit`` operation will drop you back to a command prompt,
98 The ``edit`` operation will drop you back to a command prompt,
99 allowing you to edit files freely, or even use ``hg record`` to commit
99 allowing you to edit files freely, or even use ``hg record`` to commit
100 some changes as a separate commit. When you're done, any remaining
100 some changes as a separate commit. When you're done, any remaining
101 uncommitted changes will be committed as well. When done, run ``hg
101 uncommitted changes will be committed as well. When done, run ``hg
102 histedit --continue`` to finish this step. If there are uncommitted
102 histedit --continue`` to finish this step. If there are uncommitted
103 changes, you'll be prompted for a new commit message, but the default
103 changes, you'll be prompted for a new commit message, but the default
104 commit message will be the original message for the ``edit`` ed
104 commit message will be the original message for the ``edit`` ed
105 revision, and the date of the original commit will be preserved.
105 revision, and the date of the original commit will be preserved.
106
106
107 The ``message`` operation will give you a chance to revise a commit
107 The ``message`` operation will give you a chance to revise a commit
108 message without changing the contents. It's a shortcut for doing
108 message without changing the contents. It's a shortcut for doing
109 ``edit`` immediately followed by `hg histedit --continue``.
109 ``edit`` immediately followed by `hg histedit --continue``.
110
110
111 If ``histedit`` encounters a conflict when moving a revision (while
111 If ``histedit`` encounters a conflict when moving a revision (while
112 handling ``pick`` or ``fold``), it'll stop in a similar manner to
112 handling ``pick`` or ``fold``), it'll stop in a similar manner to
113 ``edit`` with the difference that it won't prompt you for a commit
113 ``edit`` with the difference that it won't prompt you for a commit
114 message when done. If you decide at this point that you don't like how
114 message when done. If you decide at this point that you don't like how
115 much work it will be to rearrange history, or that you made a mistake,
115 much work it will be to rearrange history, or that you made a mistake,
116 you can use ``hg histedit --abort`` to abandon the new changes you
116 you can use ``hg histedit --abort`` to abandon the new changes you
117 have made and return to the state before you attempted to edit your
117 have made and return to the state before you attempted to edit your
118 history.
118 history.
119
119
120 If we clone the histedit-ed example repository above and add four more
120 If we clone the histedit-ed example repository above and add four more
121 changes, such that we have the following history::
121 changes, such that we have the following history::
122
122
123 @ 6[tip] 038383181893 2009-04-27 18:04 -0500 stefan
123 @ 6[tip] 038383181893 2009-04-27 18:04 -0500 stefan
124 | Add theta
124 | Add theta
125 |
125 |
126 o 5 140988835471 2009-04-27 18:04 -0500 stefan
126 o 5 140988835471 2009-04-27 18:04 -0500 stefan
127 | Add eta
127 | Add eta
128 |
128 |
129 o 4 122930637314 2009-04-27 18:04 -0500 stefan
129 o 4 122930637314 2009-04-27 18:04 -0500 stefan
130 | Add zeta
130 | Add zeta
131 |
131 |
132 o 3 836302820282 2009-04-27 18:04 -0500 stefan
132 o 3 836302820282 2009-04-27 18:04 -0500 stefan
133 | Add epsilon
133 | Add epsilon
134 |
134 |
135 o 2 989b4d060121 2009-04-27 18:04 -0500 durin42
135 o 2 989b4d060121 2009-04-27 18:04 -0500 durin42
136 | Add beta and delta.
136 | Add beta and delta.
137 |
137 |
138 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
138 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
139 | Add gamma
139 | Add gamma
140 |
140 |
141 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
141 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
142 Add alpha
142 Add alpha
143
143
144 If you run ``hg histedit --outgoing`` on the clone then it is the same
144 If you run ``hg histedit --outgoing`` on the clone then it is the same
145 as running ``hg histedit 836302820282``. If you need plan to push to a
145 as running ``hg histedit 836302820282``. If you need plan to push to a
146 repository that Mercurial does not detect to be related to the source
146 repository that Mercurial does not detect to be related to the source
147 repo, you can add a ``--force`` option.
147 repo, you can add a ``--force`` option.
148
148
149 Config
149 Config
150 ------
150 ------
151
151
152 Histedit rule lines are truncated to 80 characters by default. You
152 Histedit rule lines are truncated to 80 characters by default. You
153 can customize this behavior by setting a different length in your
153 can customize this behavior by setting a different length in your
154 configuration file::
154 configuration file::
155
155
156 [histedit]
156 [histedit]
157 linelen = 120 # truncate rule lines at 120 characters
157 linelen = 120 # truncate rule lines at 120 characters
158
158
159 The summary of a change can be customized as well::
159 The summary of a change can be customized as well::
160
160
161 [histedit]
161 [histedit]
162 summary-template = '{rev} {bookmarks} {desc|firstline}'
162 summary-template = '{rev} {bookmarks} {desc|firstline}'
163
163
164 The customized summary should be kept short enough that rule lines
164 The customized summary should be kept short enough that rule lines
165 will fit in the configured line length. See above if that requires
165 will fit in the configured line length. See above if that requires
166 customization.
166 customization.
167
167
168 ``hg histedit`` attempts to automatically choose an appropriate base
168 ``hg histedit`` attempts to automatically choose an appropriate base
169 revision to use. To change which base revision is used, define a
169 revision to use. To change which base revision is used, define a
170 revset in your configuration file::
170 revset in your configuration file::
171
171
172 [histedit]
172 [histedit]
173 defaultrev = only(.) & draft()
173 defaultrev = only(.) & draft()
174
174
175 By default each edited revision needs to be present in histedit commands.
175 By default each edited revision needs to be present in histedit commands.
176 To remove revision you need to use ``drop`` operation. You can configure
176 To remove revision you need to use ``drop`` operation. You can configure
177 the drop to be implicit for missing commits by adding::
177 the drop to be implicit for missing commits by adding::
178
178
179 [histedit]
179 [histedit]
180 dropmissing = True
180 dropmissing = True
181
181
182 By default, histedit will close the transaction after each action. For
182 By default, histedit will close the transaction after each action. For
183 performance purposes, you can configure histedit to use a single transaction
183 performance purposes, you can configure histedit to use a single transaction
184 across the entire histedit. WARNING: This setting introduces a significant risk
184 across the entire histedit. WARNING: This setting introduces a significant risk
185 of losing the work you've done in a histedit if the histedit aborts
185 of losing the work you've done in a histedit if the histedit aborts
186 unexpectedly::
186 unexpectedly::
187
187
188 [histedit]
188 [histedit]
189 singletransaction = True
189 singletransaction = True
190
190
191 """
191 """
192
192
193 from __future__ import absolute_import
193 from __future__ import absolute_import
194
194
195 # chistedit dependencies that are not available everywhere
195 # chistedit dependencies that are not available everywhere
196 try:
196 try:
197 import fcntl
197 import fcntl
198 import termios
198 import termios
199 except ImportError:
199 except ImportError:
200 fcntl = None
200 fcntl = None
201 termios = None
201 termios = None
202
202
203 import functools
203 import functools
204 import locale
204 import locale
205 import os
205 import os
206 import struct
206 import struct
207
207
208 from mercurial.i18n import _
208 from mercurial.i18n import _
209 from mercurial.pycompat import (
209 from mercurial.pycompat import (
210 getattr,
210 getattr,
211 open,
211 open,
212 )
212 )
213 from mercurial import (
213 from mercurial import (
214 bundle2,
214 bundle2,
215 cmdutil,
215 cmdutil,
216 context,
216 context,
217 copies,
217 copies,
218 destutil,
218 destutil,
219 discovery,
219 discovery,
220 encoding,
220 encoding,
221 error,
221 error,
222 exchange,
222 exchange,
223 extensions,
223 extensions,
224 hg,
224 hg,
225 logcmdutil,
225 logcmdutil,
226 merge as mergemod,
226 merge as mergemod,
227 mergeutil,
227 mergeutil,
228 node,
228 node,
229 obsolete,
229 obsolete,
230 pycompat,
230 pycompat,
231 registrar,
231 registrar,
232 repair,
232 repair,
233 rewriteutil,
233 rewriteutil,
234 scmutil,
234 scmutil,
235 state as statemod,
235 state as statemod,
236 util,
236 util,
237 )
237 )
238 from mercurial.utils import (
238 from mercurial.utils import (
239 dateutil,
239 dateutil,
240 stringutil,
240 stringutil,
241 )
241 )
242
242
243 pickle = util.pickle
243 pickle = util.pickle
244 cmdtable = {}
244 cmdtable = {}
245 command = registrar.command(cmdtable)
245 command = registrar.command(cmdtable)
246
246
247 configtable = {}
247 configtable = {}
248 configitem = registrar.configitem(configtable)
248 configitem = registrar.configitem(configtable)
249 configitem(
249 configitem(
250 b'experimental', b'histedit.autoverb', default=False,
250 b'experimental', b'histedit.autoverb', default=False,
251 )
251 )
252 configitem(
252 configitem(
253 b'histedit', b'defaultrev', default=None,
253 b'histedit', b'defaultrev', default=None,
254 )
254 )
255 configitem(
255 configitem(
256 b'histedit', b'dropmissing', default=False,
256 b'histedit', b'dropmissing', default=False,
257 )
257 )
258 configitem(
258 configitem(
259 b'histedit', b'linelen', default=80,
259 b'histedit', b'linelen', default=80,
260 )
260 )
261 configitem(
261 configitem(
262 b'histedit', b'singletransaction', default=False,
262 b'histedit', b'singletransaction', default=False,
263 )
263 )
264 configitem(
264 configitem(
265 b'ui', b'interface.histedit', default=None,
265 b'ui', b'interface.histedit', default=None,
266 )
266 )
267 configitem(b'histedit', b'summary-template', default=b'{rev} {desc|firstline}')
267 configitem(b'histedit', b'summary-template', default=b'{rev} {desc|firstline}')
268
268
269 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
269 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
270 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
270 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
271 # be specifying the version(s) of Mercurial they are tested with, or
271 # be specifying the version(s) of Mercurial they are tested with, or
272 # leave the attribute unspecified.
272 # leave the attribute unspecified.
273 testedwith = b'ships-with-hg-core'
273 testedwith = b'ships-with-hg-core'
274
274
275 actiontable = {}
275 actiontable = {}
276 primaryactions = set()
276 primaryactions = set()
277 secondaryactions = set()
277 secondaryactions = set()
278 tertiaryactions = set()
278 tertiaryactions = set()
279 internalactions = set()
279 internalactions = set()
280
280
281
281
282 def geteditcomment(ui, first, last):
282 def geteditcomment(ui, first, last):
283 """ construct the editor comment
283 """ construct the editor comment
284 The comment includes::
284 The comment includes::
285 - an intro
285 - an intro
286 - sorted primary commands
286 - sorted primary commands
287 - sorted short commands
287 - sorted short commands
288 - sorted long commands
288 - sorted long commands
289 - additional hints
289 - additional hints
290
290
291 Commands are only included once.
291 Commands are only included once.
292 """
292 """
293 intro = _(
293 intro = _(
294 """Edit history between %s and %s
294 b"""Edit history between %s and %s
295
295
296 Commits are listed from least to most recent
296 Commits are listed from least to most recent
297
297
298 You can reorder changesets by reordering the lines
298 You can reorder changesets by reordering the lines
299
299
300 Commands:
300 Commands:
301 """
301 """
302 )
302 )
303 actions = []
303 actions = []
304
304
305 def addverb(v):
305 def addverb(v):
306 a = actiontable[v]
306 a = actiontable[v]
307 lines = a.message.split(b"\n")
307 lines = a.message.split(b"\n")
308 if len(a.verbs):
308 if len(a.verbs):
309 v = b', '.join(sorted(a.verbs, key=lambda v: len(v)))
309 v = b', '.join(sorted(a.verbs, key=lambda v: len(v)))
310 actions.append(b" %s = %s" % (v, lines[0]))
310 actions.append(b" %s = %s" % (v, lines[0]))
311 actions.extend([b' %s'] * (len(lines) - 1))
311 actions.extend([b' %s'] * (len(lines) - 1))
312
312
313 for v in (
313 for v in (
314 sorted(primaryactions)
314 sorted(primaryactions)
315 + sorted(secondaryactions)
315 + sorted(secondaryactions)
316 + sorted(tertiaryactions)
316 + sorted(tertiaryactions)
317 ):
317 ):
318 addverb(v)
318 addverb(v)
319 actions.append(b'')
319 actions.append(b'')
320
320
321 hints = []
321 hints = []
322 if ui.configbool(b'histedit', b'dropmissing'):
322 if ui.configbool(b'histedit', b'dropmissing'):
323 hints.append(
323 hints.append(
324 b"Deleting a changeset from the list "
324 b"Deleting a changeset from the list "
325 b"will DISCARD it from the edited history!"
325 b"will DISCARD it from the edited history!"
326 )
326 )
327
327
328 lines = (intro % (first, last)).split(b'\n') + actions + hints
328 lines = (intro % (first, last)).split(b'\n') + actions + hints
329
329
330 return b''.join([b'# %s\n' % l if l else b'#\n' for l in lines])
330 return b''.join([b'# %s\n' % l if l else b'#\n' for l in lines])
331
331
332
332
333 class histeditstate(object):
333 class histeditstate(object):
334 def __init__(self, repo):
334 def __init__(self, repo):
335 self.repo = repo
335 self.repo = repo
336 self.actions = None
336 self.actions = None
337 self.keep = None
337 self.keep = None
338 self.topmost = None
338 self.topmost = None
339 self.parentctxnode = None
339 self.parentctxnode = None
340 self.lock = None
340 self.lock = None
341 self.wlock = None
341 self.wlock = None
342 self.backupfile = None
342 self.backupfile = None
343 self.stateobj = statemod.cmdstate(repo, b'histedit-state')
343 self.stateobj = statemod.cmdstate(repo, b'histedit-state')
344 self.replacements = []
344 self.replacements = []
345
345
346 def read(self):
346 def read(self):
347 """Load histedit state from disk and set fields appropriately."""
347 """Load histedit state from disk and set fields appropriately."""
348 if not self.stateobj.exists():
348 if not self.stateobj.exists():
349 cmdutil.wrongtooltocontinue(self.repo, _(b'histedit'))
349 cmdutil.wrongtooltocontinue(self.repo, _(b'histedit'))
350
350
351 data = self._read()
351 data = self._read()
352
352
353 self.parentctxnode = data[b'parentctxnode']
353 self.parentctxnode = data[b'parentctxnode']
354 actions = parserules(data[b'rules'], self)
354 actions = parserules(data[b'rules'], self)
355 self.actions = actions
355 self.actions = actions
356 self.keep = data[b'keep']
356 self.keep = data[b'keep']
357 self.topmost = data[b'topmost']
357 self.topmost = data[b'topmost']
358 self.replacements = data[b'replacements']
358 self.replacements = data[b'replacements']
359 self.backupfile = data[b'backupfile']
359 self.backupfile = data[b'backupfile']
360
360
361 def _read(self):
361 def _read(self):
362 fp = self.repo.vfs.read(b'histedit-state')
362 fp = self.repo.vfs.read(b'histedit-state')
363 if fp.startswith(b'v1\n'):
363 if fp.startswith(b'v1\n'):
364 data = self._load()
364 data = self._load()
365 parentctxnode, rules, keep, topmost, replacements, backupfile = data
365 parentctxnode, rules, keep, topmost, replacements, backupfile = data
366 else:
366 else:
367 data = pickle.loads(fp)
367 data = pickle.loads(fp)
368 parentctxnode, rules, keep, topmost, replacements = data
368 parentctxnode, rules, keep, topmost, replacements = data
369 backupfile = None
369 backupfile = None
370 rules = b"\n".join([b"%s %s" % (verb, rest) for [verb, rest] in rules])
370 rules = b"\n".join([b"%s %s" % (verb, rest) for [verb, rest] in rules])
371
371
372 return {
372 return {
373 b'parentctxnode': parentctxnode,
373 b'parentctxnode': parentctxnode,
374 b"rules": rules,
374 b"rules": rules,
375 b"keep": keep,
375 b"keep": keep,
376 b"topmost": topmost,
376 b"topmost": topmost,
377 b"replacements": replacements,
377 b"replacements": replacements,
378 b"backupfile": backupfile,
378 b"backupfile": backupfile,
379 }
379 }
380
380
381 def write(self, tr=None):
381 def write(self, tr=None):
382 if tr:
382 if tr:
383 tr.addfilegenerator(
383 tr.addfilegenerator(
384 b'histedit-state',
384 b'histedit-state',
385 (b'histedit-state',),
385 (b'histedit-state',),
386 self._write,
386 self._write,
387 location=b'plain',
387 location=b'plain',
388 )
388 )
389 else:
389 else:
390 with self.repo.vfs(b"histedit-state", b"w") as f:
390 with self.repo.vfs(b"histedit-state", b"w") as f:
391 self._write(f)
391 self._write(f)
392
392
393 def _write(self, fp):
393 def _write(self, fp):
394 fp.write(b'v1\n')
394 fp.write(b'v1\n')
395 fp.write(b'%s\n' % node.hex(self.parentctxnode))
395 fp.write(b'%s\n' % node.hex(self.parentctxnode))
396 fp.write(b'%s\n' % node.hex(self.topmost))
396 fp.write(b'%s\n' % node.hex(self.topmost))
397 fp.write(b'%s\n' % (b'True' if self.keep else b'False'))
397 fp.write(b'%s\n' % (b'True' if self.keep else b'False'))
398 fp.write(b'%d\n' % len(self.actions))
398 fp.write(b'%d\n' % len(self.actions))
399 for action in self.actions:
399 for action in self.actions:
400 fp.write(b'%s\n' % action.tostate())
400 fp.write(b'%s\n' % action.tostate())
401 fp.write(b'%d\n' % len(self.replacements))
401 fp.write(b'%d\n' % len(self.replacements))
402 for replacement in self.replacements:
402 for replacement in self.replacements:
403 fp.write(
403 fp.write(
404 b'%s%s\n'
404 b'%s%s\n'
405 % (
405 % (
406 node.hex(replacement[0]),
406 node.hex(replacement[0]),
407 b''.join(node.hex(r) for r in replacement[1]),
407 b''.join(node.hex(r) for r in replacement[1]),
408 )
408 )
409 )
409 )
410 backupfile = self.backupfile
410 backupfile = self.backupfile
411 if not backupfile:
411 if not backupfile:
412 backupfile = b''
412 backupfile = b''
413 fp.write(b'%s\n' % backupfile)
413 fp.write(b'%s\n' % backupfile)
414
414
415 def _load(self):
415 def _load(self):
416 fp = self.repo.vfs(b'histedit-state', b'r')
416 fp = self.repo.vfs(b'histedit-state', b'r')
417 lines = [l[:-1] for l in fp.readlines()]
417 lines = [l[:-1] for l in fp.readlines()]
418
418
419 index = 0
419 index = 0
420 lines[index] # version number
420 lines[index] # version number
421 index += 1
421 index += 1
422
422
423 parentctxnode = node.bin(lines[index])
423 parentctxnode = node.bin(lines[index])
424 index += 1
424 index += 1
425
425
426 topmost = node.bin(lines[index])
426 topmost = node.bin(lines[index])
427 index += 1
427 index += 1
428
428
429 keep = lines[index] == b'True'
429 keep = lines[index] == b'True'
430 index += 1
430 index += 1
431
431
432 # Rules
432 # Rules
433 rules = []
433 rules = []
434 rulelen = int(lines[index])
434 rulelen = int(lines[index])
435 index += 1
435 index += 1
436 for i in pycompat.xrange(rulelen):
436 for i in pycompat.xrange(rulelen):
437 ruleaction = lines[index]
437 ruleaction = lines[index]
438 index += 1
438 index += 1
439 rule = lines[index]
439 rule = lines[index]
440 index += 1
440 index += 1
441 rules.append((ruleaction, rule))
441 rules.append((ruleaction, rule))
442
442
443 # Replacements
443 # Replacements
444 replacements = []
444 replacements = []
445 replacementlen = int(lines[index])
445 replacementlen = int(lines[index])
446 index += 1
446 index += 1
447 for i in pycompat.xrange(replacementlen):
447 for i in pycompat.xrange(replacementlen):
448 replacement = lines[index]
448 replacement = lines[index]
449 original = node.bin(replacement[:40])
449 original = node.bin(replacement[:40])
450 succ = [
450 succ = [
451 node.bin(replacement[i : i + 40])
451 node.bin(replacement[i : i + 40])
452 for i in range(40, len(replacement), 40)
452 for i in range(40, len(replacement), 40)
453 ]
453 ]
454 replacements.append((original, succ))
454 replacements.append((original, succ))
455 index += 1
455 index += 1
456
456
457 backupfile = lines[index]
457 backupfile = lines[index]
458 index += 1
458 index += 1
459
459
460 fp.close()
460 fp.close()
461
461
462 return parentctxnode, rules, keep, topmost, replacements, backupfile
462 return parentctxnode, rules, keep, topmost, replacements, backupfile
463
463
464 def clear(self):
464 def clear(self):
465 if self.inprogress():
465 if self.inprogress():
466 self.repo.vfs.unlink(b'histedit-state')
466 self.repo.vfs.unlink(b'histedit-state')
467
467
468 def inprogress(self):
468 def inprogress(self):
469 return self.repo.vfs.exists(b'histedit-state')
469 return self.repo.vfs.exists(b'histedit-state')
470
470
471
471
472 class histeditaction(object):
472 class histeditaction(object):
473 def __init__(self, state, node):
473 def __init__(self, state, node):
474 self.state = state
474 self.state = state
475 self.repo = state.repo
475 self.repo = state.repo
476 self.node = node
476 self.node = node
477
477
478 @classmethod
478 @classmethod
479 def fromrule(cls, state, rule):
479 def fromrule(cls, state, rule):
480 """Parses the given rule, returning an instance of the histeditaction.
480 """Parses the given rule, returning an instance of the histeditaction.
481 """
481 """
482 ruleid = rule.strip().split(b' ', 1)[0]
482 ruleid = rule.strip().split(b' ', 1)[0]
483 # ruleid can be anything from rev numbers, hashes, "bookmarks" etc
483 # ruleid can be anything from rev numbers, hashes, "bookmarks" etc
484 # Check for validation of rule ids and get the rulehash
484 # Check for validation of rule ids and get the rulehash
485 try:
485 try:
486 rev = node.bin(ruleid)
486 rev = node.bin(ruleid)
487 except TypeError:
487 except TypeError:
488 try:
488 try:
489 _ctx = scmutil.revsingle(state.repo, ruleid)
489 _ctx = scmutil.revsingle(state.repo, ruleid)
490 rulehash = _ctx.hex()
490 rulehash = _ctx.hex()
491 rev = node.bin(rulehash)
491 rev = node.bin(rulehash)
492 except error.RepoLookupError:
492 except error.RepoLookupError:
493 raise error.ParseError(_(b"invalid changeset %s") % ruleid)
493 raise error.ParseError(_(b"invalid changeset %s") % ruleid)
494 return cls(state, rev)
494 return cls(state, rev)
495
495
496 def verify(self, prev, expected, seen):
496 def verify(self, prev, expected, seen):
497 """ Verifies semantic correctness of the rule"""
497 """ Verifies semantic correctness of the rule"""
498 repo = self.repo
498 repo = self.repo
499 ha = node.hex(self.node)
499 ha = node.hex(self.node)
500 self.node = scmutil.resolvehexnodeidprefix(repo, ha)
500 self.node = scmutil.resolvehexnodeidprefix(repo, ha)
501 if self.node is None:
501 if self.node is None:
502 raise error.ParseError(_(b'unknown changeset %s listed') % ha[:12])
502 raise error.ParseError(_(b'unknown changeset %s listed') % ha[:12])
503 self._verifynodeconstraints(prev, expected, seen)
503 self._verifynodeconstraints(prev, expected, seen)
504
504
505 def _verifynodeconstraints(self, prev, expected, seen):
505 def _verifynodeconstraints(self, prev, expected, seen):
506 # by default command need a node in the edited list
506 # by default command need a node in the edited list
507 if self.node not in expected:
507 if self.node not in expected:
508 raise error.ParseError(
508 raise error.ParseError(
509 _(b'%s "%s" changeset was not a candidate')
509 _(b'%s "%s" changeset was not a candidate')
510 % (self.verb, node.short(self.node)),
510 % (self.verb, node.short(self.node)),
511 hint=_(b'only use listed changesets'),
511 hint=_(b'only use listed changesets'),
512 )
512 )
513 # and only one command per node
513 # and only one command per node
514 if self.node in seen:
514 if self.node in seen:
515 raise error.ParseError(
515 raise error.ParseError(
516 _(b'duplicated command for changeset %s')
516 _(b'duplicated command for changeset %s')
517 % node.short(self.node)
517 % node.short(self.node)
518 )
518 )
519
519
520 def torule(self):
520 def torule(self):
521 """build a histedit rule line for an action
521 """build a histedit rule line for an action
522
522
523 by default lines are in the form:
523 by default lines are in the form:
524 <hash> <rev> <summary>
524 <hash> <rev> <summary>
525 """
525 """
526 ctx = self.repo[self.node]
526 ctx = self.repo[self.node]
527 ui = self.repo.ui
527 ui = self.repo.ui
528 summary = (
528 summary = (
529 cmdutil.rendertemplate(
529 cmdutil.rendertemplate(
530 ctx, ui.config(b'histedit', b'summary-template')
530 ctx, ui.config(b'histedit', b'summary-template')
531 )
531 )
532 or b''
532 or b''
533 )
533 )
534 summary = summary.splitlines()[0]
534 summary = summary.splitlines()[0]
535 line = b'%s %s %s' % (self.verb, ctx, summary)
535 line = b'%s %s %s' % (self.verb, ctx, summary)
536 # trim to 75 columns by default so it's not stupidly wide in my editor
536 # trim to 75 columns by default so it's not stupidly wide in my editor
537 # (the 5 more are left for verb)
537 # (the 5 more are left for verb)
538 maxlen = self.repo.ui.configint(b'histedit', b'linelen')
538 maxlen = self.repo.ui.configint(b'histedit', b'linelen')
539 maxlen = max(maxlen, 22) # avoid truncating hash
539 maxlen = max(maxlen, 22) # avoid truncating hash
540 return stringutil.ellipsis(line, maxlen)
540 return stringutil.ellipsis(line, maxlen)
541
541
542 def tostate(self):
542 def tostate(self):
543 """Print an action in format used by histedit state files
543 """Print an action in format used by histedit state files
544 (the first line is a verb, the remainder is the second)
544 (the first line is a verb, the remainder is the second)
545 """
545 """
546 return b"%s\n%s" % (self.verb, node.hex(self.node))
546 return b"%s\n%s" % (self.verb, node.hex(self.node))
547
547
548 def run(self):
548 def run(self):
549 """Runs the action. The default behavior is simply apply the action's
549 """Runs the action. The default behavior is simply apply the action's
550 rulectx onto the current parentctx."""
550 rulectx onto the current parentctx."""
551 self.applychange()
551 self.applychange()
552 self.continuedirty()
552 self.continuedirty()
553 return self.continueclean()
553 return self.continueclean()
554
554
555 def applychange(self):
555 def applychange(self):
556 """Applies the changes from this action's rulectx onto the current
556 """Applies the changes from this action's rulectx onto the current
557 parentctx, but does not commit them."""
557 parentctx, but does not commit them."""
558 repo = self.repo
558 repo = self.repo
559 rulectx = repo[self.node]
559 rulectx = repo[self.node]
560 repo.ui.pushbuffer(error=True, labeled=True)
560 repo.ui.pushbuffer(error=True, labeled=True)
561 hg.update(repo, self.state.parentctxnode, quietempty=True)
561 hg.update(repo, self.state.parentctxnode, quietempty=True)
562 repo.ui.popbuffer()
562 repo.ui.popbuffer()
563 stats = applychanges(repo.ui, repo, rulectx, {})
563 stats = applychanges(repo.ui, repo, rulectx, {})
564 repo.dirstate.setbranch(rulectx.branch())
564 repo.dirstate.setbranch(rulectx.branch())
565 if stats.unresolvedcount:
565 if stats.unresolvedcount:
566 raise error.InterventionRequired(
566 raise error.InterventionRequired(
567 _(b'Fix up the change (%s %s)')
567 _(b'Fix up the change (%s %s)')
568 % (self.verb, node.short(self.node)),
568 % (self.verb, node.short(self.node)),
569 hint=_(b'hg histedit --continue to resume'),
569 hint=_(b'hg histedit --continue to resume'),
570 )
570 )
571
571
572 def continuedirty(self):
572 def continuedirty(self):
573 """Continues the action when changes have been applied to the working
573 """Continues the action when changes have been applied to the working
574 copy. The default behavior is to commit the dirty changes."""
574 copy. The default behavior is to commit the dirty changes."""
575 repo = self.repo
575 repo = self.repo
576 rulectx = repo[self.node]
576 rulectx = repo[self.node]
577
577
578 editor = self.commiteditor()
578 editor = self.commiteditor()
579 commit = commitfuncfor(repo, rulectx)
579 commit = commitfuncfor(repo, rulectx)
580 if repo.ui.configbool(b'rewrite', b'update-timestamp'):
580 if repo.ui.configbool(b'rewrite', b'update-timestamp'):
581 date = dateutil.makedate()
581 date = dateutil.makedate()
582 else:
582 else:
583 date = rulectx.date()
583 date = rulectx.date()
584 commit(
584 commit(
585 text=rulectx.description(),
585 text=rulectx.description(),
586 user=rulectx.user(),
586 user=rulectx.user(),
587 date=date,
587 date=date,
588 extra=rulectx.extra(),
588 extra=rulectx.extra(),
589 editor=editor,
589 editor=editor,
590 )
590 )
591
591
592 def commiteditor(self):
592 def commiteditor(self):
593 """The editor to be used to edit the commit message."""
593 """The editor to be used to edit the commit message."""
594 return False
594 return False
595
595
596 def continueclean(self):
596 def continueclean(self):
597 """Continues the action when the working copy is clean. The default
597 """Continues the action when the working copy is clean. The default
598 behavior is to accept the current commit as the new version of the
598 behavior is to accept the current commit as the new version of the
599 rulectx."""
599 rulectx."""
600 ctx = self.repo[b'.']
600 ctx = self.repo[b'.']
601 if ctx.node() == self.state.parentctxnode:
601 if ctx.node() == self.state.parentctxnode:
602 self.repo.ui.warn(
602 self.repo.ui.warn(
603 _(b'%s: skipping changeset (no changes)\n')
603 _(b'%s: skipping changeset (no changes)\n')
604 % node.short(self.node)
604 % node.short(self.node)
605 )
605 )
606 return ctx, [(self.node, tuple())]
606 return ctx, [(self.node, tuple())]
607 if ctx.node() == self.node:
607 if ctx.node() == self.node:
608 # Nothing changed
608 # Nothing changed
609 return ctx, []
609 return ctx, []
610 return ctx, [(self.node, (ctx.node(),))]
610 return ctx, [(self.node, (ctx.node(),))]
611
611
612
612
613 def commitfuncfor(repo, src):
613 def commitfuncfor(repo, src):
614 """Build a commit function for the replacement of <src>
614 """Build a commit function for the replacement of <src>
615
615
616 This function ensure we apply the same treatment to all changesets.
616 This function ensure we apply the same treatment to all changesets.
617
617
618 - Add a 'histedit_source' entry in extra.
618 - Add a 'histedit_source' entry in extra.
619
619
620 Note that fold has its own separated logic because its handling is a bit
620 Note that fold has its own separated logic because its handling is a bit
621 different and not easily factored out of the fold method.
621 different and not easily factored out of the fold method.
622 """
622 """
623 phasemin = src.phase()
623 phasemin = src.phase()
624
624
625 def commitfunc(**kwargs):
625 def commitfunc(**kwargs):
626 overrides = {(b'phases', b'new-commit'): phasemin}
626 overrides = {(b'phases', b'new-commit'): phasemin}
627 with repo.ui.configoverride(overrides, b'histedit'):
627 with repo.ui.configoverride(overrides, b'histedit'):
628 extra = kwargs.get('extra', {}).copy()
628 extra = kwargs.get('extra', {}).copy()
629 extra[b'histedit_source'] = src.hex()
629 extra[b'histedit_source'] = src.hex()
630 kwargs['extra'] = extra
630 kwargs['extra'] = extra
631 return repo.commit(**kwargs)
631 return repo.commit(**kwargs)
632
632
633 return commitfunc
633 return commitfunc
634
634
635
635
636 def applychanges(ui, repo, ctx, opts):
636 def applychanges(ui, repo, ctx, opts):
637 """Merge changeset from ctx (only) in the current working directory"""
637 """Merge changeset from ctx (only) in the current working directory"""
638 wcpar = repo.dirstate.p1()
638 wcpar = repo.dirstate.p1()
639 if ctx.p1().node() == wcpar:
639 if ctx.p1().node() == wcpar:
640 # edits are "in place" we do not need to make any merge,
640 # edits are "in place" we do not need to make any merge,
641 # just applies changes on parent for editing
641 # just applies changes on parent for editing
642 ui.pushbuffer()
642 ui.pushbuffer()
643 cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True)
643 cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True)
644 stats = mergemod.updateresult(0, 0, 0, 0)
644 stats = mergemod.updateresult(0, 0, 0, 0)
645 ui.popbuffer()
645 ui.popbuffer()
646 else:
646 else:
647 try:
647 try:
648 # ui.forcemerge is an internal variable, do not document
648 # ui.forcemerge is an internal variable, do not document
649 repo.ui.setconfig(
649 repo.ui.setconfig(
650 b'ui', b'forcemerge', opts.get(b'tool', b''), b'histedit'
650 b'ui', b'forcemerge', opts.get(b'tool', b''), b'histedit'
651 )
651 )
652 stats = mergemod.graft(repo, ctx, labels=[b'local', b'histedit'])
652 stats = mergemod.graft(repo, ctx, labels=[b'local', b'histedit'])
653 finally:
653 finally:
654 repo.ui.setconfig(b'ui', b'forcemerge', b'', b'histedit')
654 repo.ui.setconfig(b'ui', b'forcemerge', b'', b'histedit')
655 return stats
655 return stats
656
656
657
657
658 def collapse(repo, firstctx, lastctx, commitopts, skipprompt=False):
658 def collapse(repo, firstctx, lastctx, commitopts, skipprompt=False):
659 """collapse the set of revisions from first to last as new one.
659 """collapse the set of revisions from first to last as new one.
660
660
661 Expected commit options are:
661 Expected commit options are:
662 - message
662 - message
663 - date
663 - date
664 - username
664 - username
665 Commit message is edited in all cases.
665 Commit message is edited in all cases.
666
666
667 This function works in memory."""
667 This function works in memory."""
668 ctxs = list(repo.set(b'%d::%d', firstctx.rev(), lastctx.rev()))
668 ctxs = list(repo.set(b'%d::%d', firstctx.rev(), lastctx.rev()))
669 if not ctxs:
669 if not ctxs:
670 return None
670 return None
671 for c in ctxs:
671 for c in ctxs:
672 if not c.mutable():
672 if not c.mutable():
673 raise error.ParseError(
673 raise error.ParseError(
674 _(b"cannot fold into public change %s") % node.short(c.node())
674 _(b"cannot fold into public change %s") % node.short(c.node())
675 )
675 )
676 base = firstctx.p1()
676 base = firstctx.p1()
677
677
678 # commit a new version of the old changeset, including the update
678 # commit a new version of the old changeset, including the update
679 # collect all files which might be affected
679 # collect all files which might be affected
680 files = set()
680 files = set()
681 for ctx in ctxs:
681 for ctx in ctxs:
682 files.update(ctx.files())
682 files.update(ctx.files())
683
683
684 # Recompute copies (avoid recording a -> b -> a)
684 # Recompute copies (avoid recording a -> b -> a)
685 copied = copies.pathcopies(base, lastctx)
685 copied = copies.pathcopies(base, lastctx)
686
686
687 # prune files which were reverted by the updates
687 # prune files which were reverted by the updates
688 files = [f for f in files if not cmdutil.samefile(f, lastctx, base)]
688 files = [f for f in files if not cmdutil.samefile(f, lastctx, base)]
689 # commit version of these files as defined by head
689 # commit version of these files as defined by head
690 headmf = lastctx.manifest()
690 headmf = lastctx.manifest()
691
691
692 def filectxfn(repo, ctx, path):
692 def filectxfn(repo, ctx, path):
693 if path in headmf:
693 if path in headmf:
694 fctx = lastctx[path]
694 fctx = lastctx[path]
695 flags = fctx.flags()
695 flags = fctx.flags()
696 mctx = context.memfilectx(
696 mctx = context.memfilectx(
697 repo,
697 repo,
698 ctx,
698 ctx,
699 fctx.path(),
699 fctx.path(),
700 fctx.data(),
700 fctx.data(),
701 islink=b'l' in flags,
701 islink=b'l' in flags,
702 isexec=b'x' in flags,
702 isexec=b'x' in flags,
703 copysource=copied.get(path),
703 copysource=copied.get(path),
704 )
704 )
705 return mctx
705 return mctx
706 return None
706 return None
707
707
708 if commitopts.get(b'message'):
708 if commitopts.get(b'message'):
709 message = commitopts[b'message']
709 message = commitopts[b'message']
710 else:
710 else:
711 message = firstctx.description()
711 message = firstctx.description()
712 user = commitopts.get(b'user')
712 user = commitopts.get(b'user')
713 date = commitopts.get(b'date')
713 date = commitopts.get(b'date')
714 extra = commitopts.get(b'extra')
714 extra = commitopts.get(b'extra')
715
715
716 parents = (firstctx.p1().node(), firstctx.p2().node())
716 parents = (firstctx.p1().node(), firstctx.p2().node())
717 editor = None
717 editor = None
718 if not skipprompt:
718 if not skipprompt:
719 editor = cmdutil.getcommiteditor(edit=True, editform=b'histedit.fold')
719 editor = cmdutil.getcommiteditor(edit=True, editform=b'histedit.fold')
720 new = context.memctx(
720 new = context.memctx(
721 repo,
721 repo,
722 parents=parents,
722 parents=parents,
723 text=message,
723 text=message,
724 files=files,
724 files=files,
725 filectxfn=filectxfn,
725 filectxfn=filectxfn,
726 user=user,
726 user=user,
727 date=date,
727 date=date,
728 extra=extra,
728 extra=extra,
729 editor=editor,
729 editor=editor,
730 )
730 )
731 return repo.commitctx(new)
731 return repo.commitctx(new)
732
732
733
733
734 def _isdirtywc(repo):
734 def _isdirtywc(repo):
735 return repo[None].dirty(missing=True)
735 return repo[None].dirty(missing=True)
736
736
737
737
738 def abortdirty():
738 def abortdirty():
739 raise error.Abort(
739 raise error.Abort(
740 _(b'working copy has pending changes'),
740 _(b'working copy has pending changes'),
741 hint=_(
741 hint=_(
742 b'amend, commit, or revert them and run histedit '
742 b'amend, commit, or revert them and run histedit '
743 b'--continue, or abort with histedit --abort'
743 b'--continue, or abort with histedit --abort'
744 ),
744 ),
745 )
745 )
746
746
747
747
748 def action(verbs, message, priority=False, internal=False):
748 def action(verbs, message, priority=False, internal=False):
749 def wrap(cls):
749 def wrap(cls):
750 assert not priority or not internal
750 assert not priority or not internal
751 verb = verbs[0]
751 verb = verbs[0]
752 if priority:
752 if priority:
753 primaryactions.add(verb)
753 primaryactions.add(verb)
754 elif internal:
754 elif internal:
755 internalactions.add(verb)
755 internalactions.add(verb)
756 elif len(verbs) > 1:
756 elif len(verbs) > 1:
757 secondaryactions.add(verb)
757 secondaryactions.add(verb)
758 else:
758 else:
759 tertiaryactions.add(verb)
759 tertiaryactions.add(verb)
760
760
761 cls.verb = verb
761 cls.verb = verb
762 cls.verbs = verbs
762 cls.verbs = verbs
763 cls.message = message
763 cls.message = message
764 for verb in verbs:
764 for verb in verbs:
765 actiontable[verb] = cls
765 actiontable[verb] = cls
766 return cls
766 return cls
767
767
768 return wrap
768 return wrap
769
769
770
770
771 @action([b'pick', b'p'], _(b'use commit'), priority=True)
771 @action([b'pick', b'p'], _(b'use commit'), priority=True)
772 class pick(histeditaction):
772 class pick(histeditaction):
773 def run(self):
773 def run(self):
774 rulectx = self.repo[self.node]
774 rulectx = self.repo[self.node]
775 if rulectx.p1().node() == self.state.parentctxnode:
775 if rulectx.p1().node() == self.state.parentctxnode:
776 self.repo.ui.debug(b'node %s unchanged\n' % node.short(self.node))
776 self.repo.ui.debug(b'node %s unchanged\n' % node.short(self.node))
777 return rulectx, []
777 return rulectx, []
778
778
779 return super(pick, self).run()
779 return super(pick, self).run()
780
780
781
781
782 @action([b'edit', b'e'], _(b'use commit, but stop for amending'), priority=True)
782 @action([b'edit', b'e'], _(b'use commit, but stop for amending'), priority=True)
783 class edit(histeditaction):
783 class edit(histeditaction):
784 def run(self):
784 def run(self):
785 repo = self.repo
785 repo = self.repo
786 rulectx = repo[self.node]
786 rulectx = repo[self.node]
787 hg.update(repo, self.state.parentctxnode, quietempty=True)
787 hg.update(repo, self.state.parentctxnode, quietempty=True)
788 applychanges(repo.ui, repo, rulectx, {})
788 applychanges(repo.ui, repo, rulectx, {})
789 raise error.InterventionRequired(
789 raise error.InterventionRequired(
790 _(b'Editing (%s), you may commit or record as needed now.')
790 _(b'Editing (%s), you may commit or record as needed now.')
791 % node.short(self.node),
791 % node.short(self.node),
792 hint=_(b'hg histedit --continue to resume'),
792 hint=_(b'hg histedit --continue to resume'),
793 )
793 )
794
794
795 def commiteditor(self):
795 def commiteditor(self):
796 return cmdutil.getcommiteditor(edit=True, editform=b'histedit.edit')
796 return cmdutil.getcommiteditor(edit=True, editform=b'histedit.edit')
797
797
798
798
799 @action([b'fold', b'f'], _(b'use commit, but combine it with the one above'))
799 @action([b'fold', b'f'], _(b'use commit, but combine it with the one above'))
800 class fold(histeditaction):
800 class fold(histeditaction):
801 def verify(self, prev, expected, seen):
801 def verify(self, prev, expected, seen):
802 """ Verifies semantic correctness of the fold rule"""
802 """ Verifies semantic correctness of the fold rule"""
803 super(fold, self).verify(prev, expected, seen)
803 super(fold, self).verify(prev, expected, seen)
804 repo = self.repo
804 repo = self.repo
805 if not prev:
805 if not prev:
806 c = repo[self.node].p1()
806 c = repo[self.node].p1()
807 elif not prev.verb in (b'pick', b'base'):
807 elif not prev.verb in (b'pick', b'base'):
808 return
808 return
809 else:
809 else:
810 c = repo[prev.node]
810 c = repo[prev.node]
811 if not c.mutable():
811 if not c.mutable():
812 raise error.ParseError(
812 raise error.ParseError(
813 _(b"cannot fold into public change %s") % node.short(c.node())
813 _(b"cannot fold into public change %s") % node.short(c.node())
814 )
814 )
815
815
816 def continuedirty(self):
816 def continuedirty(self):
817 repo = self.repo
817 repo = self.repo
818 rulectx = repo[self.node]
818 rulectx = repo[self.node]
819
819
820 commit = commitfuncfor(repo, rulectx)
820 commit = commitfuncfor(repo, rulectx)
821 commit(
821 commit(
822 text=b'fold-temp-revision %s' % node.short(self.node),
822 text=b'fold-temp-revision %s' % node.short(self.node),
823 user=rulectx.user(),
823 user=rulectx.user(),
824 date=rulectx.date(),
824 date=rulectx.date(),
825 extra=rulectx.extra(),
825 extra=rulectx.extra(),
826 )
826 )
827
827
828 def continueclean(self):
828 def continueclean(self):
829 repo = self.repo
829 repo = self.repo
830 ctx = repo[b'.']
830 ctx = repo[b'.']
831 rulectx = repo[self.node]
831 rulectx = repo[self.node]
832 parentctxnode = self.state.parentctxnode
832 parentctxnode = self.state.parentctxnode
833 if ctx.node() == parentctxnode:
833 if ctx.node() == parentctxnode:
834 repo.ui.warn(_(b'%s: empty changeset\n') % node.short(self.node))
834 repo.ui.warn(_(b'%s: empty changeset\n') % node.short(self.node))
835 return ctx, [(self.node, (parentctxnode,))]
835 return ctx, [(self.node, (parentctxnode,))]
836
836
837 parentctx = repo[parentctxnode]
837 parentctx = repo[parentctxnode]
838 newcommits = {
838 newcommits = {
839 c.node()
839 c.node()
840 for c in repo.set(b'(%d::. - %d)', parentctx.rev(), parentctx.rev())
840 for c in repo.set(b'(%d::. - %d)', parentctx.rev(), parentctx.rev())
841 }
841 }
842 if not newcommits:
842 if not newcommits:
843 repo.ui.warn(
843 repo.ui.warn(
844 _(
844 _(
845 b'%s: cannot fold - working copy is not a '
845 b'%s: cannot fold - working copy is not a '
846 b'descendant of previous commit %s\n'
846 b'descendant of previous commit %s\n'
847 )
847 )
848 % (node.short(self.node), node.short(parentctxnode))
848 % (node.short(self.node), node.short(parentctxnode))
849 )
849 )
850 return ctx, [(self.node, (ctx.node(),))]
850 return ctx, [(self.node, (ctx.node(),))]
851
851
852 middlecommits = newcommits.copy()
852 middlecommits = newcommits.copy()
853 middlecommits.discard(ctx.node())
853 middlecommits.discard(ctx.node())
854
854
855 return self.finishfold(
855 return self.finishfold(
856 repo.ui, repo, parentctx, rulectx, ctx.node(), middlecommits
856 repo.ui, repo, parentctx, rulectx, ctx.node(), middlecommits
857 )
857 )
858
858
859 def skipprompt(self):
859 def skipprompt(self):
860 """Returns true if the rule should skip the message editor.
860 """Returns true if the rule should skip the message editor.
861
861
862 For example, 'fold' wants to show an editor, but 'rollup'
862 For example, 'fold' wants to show an editor, but 'rollup'
863 doesn't want to.
863 doesn't want to.
864 """
864 """
865 return False
865 return False
866
866
867 def mergedescs(self):
867 def mergedescs(self):
868 """Returns true if the rule should merge messages of multiple changes.
868 """Returns true if the rule should merge messages of multiple changes.
869
869
870 This exists mainly so that 'rollup' rules can be a subclass of
870 This exists mainly so that 'rollup' rules can be a subclass of
871 'fold'.
871 'fold'.
872 """
872 """
873 return True
873 return True
874
874
875 def firstdate(self):
875 def firstdate(self):
876 """Returns true if the rule should preserve the date of the first
876 """Returns true if the rule should preserve the date of the first
877 change.
877 change.
878
878
879 This exists mainly so that 'rollup' rules can be a subclass of
879 This exists mainly so that 'rollup' rules can be a subclass of
880 'fold'.
880 'fold'.
881 """
881 """
882 return False
882 return False
883
883
884 def finishfold(self, ui, repo, ctx, oldctx, newnode, internalchanges):
884 def finishfold(self, ui, repo, ctx, oldctx, newnode, internalchanges):
885 parent = ctx.p1().node()
885 parent = ctx.p1().node()
886 hg.updaterepo(repo, parent, overwrite=False)
886 hg.updaterepo(repo, parent, overwrite=False)
887 ### prepare new commit data
887 ### prepare new commit data
888 commitopts = {}
888 commitopts = {}
889 commitopts[b'user'] = ctx.user()
889 commitopts[b'user'] = ctx.user()
890 # commit message
890 # commit message
891 if not self.mergedescs():
891 if not self.mergedescs():
892 newmessage = ctx.description()
892 newmessage = ctx.description()
893 else:
893 else:
894 newmessage = (
894 newmessage = (
895 b'\n***\n'.join(
895 b'\n***\n'.join(
896 [ctx.description()]
896 [ctx.description()]
897 + [repo[r].description() for r in internalchanges]
897 + [repo[r].description() for r in internalchanges]
898 + [oldctx.description()]
898 + [oldctx.description()]
899 )
899 )
900 + b'\n'
900 + b'\n'
901 )
901 )
902 commitopts[b'message'] = newmessage
902 commitopts[b'message'] = newmessage
903 # date
903 # date
904 if self.firstdate():
904 if self.firstdate():
905 commitopts[b'date'] = ctx.date()
905 commitopts[b'date'] = ctx.date()
906 else:
906 else:
907 commitopts[b'date'] = max(ctx.date(), oldctx.date())
907 commitopts[b'date'] = max(ctx.date(), oldctx.date())
908 # if date is to be updated to current
908 # if date is to be updated to current
909 if ui.configbool(b'rewrite', b'update-timestamp'):
909 if ui.configbool(b'rewrite', b'update-timestamp'):
910 commitopts[b'date'] = dateutil.makedate()
910 commitopts[b'date'] = dateutil.makedate()
911
911
912 extra = ctx.extra().copy()
912 extra = ctx.extra().copy()
913 # histedit_source
913 # histedit_source
914 # note: ctx is likely a temporary commit but that the best we can do
914 # note: ctx is likely a temporary commit but that the best we can do
915 # here. This is sufficient to solve issue3681 anyway.
915 # here. This is sufficient to solve issue3681 anyway.
916 extra[b'histedit_source'] = b'%s,%s' % (ctx.hex(), oldctx.hex())
916 extra[b'histedit_source'] = b'%s,%s' % (ctx.hex(), oldctx.hex())
917 commitopts[b'extra'] = extra
917 commitopts[b'extra'] = extra
918 phasemin = max(ctx.phase(), oldctx.phase())
918 phasemin = max(ctx.phase(), oldctx.phase())
919 overrides = {(b'phases', b'new-commit'): phasemin}
919 overrides = {(b'phases', b'new-commit'): phasemin}
920 with repo.ui.configoverride(overrides, b'histedit'):
920 with repo.ui.configoverride(overrides, b'histedit'):
921 n = collapse(
921 n = collapse(
922 repo,
922 repo,
923 ctx,
923 ctx,
924 repo[newnode],
924 repo[newnode],
925 commitopts,
925 commitopts,
926 skipprompt=self.skipprompt(),
926 skipprompt=self.skipprompt(),
927 )
927 )
928 if n is None:
928 if n is None:
929 return ctx, []
929 return ctx, []
930 hg.updaterepo(repo, n, overwrite=False)
930 hg.updaterepo(repo, n, overwrite=False)
931 replacements = [
931 replacements = [
932 (oldctx.node(), (newnode,)),
932 (oldctx.node(), (newnode,)),
933 (ctx.node(), (n,)),
933 (ctx.node(), (n,)),
934 (newnode, (n,)),
934 (newnode, (n,)),
935 ]
935 ]
936 for ich in internalchanges:
936 for ich in internalchanges:
937 replacements.append((ich, (n,)))
937 replacements.append((ich, (n,)))
938 return repo[n], replacements
938 return repo[n], replacements
939
939
940
940
941 @action(
941 @action(
942 [b'base', b'b'],
942 [b'base', b'b'],
943 _(b'checkout changeset and apply further changesets from there'),
943 _(b'checkout changeset and apply further changesets from there'),
944 )
944 )
945 class base(histeditaction):
945 class base(histeditaction):
946 def run(self):
946 def run(self):
947 if self.repo[b'.'].node() != self.node:
947 if self.repo[b'.'].node() != self.node:
948 mergemod.clean_update(self.repo[self.node])
948 mergemod.clean_update(self.repo[self.node])
949 return self.continueclean()
949 return self.continueclean()
950
950
951 def continuedirty(self):
951 def continuedirty(self):
952 abortdirty()
952 abortdirty()
953
953
954 def continueclean(self):
954 def continueclean(self):
955 basectx = self.repo[b'.']
955 basectx = self.repo[b'.']
956 return basectx, []
956 return basectx, []
957
957
958 def _verifynodeconstraints(self, prev, expected, seen):
958 def _verifynodeconstraints(self, prev, expected, seen):
959 # base can only be use with a node not in the edited set
959 # base can only be use with a node not in the edited set
960 if self.node in expected:
960 if self.node in expected:
961 msg = _(b'%s "%s" changeset was an edited list candidate')
961 msg = _(b'%s "%s" changeset was an edited list candidate')
962 raise error.ParseError(
962 raise error.ParseError(
963 msg % (self.verb, node.short(self.node)),
963 msg % (self.verb, node.short(self.node)),
964 hint=_(b'base must only use unlisted changesets'),
964 hint=_(b'base must only use unlisted changesets'),
965 )
965 )
966
966
967
967
968 @action(
968 @action(
969 [b'_multifold'],
969 [b'_multifold'],
970 _(
970 _(
971 """fold subclass used for when multiple folds happen in a row
971 """fold subclass used for when multiple folds happen in a row
972
972
973 We only want to fire the editor for the folded message once when
973 We only want to fire the editor for the folded message once when
974 (say) four changes are folded down into a single change. This is
974 (say) four changes are folded down into a single change. This is
975 similar to rollup, but we should preserve both messages so that
975 similar to rollup, but we should preserve both messages so that
976 when the last fold operation runs we can show the user all the
976 when the last fold operation runs we can show the user all the
977 commit messages in their editor.
977 commit messages in their editor.
978 """
978 """
979 ),
979 ),
980 internal=True,
980 internal=True,
981 )
981 )
982 class _multifold(fold):
982 class _multifold(fold):
983 def skipprompt(self):
983 def skipprompt(self):
984 return True
984 return True
985
985
986
986
987 @action(
987 @action(
988 [b"roll", b"r"],
988 [b"roll", b"r"],
989 _(b"like fold, but discard this commit's description and date"),
989 _(b"like fold, but discard this commit's description and date"),
990 )
990 )
991 class rollup(fold):
991 class rollup(fold):
992 def mergedescs(self):
992 def mergedescs(self):
993 return False
993 return False
994
994
995 def skipprompt(self):
995 def skipprompt(self):
996 return True
996 return True
997
997
998 def firstdate(self):
998 def firstdate(self):
999 return True
999 return True
1000
1000
1001
1001
1002 @action([b"drop", b"d"], _(b'remove commit from history'))
1002 @action([b"drop", b"d"], _(b'remove commit from history'))
1003 class drop(histeditaction):
1003 class drop(histeditaction):
1004 def run(self):
1004 def run(self):
1005 parentctx = self.repo[self.state.parentctxnode]
1005 parentctx = self.repo[self.state.parentctxnode]
1006 return parentctx, [(self.node, tuple())]
1006 return parentctx, [(self.node, tuple())]
1007
1007
1008
1008
1009 @action(
1009 @action(
1010 [b"mess", b"m"],
1010 [b"mess", b"m"],
1011 _(b'edit commit message without changing commit content'),
1011 _(b'edit commit message without changing commit content'),
1012 priority=True,
1012 priority=True,
1013 )
1013 )
1014 class message(histeditaction):
1014 class message(histeditaction):
1015 def commiteditor(self):
1015 def commiteditor(self):
1016 return cmdutil.getcommiteditor(edit=True, editform=b'histedit.mess')
1016 return cmdutil.getcommiteditor(edit=True, editform=b'histedit.mess')
1017
1017
1018
1018
1019 def findoutgoing(ui, repo, remote=None, force=False, opts=None):
1019 def findoutgoing(ui, repo, remote=None, force=False, opts=None):
1020 """utility function to find the first outgoing changeset
1020 """utility function to find the first outgoing changeset
1021
1021
1022 Used by initialization code"""
1022 Used by initialization code"""
1023 if opts is None:
1023 if opts is None:
1024 opts = {}
1024 opts = {}
1025 dest = ui.expandpath(remote or b'default-push', remote or b'default')
1025 dest = ui.expandpath(remote or b'default-push', remote or b'default')
1026 dest, branches = hg.parseurl(dest, None)[:2]
1026 dest, branches = hg.parseurl(dest, None)[:2]
1027 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
1027 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
1028
1028
1029 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
1029 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
1030 other = hg.peer(repo, opts, dest)
1030 other = hg.peer(repo, opts, dest)
1031
1031
1032 if revs:
1032 if revs:
1033 revs = [repo.lookup(rev) for rev in revs]
1033 revs = [repo.lookup(rev) for rev in revs]
1034
1034
1035 outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force)
1035 outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force)
1036 if not outgoing.missing:
1036 if not outgoing.missing:
1037 raise error.Abort(_(b'no outgoing ancestors'))
1037 raise error.Abort(_(b'no outgoing ancestors'))
1038 roots = list(repo.revs(b"roots(%ln)", outgoing.missing))
1038 roots = list(repo.revs(b"roots(%ln)", outgoing.missing))
1039 if len(roots) > 1:
1039 if len(roots) > 1:
1040 msg = _(b'there are ambiguous outgoing revisions')
1040 msg = _(b'there are ambiguous outgoing revisions')
1041 hint = _(b"see 'hg help histedit' for more detail")
1041 hint = _(b"see 'hg help histedit' for more detail")
1042 raise error.Abort(msg, hint=hint)
1042 raise error.Abort(msg, hint=hint)
1043 return repo[roots[0]].node()
1043 return repo[roots[0]].node()
1044
1044
1045
1045
1046 # Curses Support
1046 # Curses Support
1047 try:
1047 try:
1048 import curses
1048 import curses
1049 except ImportError:
1049 except ImportError:
1050 curses = None
1050 curses = None
1051
1051
1052 KEY_LIST = [b'pick', b'edit', b'fold', b'drop', b'mess', b'roll']
1052 KEY_LIST = [b'pick', b'edit', b'fold', b'drop', b'mess', b'roll']
1053 ACTION_LABELS = {
1053 ACTION_LABELS = {
1054 b'fold': b'^fold',
1054 b'fold': b'^fold',
1055 b'roll': b'^roll',
1055 b'roll': b'^roll',
1056 }
1056 }
1057
1057
1058 COLOR_HELP, COLOR_SELECTED, COLOR_OK, COLOR_WARN, COLOR_CURRENT = 1, 2, 3, 4, 5
1058 COLOR_HELP, COLOR_SELECTED, COLOR_OK, COLOR_WARN, COLOR_CURRENT = 1, 2, 3, 4, 5
1059 COLOR_DIFF_ADD_LINE, COLOR_DIFF_DEL_LINE, COLOR_DIFF_OFFSET = 6, 7, 8
1059 COLOR_DIFF_ADD_LINE, COLOR_DIFF_DEL_LINE, COLOR_DIFF_OFFSET = 6, 7, 8
1060 COLOR_ROLL, COLOR_ROLL_CURRENT, COLOR_ROLL_SELECTED = 9, 10, 11
1060 COLOR_ROLL, COLOR_ROLL_CURRENT, COLOR_ROLL_SELECTED = 9, 10, 11
1061
1061
1062 E_QUIT, E_HISTEDIT = 1, 2
1062 E_QUIT, E_HISTEDIT = 1, 2
1063 E_PAGEDOWN, E_PAGEUP, E_LINEUP, E_LINEDOWN, E_RESIZE = 3, 4, 5, 6, 7
1063 E_PAGEDOWN, E_PAGEUP, E_LINEUP, E_LINEDOWN, E_RESIZE = 3, 4, 5, 6, 7
1064 MODE_INIT, MODE_PATCH, MODE_RULES, MODE_HELP = 0, 1, 2, 3
1064 MODE_INIT, MODE_PATCH, MODE_RULES, MODE_HELP = 0, 1, 2, 3
1065
1065
1066 KEYTABLE = {
1066 KEYTABLE = {
1067 b'global': {
1067 b'global': {
1068 b'h': b'next-action',
1068 b'h': b'next-action',
1069 b'KEY_RIGHT': b'next-action',
1069 b'KEY_RIGHT': b'next-action',
1070 b'l': b'prev-action',
1070 b'l': b'prev-action',
1071 b'KEY_LEFT': b'prev-action',
1071 b'KEY_LEFT': b'prev-action',
1072 b'q': b'quit',
1072 b'q': b'quit',
1073 b'c': b'histedit',
1073 b'c': b'histedit',
1074 b'C': b'histedit',
1074 b'C': b'histedit',
1075 b'v': b'showpatch',
1075 b'v': b'showpatch',
1076 b'?': b'help',
1076 b'?': b'help',
1077 },
1077 },
1078 MODE_RULES: {
1078 MODE_RULES: {
1079 b'd': b'action-drop',
1079 b'd': b'action-drop',
1080 b'e': b'action-edit',
1080 b'e': b'action-edit',
1081 b'f': b'action-fold',
1081 b'f': b'action-fold',
1082 b'm': b'action-mess',
1082 b'm': b'action-mess',
1083 b'p': b'action-pick',
1083 b'p': b'action-pick',
1084 b'r': b'action-roll',
1084 b'r': b'action-roll',
1085 b' ': b'select',
1085 b' ': b'select',
1086 b'j': b'down',
1086 b'j': b'down',
1087 b'k': b'up',
1087 b'k': b'up',
1088 b'KEY_DOWN': b'down',
1088 b'KEY_DOWN': b'down',
1089 b'KEY_UP': b'up',
1089 b'KEY_UP': b'up',
1090 b'J': b'move-down',
1090 b'J': b'move-down',
1091 b'K': b'move-up',
1091 b'K': b'move-up',
1092 b'KEY_NPAGE': b'move-down',
1092 b'KEY_NPAGE': b'move-down',
1093 b'KEY_PPAGE': b'move-up',
1093 b'KEY_PPAGE': b'move-up',
1094 b'0': b'goto', # Used for 0..9
1094 b'0': b'goto', # Used for 0..9
1095 },
1095 },
1096 MODE_PATCH: {
1096 MODE_PATCH: {
1097 b' ': b'page-down',
1097 b' ': b'page-down',
1098 b'KEY_NPAGE': b'page-down',
1098 b'KEY_NPAGE': b'page-down',
1099 b'KEY_PPAGE': b'page-up',
1099 b'KEY_PPAGE': b'page-up',
1100 b'j': b'line-down',
1100 b'j': b'line-down',
1101 b'k': b'line-up',
1101 b'k': b'line-up',
1102 b'KEY_DOWN': b'line-down',
1102 b'KEY_DOWN': b'line-down',
1103 b'KEY_UP': b'line-up',
1103 b'KEY_UP': b'line-up',
1104 b'J': b'down',
1104 b'J': b'down',
1105 b'K': b'up',
1105 b'K': b'up',
1106 },
1106 },
1107 MODE_HELP: {},
1107 MODE_HELP: {},
1108 }
1108 }
1109
1109
1110
1110
1111 def screen_size():
1111 def screen_size():
1112 return struct.unpack(b'hh', fcntl.ioctl(1, termios.TIOCGWINSZ, b' '))
1112 return struct.unpack(b'hh', fcntl.ioctl(1, termios.TIOCGWINSZ, b' '))
1113
1113
1114
1114
1115 class histeditrule(object):
1115 class histeditrule(object):
1116 def __init__(self, ui, ctx, pos, action=b'pick'):
1116 def __init__(self, ui, ctx, pos, action=b'pick'):
1117 self.ui = ui
1117 self.ui = ui
1118 self.ctx = ctx
1118 self.ctx = ctx
1119 self.action = action
1119 self.action = action
1120 self.origpos = pos
1120 self.origpos = pos
1121 self.pos = pos
1121 self.pos = pos
1122 self.conflicts = []
1122 self.conflicts = []
1123
1123
1124 def __bytes__(self):
1124 def __bytes__(self):
1125 # Example display of several histeditrules:
1125 # Example display of several histeditrules:
1126 #
1126 #
1127 # #10 pick 316392:06a16c25c053 add option to skip tests
1127 # #10 pick 316392:06a16c25c053 add option to skip tests
1128 # #11 ^roll 316393:71313c964cc5 <RED>oops a fixup commit</RED>
1128 # #11 ^roll 316393:71313c964cc5 <RED>oops a fixup commit</RED>
1129 # #12 pick 316394:ab31f3973b0d include mfbt for mozilla-config.h
1129 # #12 pick 316394:ab31f3973b0d include mfbt for mozilla-config.h
1130 # #13 ^fold 316395:14ce5803f4c3 fix warnings
1130 # #13 ^fold 316395:14ce5803f4c3 fix warnings
1131 #
1131 #
1132 # The carets point to the changeset being folded into ("roll this
1132 # The carets point to the changeset being folded into ("roll this
1133 # changeset into the changeset above").
1133 # changeset into the changeset above").
1134 return b'%s%s' % (self.prefix, self.desc)
1134 return b'%s%s' % (self.prefix, self.desc)
1135
1135
1136 __str__ = encoding.strmethod(__bytes__)
1136 __str__ = encoding.strmethod(__bytes__)
1137
1137
1138 @property
1138 @property
1139 def prefix(self):
1139 def prefix(self):
1140 # Some actions ('fold' and 'roll') combine a patch with a
1140 # Some actions ('fold' and 'roll') combine a patch with a
1141 # previous one. Add a marker showing which patch they apply
1141 # previous one. Add a marker showing which patch they apply
1142 # to.
1142 # to.
1143 action = ACTION_LABELS.get(self.action, self.action)
1143 action = ACTION_LABELS.get(self.action, self.action)
1144
1144
1145 h = self.ctx.hex()[0:12]
1145 h = self.ctx.hex()[0:12]
1146 r = self.ctx.rev()
1146 r = self.ctx.rev()
1147
1147
1148 return b"#%s %s %d:%s " % (
1148 return b"#%s %s %d:%s " % (
1149 (b'%d' % self.origpos).ljust(2),
1149 (b'%d' % self.origpos).ljust(2),
1150 action.ljust(6),
1150 action.ljust(6),
1151 r,
1151 r,
1152 h,
1152 h,
1153 )
1153 )
1154
1154
1155 @property
1155 @property
1156 def desc(self):
1156 def desc(self):
1157 summary = (
1157 summary = (
1158 cmdutil.rendertemplate(
1158 cmdutil.rendertemplate(
1159 self.ctx, self.ui.config(b'histedit', b'summary-template')
1159 self.ctx, self.ui.config(b'histedit', b'summary-template')
1160 )
1160 )
1161 or b''
1161 or b''
1162 )
1162 )
1163 if summary:
1163 if summary:
1164 return summary
1164 return summary
1165 # This is split off from the prefix property so that we can
1165 # This is split off from the prefix property so that we can
1166 # separately make the description for 'roll' red (since it
1166 # separately make the description for 'roll' red (since it
1167 # will get discarded).
1167 # will get discarded).
1168 return self.ctx.description().splitlines()[0].strip()
1168 return self.ctx.description().splitlines()[0].strip()
1169
1169
1170 def checkconflicts(self, other):
1170 def checkconflicts(self, other):
1171 if other.pos > self.pos and other.origpos <= self.origpos:
1171 if other.pos > self.pos and other.origpos <= self.origpos:
1172 if set(other.ctx.files()) & set(self.ctx.files()) != set():
1172 if set(other.ctx.files()) & set(self.ctx.files()) != set():
1173 self.conflicts.append(other)
1173 self.conflicts.append(other)
1174 return self.conflicts
1174 return self.conflicts
1175
1175
1176 if other in self.conflicts:
1176 if other in self.conflicts:
1177 self.conflicts.remove(other)
1177 self.conflicts.remove(other)
1178 return self.conflicts
1178 return self.conflicts
1179
1179
1180
1180
1181 # ============ EVENTS ===============
1181 # ============ EVENTS ===============
1182 def movecursor(state, oldpos, newpos):
1182 def movecursor(state, oldpos, newpos):
1183 '''Change the rule/changeset that the cursor is pointing to, regardless of
1183 '''Change the rule/changeset that the cursor is pointing to, regardless of
1184 current mode (you can switch between patches from the view patch window).'''
1184 current mode (you can switch between patches from the view patch window).'''
1185 state[b'pos'] = newpos
1185 state[b'pos'] = newpos
1186
1186
1187 mode, _ = state[b'mode']
1187 mode, _ = state[b'mode']
1188 if mode == MODE_RULES:
1188 if mode == MODE_RULES:
1189 # Scroll through the list by updating the view for MODE_RULES, so that
1189 # Scroll through the list by updating the view for MODE_RULES, so that
1190 # even if we are not currently viewing the rules, switching back will
1190 # even if we are not currently viewing the rules, switching back will
1191 # result in the cursor's rule being visible.
1191 # result in the cursor's rule being visible.
1192 modestate = state[b'modes'][MODE_RULES]
1192 modestate = state[b'modes'][MODE_RULES]
1193 if newpos < modestate[b'line_offset']:
1193 if newpos < modestate[b'line_offset']:
1194 modestate[b'line_offset'] = newpos
1194 modestate[b'line_offset'] = newpos
1195 elif newpos > modestate[b'line_offset'] + state[b'page_height'] - 1:
1195 elif newpos > modestate[b'line_offset'] + state[b'page_height'] - 1:
1196 modestate[b'line_offset'] = newpos - state[b'page_height'] + 1
1196 modestate[b'line_offset'] = newpos - state[b'page_height'] + 1
1197
1197
1198 # Reset the patch view region to the top of the new patch.
1198 # Reset the patch view region to the top of the new patch.
1199 state[b'modes'][MODE_PATCH][b'line_offset'] = 0
1199 state[b'modes'][MODE_PATCH][b'line_offset'] = 0
1200
1200
1201
1201
1202 def changemode(state, mode):
1202 def changemode(state, mode):
1203 curmode, _ = state[b'mode']
1203 curmode, _ = state[b'mode']
1204 state[b'mode'] = (mode, curmode)
1204 state[b'mode'] = (mode, curmode)
1205 if mode == MODE_PATCH:
1205 if mode == MODE_PATCH:
1206 state[b'modes'][MODE_PATCH][b'patchcontents'] = patchcontents(state)
1206 state[b'modes'][MODE_PATCH][b'patchcontents'] = patchcontents(state)
1207
1207
1208
1208
1209 def makeselection(state, pos):
1209 def makeselection(state, pos):
1210 state[b'selected'] = pos
1210 state[b'selected'] = pos
1211
1211
1212
1212
1213 def swap(state, oldpos, newpos):
1213 def swap(state, oldpos, newpos):
1214 """Swap two positions and calculate necessary conflicts in
1214 """Swap two positions and calculate necessary conflicts in
1215 O(|newpos-oldpos|) time"""
1215 O(|newpos-oldpos|) time"""
1216
1216
1217 rules = state[b'rules']
1217 rules = state[b'rules']
1218 assert 0 <= oldpos < len(rules) and 0 <= newpos < len(rules)
1218 assert 0 <= oldpos < len(rules) and 0 <= newpos < len(rules)
1219
1219
1220 rules[oldpos], rules[newpos] = rules[newpos], rules[oldpos]
1220 rules[oldpos], rules[newpos] = rules[newpos], rules[oldpos]
1221
1221
1222 # TODO: swap should not know about histeditrule's internals
1222 # TODO: swap should not know about histeditrule's internals
1223 rules[newpos].pos = newpos
1223 rules[newpos].pos = newpos
1224 rules[oldpos].pos = oldpos
1224 rules[oldpos].pos = oldpos
1225
1225
1226 start = min(oldpos, newpos)
1226 start = min(oldpos, newpos)
1227 end = max(oldpos, newpos)
1227 end = max(oldpos, newpos)
1228 for r in pycompat.xrange(start, end + 1):
1228 for r in pycompat.xrange(start, end + 1):
1229 rules[newpos].checkconflicts(rules[r])
1229 rules[newpos].checkconflicts(rules[r])
1230 rules[oldpos].checkconflicts(rules[r])
1230 rules[oldpos].checkconflicts(rules[r])
1231
1231
1232 if state[b'selected']:
1232 if state[b'selected']:
1233 makeselection(state, newpos)
1233 makeselection(state, newpos)
1234
1234
1235
1235
1236 def changeaction(state, pos, action):
1236 def changeaction(state, pos, action):
1237 """Change the action state on the given position to the new action"""
1237 """Change the action state on the given position to the new action"""
1238 rules = state[b'rules']
1238 rules = state[b'rules']
1239 assert 0 <= pos < len(rules)
1239 assert 0 <= pos < len(rules)
1240 rules[pos].action = action
1240 rules[pos].action = action
1241
1241
1242
1242
1243 def cycleaction(state, pos, next=False):
1243 def cycleaction(state, pos, next=False):
1244 """Changes the action state the next or the previous action from
1244 """Changes the action state the next or the previous action from
1245 the action list"""
1245 the action list"""
1246 rules = state[b'rules']
1246 rules = state[b'rules']
1247 assert 0 <= pos < len(rules)
1247 assert 0 <= pos < len(rules)
1248 current = rules[pos].action
1248 current = rules[pos].action
1249
1249
1250 assert current in KEY_LIST
1250 assert current in KEY_LIST
1251
1251
1252 index = KEY_LIST.index(current)
1252 index = KEY_LIST.index(current)
1253 if next:
1253 if next:
1254 index += 1
1254 index += 1
1255 else:
1255 else:
1256 index -= 1
1256 index -= 1
1257 changeaction(state, pos, KEY_LIST[index % len(KEY_LIST)])
1257 changeaction(state, pos, KEY_LIST[index % len(KEY_LIST)])
1258
1258
1259
1259
1260 def changeview(state, delta, unit):
1260 def changeview(state, delta, unit):
1261 '''Change the region of whatever is being viewed (a patch or the list of
1261 '''Change the region of whatever is being viewed (a patch or the list of
1262 changesets). 'delta' is an amount (+/- 1) and 'unit' is 'page' or 'line'.'''
1262 changesets). 'delta' is an amount (+/- 1) and 'unit' is 'page' or 'line'.'''
1263 mode, _ = state[b'mode']
1263 mode, _ = state[b'mode']
1264 if mode != MODE_PATCH:
1264 if mode != MODE_PATCH:
1265 return
1265 return
1266 mode_state = state[b'modes'][mode]
1266 mode_state = state[b'modes'][mode]
1267 num_lines = len(mode_state[b'patchcontents'])
1267 num_lines = len(mode_state[b'patchcontents'])
1268 page_height = state[b'page_height']
1268 page_height = state[b'page_height']
1269 unit = page_height if unit == b'page' else 1
1269 unit = page_height if unit == b'page' else 1
1270 num_pages = 1 + (num_lines - 1) // page_height
1270 num_pages = 1 + (num_lines - 1) // page_height
1271 max_offset = (num_pages - 1) * page_height
1271 max_offset = (num_pages - 1) * page_height
1272 newline = mode_state[b'line_offset'] + delta * unit
1272 newline = mode_state[b'line_offset'] + delta * unit
1273 mode_state[b'line_offset'] = max(0, min(max_offset, newline))
1273 mode_state[b'line_offset'] = max(0, min(max_offset, newline))
1274
1274
1275
1275
1276 def event(state, ch):
1276 def event(state, ch):
1277 """Change state based on the current character input
1277 """Change state based on the current character input
1278
1278
1279 This takes the current state and based on the current character input from
1279 This takes the current state and based on the current character input from
1280 the user we change the state.
1280 the user we change the state.
1281 """
1281 """
1282 selected = state[b'selected']
1282 selected = state[b'selected']
1283 oldpos = state[b'pos']
1283 oldpos = state[b'pos']
1284 rules = state[b'rules']
1284 rules = state[b'rules']
1285
1285
1286 if ch in (curses.KEY_RESIZE, b"KEY_RESIZE"):
1286 if ch in (curses.KEY_RESIZE, b"KEY_RESIZE"):
1287 return E_RESIZE
1287 return E_RESIZE
1288
1288
1289 lookup_ch = ch
1289 lookup_ch = ch
1290 if ch is not None and b'0' <= ch <= b'9':
1290 if ch is not None and b'0' <= ch <= b'9':
1291 lookup_ch = b'0'
1291 lookup_ch = b'0'
1292
1292
1293 curmode, prevmode = state[b'mode']
1293 curmode, prevmode = state[b'mode']
1294 action = KEYTABLE[curmode].get(
1294 action = KEYTABLE[curmode].get(
1295 lookup_ch, KEYTABLE[b'global'].get(lookup_ch)
1295 lookup_ch, KEYTABLE[b'global'].get(lookup_ch)
1296 )
1296 )
1297 if action is None:
1297 if action is None:
1298 return
1298 return
1299 if action in (b'down', b'move-down'):
1299 if action in (b'down', b'move-down'):
1300 newpos = min(oldpos + 1, len(rules) - 1)
1300 newpos = min(oldpos + 1, len(rules) - 1)
1301 movecursor(state, oldpos, newpos)
1301 movecursor(state, oldpos, newpos)
1302 if selected is not None or action == b'move-down':
1302 if selected is not None or action == b'move-down':
1303 swap(state, oldpos, newpos)
1303 swap(state, oldpos, newpos)
1304 elif action in (b'up', b'move-up'):
1304 elif action in (b'up', b'move-up'):
1305 newpos = max(0, oldpos - 1)
1305 newpos = max(0, oldpos - 1)
1306 movecursor(state, oldpos, newpos)
1306 movecursor(state, oldpos, newpos)
1307 if selected is not None or action == b'move-up':
1307 if selected is not None or action == b'move-up':
1308 swap(state, oldpos, newpos)
1308 swap(state, oldpos, newpos)
1309 elif action == b'next-action':
1309 elif action == b'next-action':
1310 cycleaction(state, oldpos, next=True)
1310 cycleaction(state, oldpos, next=True)
1311 elif action == b'prev-action':
1311 elif action == b'prev-action':
1312 cycleaction(state, oldpos, next=False)
1312 cycleaction(state, oldpos, next=False)
1313 elif action == b'select':
1313 elif action == b'select':
1314 selected = oldpos if selected is None else None
1314 selected = oldpos if selected is None else None
1315 makeselection(state, selected)
1315 makeselection(state, selected)
1316 elif action == b'goto' and int(ch) < len(rules) and len(rules) <= 10:
1316 elif action == b'goto' and int(ch) < len(rules) and len(rules) <= 10:
1317 newrule = next((r for r in rules if r.origpos == int(ch)))
1317 newrule = next((r for r in rules if r.origpos == int(ch)))
1318 movecursor(state, oldpos, newrule.pos)
1318 movecursor(state, oldpos, newrule.pos)
1319 if selected is not None:
1319 if selected is not None:
1320 swap(state, oldpos, newrule.pos)
1320 swap(state, oldpos, newrule.pos)
1321 elif action.startswith(b'action-'):
1321 elif action.startswith(b'action-'):
1322 changeaction(state, oldpos, action[7:])
1322 changeaction(state, oldpos, action[7:])
1323 elif action == b'showpatch':
1323 elif action == b'showpatch':
1324 changemode(state, MODE_PATCH if curmode != MODE_PATCH else prevmode)
1324 changemode(state, MODE_PATCH if curmode != MODE_PATCH else prevmode)
1325 elif action == b'help':
1325 elif action == b'help':
1326 changemode(state, MODE_HELP if curmode != MODE_HELP else prevmode)
1326 changemode(state, MODE_HELP if curmode != MODE_HELP else prevmode)
1327 elif action == b'quit':
1327 elif action == b'quit':
1328 return E_QUIT
1328 return E_QUIT
1329 elif action == b'histedit':
1329 elif action == b'histedit':
1330 return E_HISTEDIT
1330 return E_HISTEDIT
1331 elif action == b'page-down':
1331 elif action == b'page-down':
1332 return E_PAGEDOWN
1332 return E_PAGEDOWN
1333 elif action == b'page-up':
1333 elif action == b'page-up':
1334 return E_PAGEUP
1334 return E_PAGEUP
1335 elif action == b'line-down':
1335 elif action == b'line-down':
1336 return E_LINEDOWN
1336 return E_LINEDOWN
1337 elif action == b'line-up':
1337 elif action == b'line-up':
1338 return E_LINEUP
1338 return E_LINEUP
1339
1339
1340
1340
1341 def makecommands(rules):
1341 def makecommands(rules):
1342 """Returns a list of commands consumable by histedit --commands based on
1342 """Returns a list of commands consumable by histedit --commands based on
1343 our list of rules"""
1343 our list of rules"""
1344 commands = []
1344 commands = []
1345 for rules in rules:
1345 for rules in rules:
1346 commands.append(b'%s %s\n' % (rules.action, rules.ctx))
1346 commands.append(b'%s %s\n' % (rules.action, rules.ctx))
1347 return commands
1347 return commands
1348
1348
1349
1349
1350 def addln(win, y, x, line, color=None):
1350 def addln(win, y, x, line, color=None):
1351 """Add a line to the given window left padding but 100% filled with
1351 """Add a line to the given window left padding but 100% filled with
1352 whitespace characters, so that the color appears on the whole line"""
1352 whitespace characters, so that the color appears on the whole line"""
1353 maxy, maxx = win.getmaxyx()
1353 maxy, maxx = win.getmaxyx()
1354 length = maxx - 1 - x
1354 length = maxx - 1 - x
1355 line = bytes(line).ljust(length)[:length]
1355 line = bytes(line).ljust(length)[:length]
1356 if y < 0:
1356 if y < 0:
1357 y = maxy + y
1357 y = maxy + y
1358 if x < 0:
1358 if x < 0:
1359 x = maxx + x
1359 x = maxx + x
1360 if color:
1360 if color:
1361 win.addstr(y, x, line, color)
1361 win.addstr(y, x, line, color)
1362 else:
1362 else:
1363 win.addstr(y, x, line)
1363 win.addstr(y, x, line)
1364
1364
1365
1365
1366 def _trunc_head(line, n):
1366 def _trunc_head(line, n):
1367 if len(line) <= n:
1367 if len(line) <= n:
1368 return line
1368 return line
1369 return b'> ' + line[-(n - 2) :]
1369 return b'> ' + line[-(n - 2) :]
1370
1370
1371
1371
1372 def _trunc_tail(line, n):
1372 def _trunc_tail(line, n):
1373 if len(line) <= n:
1373 if len(line) <= n:
1374 return line
1374 return line
1375 return line[: n - 2] + b' >'
1375 return line[: n - 2] + b' >'
1376
1376
1377
1377
1378 def patchcontents(state):
1378 def patchcontents(state):
1379 repo = state[b'repo']
1379 repo = state[b'repo']
1380 rule = state[b'rules'][state[b'pos']]
1380 rule = state[b'rules'][state[b'pos']]
1381 displayer = logcmdutil.changesetdisplayer(
1381 displayer = logcmdutil.changesetdisplayer(
1382 repo.ui, repo, {b"patch": True, b"template": b"status"}, buffered=True
1382 repo.ui, repo, {b"patch": True, b"template": b"status"}, buffered=True
1383 )
1383 )
1384 overrides = {(b'ui', b'verbose'): True}
1384 overrides = {(b'ui', b'verbose'): True}
1385 with repo.ui.configoverride(overrides, source=b'histedit'):
1385 with repo.ui.configoverride(overrides, source=b'histedit'):
1386 displayer.show(rule.ctx)
1386 displayer.show(rule.ctx)
1387 displayer.close()
1387 displayer.close()
1388 return displayer.hunk[rule.ctx.rev()].splitlines()
1388 return displayer.hunk[rule.ctx.rev()].splitlines()
1389
1389
1390
1390
1391 def _chisteditmain(repo, rules, stdscr):
1391 def _chisteditmain(repo, rules, stdscr):
1392 try:
1392 try:
1393 curses.use_default_colors()
1393 curses.use_default_colors()
1394 except curses.error:
1394 except curses.error:
1395 pass
1395 pass
1396
1396
1397 # initialize color pattern
1397 # initialize color pattern
1398 curses.init_pair(COLOR_HELP, curses.COLOR_WHITE, curses.COLOR_BLUE)
1398 curses.init_pair(COLOR_HELP, curses.COLOR_WHITE, curses.COLOR_BLUE)
1399 curses.init_pair(COLOR_SELECTED, curses.COLOR_BLACK, curses.COLOR_WHITE)
1399 curses.init_pair(COLOR_SELECTED, curses.COLOR_BLACK, curses.COLOR_WHITE)
1400 curses.init_pair(COLOR_WARN, curses.COLOR_BLACK, curses.COLOR_YELLOW)
1400 curses.init_pair(COLOR_WARN, curses.COLOR_BLACK, curses.COLOR_YELLOW)
1401 curses.init_pair(COLOR_OK, curses.COLOR_BLACK, curses.COLOR_GREEN)
1401 curses.init_pair(COLOR_OK, curses.COLOR_BLACK, curses.COLOR_GREEN)
1402 curses.init_pair(COLOR_CURRENT, curses.COLOR_WHITE, curses.COLOR_MAGENTA)
1402 curses.init_pair(COLOR_CURRENT, curses.COLOR_WHITE, curses.COLOR_MAGENTA)
1403 curses.init_pair(COLOR_DIFF_ADD_LINE, curses.COLOR_GREEN, -1)
1403 curses.init_pair(COLOR_DIFF_ADD_LINE, curses.COLOR_GREEN, -1)
1404 curses.init_pair(COLOR_DIFF_DEL_LINE, curses.COLOR_RED, -1)
1404 curses.init_pair(COLOR_DIFF_DEL_LINE, curses.COLOR_RED, -1)
1405 curses.init_pair(COLOR_DIFF_OFFSET, curses.COLOR_MAGENTA, -1)
1405 curses.init_pair(COLOR_DIFF_OFFSET, curses.COLOR_MAGENTA, -1)
1406 curses.init_pair(COLOR_ROLL, curses.COLOR_RED, -1)
1406 curses.init_pair(COLOR_ROLL, curses.COLOR_RED, -1)
1407 curses.init_pair(
1407 curses.init_pair(
1408 COLOR_ROLL_CURRENT, curses.COLOR_BLACK, curses.COLOR_MAGENTA
1408 COLOR_ROLL_CURRENT, curses.COLOR_BLACK, curses.COLOR_MAGENTA
1409 )
1409 )
1410 curses.init_pair(COLOR_ROLL_SELECTED, curses.COLOR_RED, curses.COLOR_WHITE)
1410 curses.init_pair(COLOR_ROLL_SELECTED, curses.COLOR_RED, curses.COLOR_WHITE)
1411
1411
1412 # don't display the cursor
1412 # don't display the cursor
1413 try:
1413 try:
1414 curses.curs_set(0)
1414 curses.curs_set(0)
1415 except curses.error:
1415 except curses.error:
1416 pass
1416 pass
1417
1417
1418 def rendercommit(win, state):
1418 def rendercommit(win, state):
1419 """Renders the commit window that shows the log of the current selected
1419 """Renders the commit window that shows the log of the current selected
1420 commit"""
1420 commit"""
1421 pos = state[b'pos']
1421 pos = state[b'pos']
1422 rules = state[b'rules']
1422 rules = state[b'rules']
1423 rule = rules[pos]
1423 rule = rules[pos]
1424
1424
1425 ctx = rule.ctx
1425 ctx = rule.ctx
1426 win.box()
1426 win.box()
1427
1427
1428 maxy, maxx = win.getmaxyx()
1428 maxy, maxx = win.getmaxyx()
1429 length = maxx - 3
1429 length = maxx - 3
1430
1430
1431 line = b"changeset: %d:%s" % (ctx.rev(), ctx.hex()[:12])
1431 line = b"changeset: %d:%s" % (ctx.rev(), ctx.hex()[:12])
1432 win.addstr(1, 1, line[:length])
1432 win.addstr(1, 1, line[:length])
1433
1433
1434 line = b"user: %s" % ctx.user()
1434 line = b"user: %s" % ctx.user()
1435 win.addstr(2, 1, line[:length])
1435 win.addstr(2, 1, line[:length])
1436
1436
1437 bms = repo.nodebookmarks(ctx.node())
1437 bms = repo.nodebookmarks(ctx.node())
1438 line = b"bookmark: %s" % b' '.join(bms)
1438 line = b"bookmark: %s" % b' '.join(bms)
1439 win.addstr(3, 1, line[:length])
1439 win.addstr(3, 1, line[:length])
1440
1440
1441 line = b"summary: %s" % (ctx.description().splitlines()[0])
1441 line = b"summary: %s" % (ctx.description().splitlines()[0])
1442 win.addstr(4, 1, line[:length])
1442 win.addstr(4, 1, line[:length])
1443
1443
1444 line = b"files: "
1444 line = b"files: "
1445 win.addstr(5, 1, line)
1445 win.addstr(5, 1, line)
1446 fnx = 1 + len(line)
1446 fnx = 1 + len(line)
1447 fnmaxx = length - fnx + 1
1447 fnmaxx = length - fnx + 1
1448 y = 5
1448 y = 5
1449 fnmaxn = maxy - (1 + y) - 1
1449 fnmaxn = maxy - (1 + y) - 1
1450 files = ctx.files()
1450 files = ctx.files()
1451 for i, line1 in enumerate(files):
1451 for i, line1 in enumerate(files):
1452 if len(files) > fnmaxn and i == fnmaxn - 1:
1452 if len(files) > fnmaxn and i == fnmaxn - 1:
1453 win.addstr(y, fnx, _trunc_tail(b','.join(files[i:]), fnmaxx))
1453 win.addstr(y, fnx, _trunc_tail(b','.join(files[i:]), fnmaxx))
1454 y = y + 1
1454 y = y + 1
1455 break
1455 break
1456 win.addstr(y, fnx, _trunc_head(line1, fnmaxx))
1456 win.addstr(y, fnx, _trunc_head(line1, fnmaxx))
1457 y = y + 1
1457 y = y + 1
1458
1458
1459 conflicts = rule.conflicts
1459 conflicts = rule.conflicts
1460 if len(conflicts) > 0:
1460 if len(conflicts) > 0:
1461 conflictstr = b','.join(map(lambda r: r.ctx.hex()[:12], conflicts))
1461 conflictstr = b','.join(map(lambda r: r.ctx.hex()[:12], conflicts))
1462 conflictstr = b"changed files overlap with %s" % conflictstr
1462 conflictstr = b"changed files overlap with %s" % conflictstr
1463 else:
1463 else:
1464 conflictstr = b'no overlap'
1464 conflictstr = b'no overlap'
1465
1465
1466 win.addstr(y, 1, conflictstr[:length])
1466 win.addstr(y, 1, conflictstr[:length])
1467 win.noutrefresh()
1467 win.noutrefresh()
1468
1468
1469 def helplines(mode):
1469 def helplines(mode):
1470 if mode == MODE_PATCH:
1470 if mode == MODE_PATCH:
1471 help = b"""\
1471 help = b"""\
1472 ?: help, k/up: line up, j/down: line down, v: stop viewing patch
1472 ?: help, k/up: line up, j/down: line down, v: stop viewing patch
1473 pgup: prev page, space/pgdn: next page, c: commit, q: abort
1473 pgup: prev page, space/pgdn: next page, c: commit, q: abort
1474 """
1474 """
1475 else:
1475 else:
1476 help = b"""\
1476 help = b"""\
1477 ?: help, k/up: move up, j/down: move down, space: select, v: view patch
1477 ?: help, k/up: move up, j/down: move down, space: select, v: view patch
1478 d: drop, e: edit, f: fold, m: mess, p: pick, r: roll
1478 d: drop, e: edit, f: fold, m: mess, p: pick, r: roll
1479 pgup/K: move patch up, pgdn/J: move patch down, c: commit, q: abort
1479 pgup/K: move patch up, pgdn/J: move patch down, c: commit, q: abort
1480 """
1480 """
1481 return help.splitlines()
1481 return help.splitlines()
1482
1482
1483 def renderhelp(win, state):
1483 def renderhelp(win, state):
1484 maxy, maxx = win.getmaxyx()
1484 maxy, maxx = win.getmaxyx()
1485 mode, _ = state[b'mode']
1485 mode, _ = state[b'mode']
1486 for y, line in enumerate(helplines(mode)):
1486 for y, line in enumerate(helplines(mode)):
1487 if y >= maxy:
1487 if y >= maxy:
1488 break
1488 break
1489 addln(win, y, 0, line, curses.color_pair(COLOR_HELP))
1489 addln(win, y, 0, line, curses.color_pair(COLOR_HELP))
1490 win.noutrefresh()
1490 win.noutrefresh()
1491
1491
1492 def renderrules(rulesscr, state):
1492 def renderrules(rulesscr, state):
1493 rules = state[b'rules']
1493 rules = state[b'rules']
1494 pos = state[b'pos']
1494 pos = state[b'pos']
1495 selected = state[b'selected']
1495 selected = state[b'selected']
1496 start = state[b'modes'][MODE_RULES][b'line_offset']
1496 start = state[b'modes'][MODE_RULES][b'line_offset']
1497
1497
1498 conflicts = [r.ctx for r in rules if r.conflicts]
1498 conflicts = [r.ctx for r in rules if r.conflicts]
1499 if len(conflicts) > 0:
1499 if len(conflicts) > 0:
1500 line = b"potential conflict in %s" % b','.join(
1500 line = b"potential conflict in %s" % b','.join(
1501 map(pycompat.bytestr, conflicts)
1501 map(pycompat.bytestr, conflicts)
1502 )
1502 )
1503 addln(rulesscr, -1, 0, line, curses.color_pair(COLOR_WARN))
1503 addln(rulesscr, -1, 0, line, curses.color_pair(COLOR_WARN))
1504
1504
1505 for y, rule in enumerate(rules[start:]):
1505 for y, rule in enumerate(rules[start:]):
1506 if y >= state[b'page_height']:
1506 if y >= state[b'page_height']:
1507 break
1507 break
1508 if len(rule.conflicts) > 0:
1508 if len(rule.conflicts) > 0:
1509 rulesscr.addstr(y, 0, b" ", curses.color_pair(COLOR_WARN))
1509 rulesscr.addstr(y, 0, b" ", curses.color_pair(COLOR_WARN))
1510 else:
1510 else:
1511 rulesscr.addstr(y, 0, b" ", curses.COLOR_BLACK)
1511 rulesscr.addstr(y, 0, b" ", curses.COLOR_BLACK)
1512
1512
1513 if y + start == selected:
1513 if y + start == selected:
1514 rollcolor = COLOR_ROLL_SELECTED
1514 rollcolor = COLOR_ROLL_SELECTED
1515 addln(rulesscr, y, 2, rule, curses.color_pair(COLOR_SELECTED))
1515 addln(rulesscr, y, 2, rule, curses.color_pair(COLOR_SELECTED))
1516 elif y + start == pos:
1516 elif y + start == pos:
1517 rollcolor = COLOR_ROLL_CURRENT
1517 rollcolor = COLOR_ROLL_CURRENT
1518 addln(
1518 addln(
1519 rulesscr,
1519 rulesscr,
1520 y,
1520 y,
1521 2,
1521 2,
1522 rule,
1522 rule,
1523 curses.color_pair(COLOR_CURRENT) | curses.A_BOLD,
1523 curses.color_pair(COLOR_CURRENT) | curses.A_BOLD,
1524 )
1524 )
1525 else:
1525 else:
1526 rollcolor = COLOR_ROLL
1526 rollcolor = COLOR_ROLL
1527 addln(rulesscr, y, 2, rule)
1527 addln(rulesscr, y, 2, rule)
1528
1528
1529 if rule.action == b'roll':
1529 if rule.action == b'roll':
1530 rulesscr.addstr(
1530 rulesscr.addstr(
1531 y,
1531 y,
1532 2 + len(rule.prefix),
1532 2 + len(rule.prefix),
1533 rule.desc,
1533 rule.desc,
1534 curses.color_pair(rollcolor),
1534 curses.color_pair(rollcolor),
1535 )
1535 )
1536
1536
1537 rulesscr.noutrefresh()
1537 rulesscr.noutrefresh()
1538
1538
1539 def renderstring(win, state, output, diffcolors=False):
1539 def renderstring(win, state, output, diffcolors=False):
1540 maxy, maxx = win.getmaxyx()
1540 maxy, maxx = win.getmaxyx()
1541 length = min(maxy - 1, len(output))
1541 length = min(maxy - 1, len(output))
1542 for y in range(0, length):
1542 for y in range(0, length):
1543 line = output[y]
1543 line = output[y]
1544 if diffcolors:
1544 if diffcolors:
1545 if line and line[0] == b'+':
1545 if line and line[0] == b'+':
1546 win.addstr(
1546 win.addstr(
1547 y, 0, line, curses.color_pair(COLOR_DIFF_ADD_LINE)
1547 y, 0, line, curses.color_pair(COLOR_DIFF_ADD_LINE)
1548 )
1548 )
1549 elif line and line[0] == b'-':
1549 elif line and line[0] == b'-':
1550 win.addstr(
1550 win.addstr(
1551 y, 0, line, curses.color_pair(COLOR_DIFF_DEL_LINE)
1551 y, 0, line, curses.color_pair(COLOR_DIFF_DEL_LINE)
1552 )
1552 )
1553 elif line.startswith(b'@@ '):
1553 elif line.startswith(b'@@ '):
1554 win.addstr(y, 0, line, curses.color_pair(COLOR_DIFF_OFFSET))
1554 win.addstr(y, 0, line, curses.color_pair(COLOR_DIFF_OFFSET))
1555 else:
1555 else:
1556 win.addstr(y, 0, line)
1556 win.addstr(y, 0, line)
1557 else:
1557 else:
1558 win.addstr(y, 0, line)
1558 win.addstr(y, 0, line)
1559 win.noutrefresh()
1559 win.noutrefresh()
1560
1560
1561 def renderpatch(win, state):
1561 def renderpatch(win, state):
1562 start = state[b'modes'][MODE_PATCH][b'line_offset']
1562 start = state[b'modes'][MODE_PATCH][b'line_offset']
1563 content = state[b'modes'][MODE_PATCH][b'patchcontents']
1563 content = state[b'modes'][MODE_PATCH][b'patchcontents']
1564 renderstring(win, state, content[start:], diffcolors=True)
1564 renderstring(win, state, content[start:], diffcolors=True)
1565
1565
1566 def layout(mode):
1566 def layout(mode):
1567 maxy, maxx = stdscr.getmaxyx()
1567 maxy, maxx = stdscr.getmaxyx()
1568 helplen = len(helplines(mode))
1568 helplen = len(helplines(mode))
1569 return {
1569 return {
1570 b'commit': (12, maxx),
1570 b'commit': (12, maxx),
1571 b'help': (helplen, maxx),
1571 b'help': (helplen, maxx),
1572 b'main': (maxy - helplen - 12, maxx),
1572 b'main': (maxy - helplen - 12, maxx),
1573 }
1573 }
1574
1574
1575 def drawvertwin(size, y, x):
1575 def drawvertwin(size, y, x):
1576 win = curses.newwin(size[0], size[1], y, x)
1576 win = curses.newwin(size[0], size[1], y, x)
1577 y += size[0]
1577 y += size[0]
1578 return win, y, x
1578 return win, y, x
1579
1579
1580 state = {
1580 state = {
1581 b'pos': 0,
1581 b'pos': 0,
1582 b'rules': rules,
1582 b'rules': rules,
1583 b'selected': None,
1583 b'selected': None,
1584 b'mode': (MODE_INIT, MODE_INIT),
1584 b'mode': (MODE_INIT, MODE_INIT),
1585 b'page_height': None,
1585 b'page_height': None,
1586 b'modes': {
1586 b'modes': {
1587 MODE_RULES: {b'line_offset': 0,},
1587 MODE_RULES: {b'line_offset': 0,},
1588 MODE_PATCH: {b'line_offset': 0,},
1588 MODE_PATCH: {b'line_offset': 0,},
1589 },
1589 },
1590 b'repo': repo,
1590 b'repo': repo,
1591 }
1591 }
1592
1592
1593 # eventloop
1593 # eventloop
1594 ch = None
1594 ch = None
1595 stdscr.clear()
1595 stdscr.clear()
1596 stdscr.refresh()
1596 stdscr.refresh()
1597 while True:
1597 while True:
1598 try:
1598 try:
1599 oldmode, _ = state[b'mode']
1599 oldmode, _ = state[b'mode']
1600 if oldmode == MODE_INIT:
1600 if oldmode == MODE_INIT:
1601 changemode(state, MODE_RULES)
1601 changemode(state, MODE_RULES)
1602 e = event(state, ch)
1602 e = event(state, ch)
1603
1603
1604 if e == E_QUIT:
1604 if e == E_QUIT:
1605 return False
1605 return False
1606 if e == E_HISTEDIT:
1606 if e == E_HISTEDIT:
1607 return state[b'rules']
1607 return state[b'rules']
1608 else:
1608 else:
1609 if e == E_RESIZE:
1609 if e == E_RESIZE:
1610 size = screen_size()
1610 size = screen_size()
1611 if size != stdscr.getmaxyx():
1611 if size != stdscr.getmaxyx():
1612 curses.resizeterm(*size)
1612 curses.resizeterm(*size)
1613
1613
1614 curmode, _ = state[b'mode']
1614 curmode, _ = state[b'mode']
1615 sizes = layout(curmode)
1615 sizes = layout(curmode)
1616 if curmode != oldmode:
1616 if curmode != oldmode:
1617 state[b'page_height'] = sizes[b'main'][0]
1617 state[b'page_height'] = sizes[b'main'][0]
1618 # Adjust the view to fit the current screen size.
1618 # Adjust the view to fit the current screen size.
1619 movecursor(state, state[b'pos'], state[b'pos'])
1619 movecursor(state, state[b'pos'], state[b'pos'])
1620
1620
1621 # Pack the windows against the top, each pane spread across the
1621 # Pack the windows against the top, each pane spread across the
1622 # full width of the screen.
1622 # full width of the screen.
1623 y, x = (0, 0)
1623 y, x = (0, 0)
1624 helpwin, y, x = drawvertwin(sizes[b'help'], y, x)
1624 helpwin, y, x = drawvertwin(sizes[b'help'], y, x)
1625 mainwin, y, x = drawvertwin(sizes[b'main'], y, x)
1625 mainwin, y, x = drawvertwin(sizes[b'main'], y, x)
1626 commitwin, y, x = drawvertwin(sizes[b'commit'], y, x)
1626 commitwin, y, x = drawvertwin(sizes[b'commit'], y, x)
1627
1627
1628 if e in (E_PAGEDOWN, E_PAGEUP, E_LINEDOWN, E_LINEUP):
1628 if e in (E_PAGEDOWN, E_PAGEUP, E_LINEDOWN, E_LINEUP):
1629 if e == E_PAGEDOWN:
1629 if e == E_PAGEDOWN:
1630 changeview(state, +1, b'page')
1630 changeview(state, +1, b'page')
1631 elif e == E_PAGEUP:
1631 elif e == E_PAGEUP:
1632 changeview(state, -1, b'page')
1632 changeview(state, -1, b'page')
1633 elif e == E_LINEDOWN:
1633 elif e == E_LINEDOWN:
1634 changeview(state, +1, b'line')
1634 changeview(state, +1, b'line')
1635 elif e == E_LINEUP:
1635 elif e == E_LINEUP:
1636 changeview(state, -1, b'line')
1636 changeview(state, -1, b'line')
1637
1637
1638 # start rendering
1638 # start rendering
1639 commitwin.erase()
1639 commitwin.erase()
1640 helpwin.erase()
1640 helpwin.erase()
1641 mainwin.erase()
1641 mainwin.erase()
1642 if curmode == MODE_PATCH:
1642 if curmode == MODE_PATCH:
1643 renderpatch(mainwin, state)
1643 renderpatch(mainwin, state)
1644 elif curmode == MODE_HELP:
1644 elif curmode == MODE_HELP:
1645 renderstring(mainwin, state, __doc__.strip().splitlines())
1645 renderstring(mainwin, state, __doc__.strip().splitlines())
1646 else:
1646 else:
1647 renderrules(mainwin, state)
1647 renderrules(mainwin, state)
1648 rendercommit(commitwin, state)
1648 rendercommit(commitwin, state)
1649 renderhelp(helpwin, state)
1649 renderhelp(helpwin, state)
1650 curses.doupdate()
1650 curses.doupdate()
1651 # done rendering
1651 # done rendering
1652 ch = encoding.strtolocal(stdscr.getkey())
1652 ch = encoding.strtolocal(stdscr.getkey())
1653 except curses.error:
1653 except curses.error:
1654 pass
1654 pass
1655
1655
1656
1656
1657 def _chistedit(ui, repo, freeargs, opts):
1657 def _chistedit(ui, repo, freeargs, opts):
1658 """interactively edit changeset history via a curses interface
1658 """interactively edit changeset history via a curses interface
1659
1659
1660 Provides a ncurses interface to histedit. Press ? in chistedit mode
1660 Provides a ncurses interface to histedit. Press ? in chistedit mode
1661 to see an extensive help. Requires python-curses to be installed."""
1661 to see an extensive help. Requires python-curses to be installed."""
1662
1662
1663 if curses is None:
1663 if curses is None:
1664 raise error.Abort(_(b"Python curses library required"))
1664 raise error.Abort(_(b"Python curses library required"))
1665
1665
1666 # disable color
1666 # disable color
1667 ui._colormode = None
1667 ui._colormode = None
1668
1668
1669 try:
1669 try:
1670 keep = opts.get(b'keep')
1670 keep = opts.get(b'keep')
1671 revs = opts.get(b'rev', [])[:]
1671 revs = opts.get(b'rev', [])[:]
1672 cmdutil.checkunfinished(repo)
1672 cmdutil.checkunfinished(repo)
1673 cmdutil.bailifchanged(repo)
1673 cmdutil.bailifchanged(repo)
1674
1674
1675 if os.path.exists(os.path.join(repo.path, b'histedit-state')):
1675 if os.path.exists(os.path.join(repo.path, b'histedit-state')):
1676 raise error.Abort(
1676 raise error.Abort(
1677 _(
1677 _(
1678 b'history edit already in progress, try '
1678 b'history edit already in progress, try '
1679 b'--continue or --abort'
1679 b'--continue or --abort'
1680 )
1680 )
1681 )
1681 )
1682 revs.extend(freeargs)
1682 revs.extend(freeargs)
1683 if not revs:
1683 if not revs:
1684 defaultrev = destutil.desthistedit(ui, repo)
1684 defaultrev = destutil.desthistedit(ui, repo)
1685 if defaultrev is not None:
1685 if defaultrev is not None:
1686 revs.append(defaultrev)
1686 revs.append(defaultrev)
1687 if len(revs) != 1:
1687 if len(revs) != 1:
1688 raise error.Abort(
1688 raise error.Abort(
1689 _(b'histedit requires exactly one ancestor revision')
1689 _(b'histedit requires exactly one ancestor revision')
1690 )
1690 )
1691
1691
1692 rr = list(repo.set(b'roots(%ld)', scmutil.revrange(repo, revs)))
1692 rr = list(repo.set(b'roots(%ld)', scmutil.revrange(repo, revs)))
1693 if len(rr) != 1:
1693 if len(rr) != 1:
1694 raise error.Abort(
1694 raise error.Abort(
1695 _(
1695 _(
1696 b'The specified revisions must have '
1696 b'The specified revisions must have '
1697 b'exactly one common root'
1697 b'exactly one common root'
1698 )
1698 )
1699 )
1699 )
1700 root = rr[0].node()
1700 root = rr[0].node()
1701
1701
1702 topmost = repo.dirstate.p1()
1702 topmost = repo.dirstate.p1()
1703 revs = between(repo, root, topmost, keep)
1703 revs = between(repo, root, topmost, keep)
1704 if not revs:
1704 if not revs:
1705 raise error.Abort(
1705 raise error.Abort(
1706 _(b'%s is not an ancestor of working directory')
1706 _(b'%s is not an ancestor of working directory')
1707 % node.short(root)
1707 % node.short(root)
1708 )
1708 )
1709
1709
1710 ctxs = []
1710 ctxs = []
1711 for i, r in enumerate(revs):
1711 for i, r in enumerate(revs):
1712 ctxs.append(histeditrule(ui, repo[r], i))
1712 ctxs.append(histeditrule(ui, repo[r], i))
1713 # Curses requires setting the locale or it will default to the C
1713 # Curses requires setting the locale or it will default to the C
1714 # locale. This sets the locale to the user's default system
1714 # locale. This sets the locale to the user's default system
1715 # locale.
1715 # locale.
1716 locale.setlocale(locale.LC_ALL, '')
1716 locale.setlocale(locale.LC_ALL, '')
1717 rc = curses.wrapper(functools.partial(_chisteditmain, repo, ctxs))
1717 rc = curses.wrapper(functools.partial(_chisteditmain, repo, ctxs))
1718 curses.echo()
1718 curses.echo()
1719 curses.endwin()
1719 curses.endwin()
1720 if rc is False:
1720 if rc is False:
1721 ui.write(_(b"histedit aborted\n"))
1721 ui.write(_(b"histedit aborted\n"))
1722 return 0
1722 return 0
1723 if type(rc) is list:
1723 if type(rc) is list:
1724 ui.status(_(b"performing changes\n"))
1724 ui.status(_(b"performing changes\n"))
1725 rules = makecommands(rc)
1725 rules = makecommands(rc)
1726 with repo.vfs(b'chistedit', b'w+') as fp:
1726 with repo.vfs(b'chistedit', b'w+') as fp:
1727 for r in rules:
1727 for r in rules:
1728 fp.write(r)
1728 fp.write(r)
1729 opts[b'commands'] = fp.name
1729 opts[b'commands'] = fp.name
1730 return _texthistedit(ui, repo, freeargs, opts)
1730 return _texthistedit(ui, repo, freeargs, opts)
1731 except KeyboardInterrupt:
1731 except KeyboardInterrupt:
1732 pass
1732 pass
1733 return -1
1733 return -1
1734
1734
1735
1735
1736 @command(
1736 @command(
1737 b'histedit',
1737 b'histedit',
1738 [
1738 [
1739 (
1739 (
1740 b'',
1740 b'',
1741 b'commands',
1741 b'commands',
1742 b'',
1742 b'',
1743 _(b'read history edits from the specified file'),
1743 _(b'read history edits from the specified file'),
1744 _(b'FILE'),
1744 _(b'FILE'),
1745 ),
1745 ),
1746 (b'c', b'continue', False, _(b'continue an edit already in progress')),
1746 (b'c', b'continue', False, _(b'continue an edit already in progress')),
1747 (b'', b'edit-plan', False, _(b'edit remaining actions list')),
1747 (b'', b'edit-plan', False, _(b'edit remaining actions list')),
1748 (
1748 (
1749 b'k',
1749 b'k',
1750 b'keep',
1750 b'keep',
1751 False,
1751 False,
1752 _(b"don't strip old nodes after edit is complete"),
1752 _(b"don't strip old nodes after edit is complete"),
1753 ),
1753 ),
1754 (b'', b'abort', False, _(b'abort an edit in progress')),
1754 (b'', b'abort', False, _(b'abort an edit in progress')),
1755 (b'o', b'outgoing', False, _(b'changesets not found in destination')),
1755 (b'o', b'outgoing', False, _(b'changesets not found in destination')),
1756 (
1756 (
1757 b'f',
1757 b'f',
1758 b'force',
1758 b'force',
1759 False,
1759 False,
1760 _(b'force outgoing even for unrelated repositories'),
1760 _(b'force outgoing even for unrelated repositories'),
1761 ),
1761 ),
1762 (b'r', b'rev', [], _(b'first revision to be edited'), _(b'REV')),
1762 (b'r', b'rev', [], _(b'first revision to be edited'), _(b'REV')),
1763 ]
1763 ]
1764 + cmdutil.formatteropts,
1764 + cmdutil.formatteropts,
1765 _(b"[OPTIONS] ([ANCESTOR] | --outgoing [URL])"),
1765 _(b"[OPTIONS] ([ANCESTOR] | --outgoing [URL])"),
1766 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
1766 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
1767 )
1767 )
1768 def histedit(ui, repo, *freeargs, **opts):
1768 def histedit(ui, repo, *freeargs, **opts):
1769 """interactively edit changeset history
1769 """interactively edit changeset history
1770
1770
1771 This command lets you edit a linear series of changesets (up to
1771 This command lets you edit a linear series of changesets (up to
1772 and including the working directory, which should be clean).
1772 and including the working directory, which should be clean).
1773 You can:
1773 You can:
1774
1774
1775 - `pick` to [re]order a changeset
1775 - `pick` to [re]order a changeset
1776
1776
1777 - `drop` to omit changeset
1777 - `drop` to omit changeset
1778
1778
1779 - `mess` to reword the changeset commit message
1779 - `mess` to reword the changeset commit message
1780
1780
1781 - `fold` to combine it with the preceding changeset (using the later date)
1781 - `fold` to combine it with the preceding changeset (using the later date)
1782
1782
1783 - `roll` like fold, but discarding this commit's description and date
1783 - `roll` like fold, but discarding this commit's description and date
1784
1784
1785 - `edit` to edit this changeset (preserving date)
1785 - `edit` to edit this changeset (preserving date)
1786
1786
1787 - `base` to checkout changeset and apply further changesets from there
1787 - `base` to checkout changeset and apply further changesets from there
1788
1788
1789 There are a number of ways to select the root changeset:
1789 There are a number of ways to select the root changeset:
1790
1790
1791 - Specify ANCESTOR directly
1791 - Specify ANCESTOR directly
1792
1792
1793 - Use --outgoing -- it will be the first linear changeset not
1793 - Use --outgoing -- it will be the first linear changeset not
1794 included in destination. (See :hg:`help config.paths.default-push`)
1794 included in destination. (See :hg:`help config.paths.default-push`)
1795
1795
1796 - Otherwise, the value from the "histedit.defaultrev" config option
1796 - Otherwise, the value from the "histedit.defaultrev" config option
1797 is used as a revset to select the base revision when ANCESTOR is not
1797 is used as a revset to select the base revision when ANCESTOR is not
1798 specified. The first revision returned by the revset is used. By
1798 specified. The first revision returned by the revset is used. By
1799 default, this selects the editable history that is unique to the
1799 default, this selects the editable history that is unique to the
1800 ancestry of the working directory.
1800 ancestry of the working directory.
1801
1801
1802 .. container:: verbose
1802 .. container:: verbose
1803
1803
1804 If you use --outgoing, this command will abort if there are ambiguous
1804 If you use --outgoing, this command will abort if there are ambiguous
1805 outgoing revisions. For example, if there are multiple branches
1805 outgoing revisions. For example, if there are multiple branches
1806 containing outgoing revisions.
1806 containing outgoing revisions.
1807
1807
1808 Use "min(outgoing() and ::.)" or similar revset specification
1808 Use "min(outgoing() and ::.)" or similar revset specification
1809 instead of --outgoing to specify edit target revision exactly in
1809 instead of --outgoing to specify edit target revision exactly in
1810 such ambiguous situation. See :hg:`help revsets` for detail about
1810 such ambiguous situation. See :hg:`help revsets` for detail about
1811 selecting revisions.
1811 selecting revisions.
1812
1812
1813 .. container:: verbose
1813 .. container:: verbose
1814
1814
1815 Examples:
1815 Examples:
1816
1816
1817 - A number of changes have been made.
1817 - A number of changes have been made.
1818 Revision 3 is no longer needed.
1818 Revision 3 is no longer needed.
1819
1819
1820 Start history editing from revision 3::
1820 Start history editing from revision 3::
1821
1821
1822 hg histedit -r 3
1822 hg histedit -r 3
1823
1823
1824 An editor opens, containing the list of revisions,
1824 An editor opens, containing the list of revisions,
1825 with specific actions specified::
1825 with specific actions specified::
1826
1826
1827 pick 5339bf82f0ca 3 Zworgle the foobar
1827 pick 5339bf82f0ca 3 Zworgle the foobar
1828 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1828 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1829 pick 0a9639fcda9d 5 Morgify the cromulancy
1829 pick 0a9639fcda9d 5 Morgify the cromulancy
1830
1830
1831 Additional information about the possible actions
1831 Additional information about the possible actions
1832 to take appears below the list of revisions.
1832 to take appears below the list of revisions.
1833
1833
1834 To remove revision 3 from the history,
1834 To remove revision 3 from the history,
1835 its action (at the beginning of the relevant line)
1835 its action (at the beginning of the relevant line)
1836 is changed to 'drop'::
1836 is changed to 'drop'::
1837
1837
1838 drop 5339bf82f0ca 3 Zworgle the foobar
1838 drop 5339bf82f0ca 3 Zworgle the foobar
1839 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1839 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1840 pick 0a9639fcda9d 5 Morgify the cromulancy
1840 pick 0a9639fcda9d 5 Morgify the cromulancy
1841
1841
1842 - A number of changes have been made.
1842 - A number of changes have been made.
1843 Revision 2 and 4 need to be swapped.
1843 Revision 2 and 4 need to be swapped.
1844
1844
1845 Start history editing from revision 2::
1845 Start history editing from revision 2::
1846
1846
1847 hg histedit -r 2
1847 hg histedit -r 2
1848
1848
1849 An editor opens, containing the list of revisions,
1849 An editor opens, containing the list of revisions,
1850 with specific actions specified::
1850 with specific actions specified::
1851
1851
1852 pick 252a1af424ad 2 Blorb a morgwazzle
1852 pick 252a1af424ad 2 Blorb a morgwazzle
1853 pick 5339bf82f0ca 3 Zworgle the foobar
1853 pick 5339bf82f0ca 3 Zworgle the foobar
1854 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1854 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1855
1855
1856 To swap revision 2 and 4, its lines are swapped
1856 To swap revision 2 and 4, its lines are swapped
1857 in the editor::
1857 in the editor::
1858
1858
1859 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1859 pick 8ef592ce7cc4 4 Bedazzle the zerlog
1860 pick 5339bf82f0ca 3 Zworgle the foobar
1860 pick 5339bf82f0ca 3 Zworgle the foobar
1861 pick 252a1af424ad 2 Blorb a morgwazzle
1861 pick 252a1af424ad 2 Blorb a morgwazzle
1862
1862
1863 Returns 0 on success, 1 if user intervention is required (not only
1863 Returns 0 on success, 1 if user intervention is required (not only
1864 for intentional "edit" command, but also for resolving unexpected
1864 for intentional "edit" command, but also for resolving unexpected
1865 conflicts).
1865 conflicts).
1866 """
1866 """
1867 opts = pycompat.byteskwargs(opts)
1867 opts = pycompat.byteskwargs(opts)
1868
1868
1869 # kludge: _chistedit only works for starting an edit, not aborting
1869 # kludge: _chistedit only works for starting an edit, not aborting
1870 # or continuing, so fall back to regular _texthistedit for those
1870 # or continuing, so fall back to regular _texthistedit for those
1871 # operations.
1871 # operations.
1872 if ui.interface(b'histedit') == b'curses' and _getgoal(opts) == goalnew:
1872 if ui.interface(b'histedit') == b'curses' and _getgoal(opts) == goalnew:
1873 return _chistedit(ui, repo, freeargs, opts)
1873 return _chistedit(ui, repo, freeargs, opts)
1874 return _texthistedit(ui, repo, freeargs, opts)
1874 return _texthistedit(ui, repo, freeargs, opts)
1875
1875
1876
1876
1877 def _texthistedit(ui, repo, freeargs, opts):
1877 def _texthistedit(ui, repo, freeargs, opts):
1878 state = histeditstate(repo)
1878 state = histeditstate(repo)
1879 with repo.wlock() as wlock, repo.lock() as lock:
1879 with repo.wlock() as wlock, repo.lock() as lock:
1880 state.wlock = wlock
1880 state.wlock = wlock
1881 state.lock = lock
1881 state.lock = lock
1882 _histedit(ui, repo, state, freeargs, opts)
1882 _histedit(ui, repo, state, freeargs, opts)
1883
1883
1884
1884
1885 goalcontinue = b'continue'
1885 goalcontinue = b'continue'
1886 goalabort = b'abort'
1886 goalabort = b'abort'
1887 goaleditplan = b'edit-plan'
1887 goaleditplan = b'edit-plan'
1888 goalnew = b'new'
1888 goalnew = b'new'
1889
1889
1890
1890
1891 def _getgoal(opts):
1891 def _getgoal(opts):
1892 if opts.get(b'continue'):
1892 if opts.get(b'continue'):
1893 return goalcontinue
1893 return goalcontinue
1894 if opts.get(b'abort'):
1894 if opts.get(b'abort'):
1895 return goalabort
1895 return goalabort
1896 if opts.get(b'edit_plan'):
1896 if opts.get(b'edit_plan'):
1897 return goaleditplan
1897 return goaleditplan
1898 return goalnew
1898 return goalnew
1899
1899
1900
1900
1901 def _readfile(ui, path):
1901 def _readfile(ui, path):
1902 if path == b'-':
1902 if path == b'-':
1903 with ui.timeblockedsection(b'histedit'):
1903 with ui.timeblockedsection(b'histedit'):
1904 return ui.fin.read()
1904 return ui.fin.read()
1905 else:
1905 else:
1906 with open(path, b'rb') as f:
1906 with open(path, b'rb') as f:
1907 return f.read()
1907 return f.read()
1908
1908
1909
1909
1910 def _validateargs(ui, repo, state, freeargs, opts, goal, rules, revs):
1910 def _validateargs(ui, repo, state, freeargs, opts, goal, rules, revs):
1911 # TODO only abort if we try to histedit mq patches, not just
1911 # TODO only abort if we try to histedit mq patches, not just
1912 # blanket if mq patches are applied somewhere
1912 # blanket if mq patches are applied somewhere
1913 mq = getattr(repo, 'mq', None)
1913 mq = getattr(repo, 'mq', None)
1914 if mq and mq.applied:
1914 if mq and mq.applied:
1915 raise error.Abort(_(b'source has mq patches applied'))
1915 raise error.Abort(_(b'source has mq patches applied'))
1916
1916
1917 # basic argument incompatibility processing
1917 # basic argument incompatibility processing
1918 outg = opts.get(b'outgoing')
1918 outg = opts.get(b'outgoing')
1919 editplan = opts.get(b'edit_plan')
1919 editplan = opts.get(b'edit_plan')
1920 abort = opts.get(b'abort')
1920 abort = opts.get(b'abort')
1921 force = opts.get(b'force')
1921 force = opts.get(b'force')
1922 if force and not outg:
1922 if force and not outg:
1923 raise error.Abort(_(b'--force only allowed with --outgoing'))
1923 raise error.Abort(_(b'--force only allowed with --outgoing'))
1924 if goal == b'continue':
1924 if goal == b'continue':
1925 if any((outg, abort, revs, freeargs, rules, editplan)):
1925 if any((outg, abort, revs, freeargs, rules, editplan)):
1926 raise error.Abort(_(b'no arguments allowed with --continue'))
1926 raise error.Abort(_(b'no arguments allowed with --continue'))
1927 elif goal == b'abort':
1927 elif goal == b'abort':
1928 if any((outg, revs, freeargs, rules, editplan)):
1928 if any((outg, revs, freeargs, rules, editplan)):
1929 raise error.Abort(_(b'no arguments allowed with --abort'))
1929 raise error.Abort(_(b'no arguments allowed with --abort'))
1930 elif goal == b'edit-plan':
1930 elif goal == b'edit-plan':
1931 if any((outg, revs, freeargs)):
1931 if any((outg, revs, freeargs)):
1932 raise error.Abort(
1932 raise error.Abort(
1933 _(b'only --commands argument allowed with --edit-plan')
1933 _(b'only --commands argument allowed with --edit-plan')
1934 )
1934 )
1935 else:
1935 else:
1936 if state.inprogress():
1936 if state.inprogress():
1937 raise error.Abort(
1937 raise error.Abort(
1938 _(
1938 _(
1939 b'history edit already in progress, try '
1939 b'history edit already in progress, try '
1940 b'--continue or --abort'
1940 b'--continue or --abort'
1941 )
1941 )
1942 )
1942 )
1943 if outg:
1943 if outg:
1944 if revs:
1944 if revs:
1945 raise error.Abort(_(b'no revisions allowed with --outgoing'))
1945 raise error.Abort(_(b'no revisions allowed with --outgoing'))
1946 if len(freeargs) > 1:
1946 if len(freeargs) > 1:
1947 raise error.Abort(
1947 raise error.Abort(
1948 _(b'only one repo argument allowed with --outgoing')
1948 _(b'only one repo argument allowed with --outgoing')
1949 )
1949 )
1950 else:
1950 else:
1951 revs.extend(freeargs)
1951 revs.extend(freeargs)
1952 if len(revs) == 0:
1952 if len(revs) == 0:
1953 defaultrev = destutil.desthistedit(ui, repo)
1953 defaultrev = destutil.desthistedit(ui, repo)
1954 if defaultrev is not None:
1954 if defaultrev is not None:
1955 revs.append(defaultrev)
1955 revs.append(defaultrev)
1956
1956
1957 if len(revs) != 1:
1957 if len(revs) != 1:
1958 raise error.Abort(
1958 raise error.Abort(
1959 _(b'histedit requires exactly one ancestor revision')
1959 _(b'histedit requires exactly one ancestor revision')
1960 )
1960 )
1961
1961
1962
1962
1963 def _histedit(ui, repo, state, freeargs, opts):
1963 def _histedit(ui, repo, state, freeargs, opts):
1964 fm = ui.formatter(b'histedit', opts)
1964 fm = ui.formatter(b'histedit', opts)
1965 fm.startitem()
1965 fm.startitem()
1966 goal = _getgoal(opts)
1966 goal = _getgoal(opts)
1967 revs = opts.get(b'rev', [])
1967 revs = opts.get(b'rev', [])
1968 nobackup = not ui.configbool(b'rewrite', b'backup-bundle')
1968 nobackup = not ui.configbool(b'rewrite', b'backup-bundle')
1969 rules = opts.get(b'commands', b'')
1969 rules = opts.get(b'commands', b'')
1970 state.keep = opts.get(b'keep', False)
1970 state.keep = opts.get(b'keep', False)
1971
1971
1972 _validateargs(ui, repo, state, freeargs, opts, goal, rules, revs)
1972 _validateargs(ui, repo, state, freeargs, opts, goal, rules, revs)
1973
1973
1974 hastags = False
1974 hastags = False
1975 if revs:
1975 if revs:
1976 revs = scmutil.revrange(repo, revs)
1976 revs = scmutil.revrange(repo, revs)
1977 ctxs = [repo[rev] for rev in revs]
1977 ctxs = [repo[rev] for rev in revs]
1978 for ctx in ctxs:
1978 for ctx in ctxs:
1979 tags = [tag for tag in ctx.tags() if tag != b'tip']
1979 tags = [tag for tag in ctx.tags() if tag != b'tip']
1980 if not hastags:
1980 if not hastags:
1981 hastags = len(tags)
1981 hastags = len(tags)
1982 if hastags:
1982 if hastags:
1983 if ui.promptchoice(
1983 if ui.promptchoice(
1984 _(
1984 _(
1985 b'warning: tags associated with the given'
1985 b'warning: tags associated with the given'
1986 b' changeset will be lost after histedit.\n'
1986 b' changeset will be lost after histedit.\n'
1987 b'do you want to continue (yN)? $$ &Yes $$ &No'
1987 b'do you want to continue (yN)? $$ &Yes $$ &No'
1988 ),
1988 ),
1989 default=1,
1989 default=1,
1990 ):
1990 ):
1991 raise error.Abort(_(b'histedit cancelled\n'))
1991 raise error.Abort(_(b'histedit cancelled\n'))
1992 # rebuild state
1992 # rebuild state
1993 if goal == goalcontinue:
1993 if goal == goalcontinue:
1994 state.read()
1994 state.read()
1995 state = bootstrapcontinue(ui, state, opts)
1995 state = bootstrapcontinue(ui, state, opts)
1996 elif goal == goaleditplan:
1996 elif goal == goaleditplan:
1997 _edithisteditplan(ui, repo, state, rules)
1997 _edithisteditplan(ui, repo, state, rules)
1998 return
1998 return
1999 elif goal == goalabort:
1999 elif goal == goalabort:
2000 _aborthistedit(ui, repo, state, nobackup=nobackup)
2000 _aborthistedit(ui, repo, state, nobackup=nobackup)
2001 return
2001 return
2002 else:
2002 else:
2003 # goal == goalnew
2003 # goal == goalnew
2004 _newhistedit(ui, repo, state, revs, freeargs, opts)
2004 _newhistedit(ui, repo, state, revs, freeargs, opts)
2005
2005
2006 _continuehistedit(ui, repo, state)
2006 _continuehistedit(ui, repo, state)
2007 _finishhistedit(ui, repo, state, fm)
2007 _finishhistedit(ui, repo, state, fm)
2008 fm.end()
2008 fm.end()
2009
2009
2010
2010
2011 def _continuehistedit(ui, repo, state):
2011 def _continuehistedit(ui, repo, state):
2012 """This function runs after either:
2012 """This function runs after either:
2013 - bootstrapcontinue (if the goal is 'continue')
2013 - bootstrapcontinue (if the goal is 'continue')
2014 - _newhistedit (if the goal is 'new')
2014 - _newhistedit (if the goal is 'new')
2015 """
2015 """
2016 # preprocess rules so that we can hide inner folds from the user
2016 # preprocess rules so that we can hide inner folds from the user
2017 # and only show one editor
2017 # and only show one editor
2018 actions = state.actions[:]
2018 actions = state.actions[:]
2019 for idx, (action, nextact) in enumerate(zip(actions, actions[1:] + [None])):
2019 for idx, (action, nextact) in enumerate(zip(actions, actions[1:] + [None])):
2020 if action.verb == b'fold' and nextact and nextact.verb == b'fold':
2020 if action.verb == b'fold' and nextact and nextact.verb == b'fold':
2021 state.actions[idx].__class__ = _multifold
2021 state.actions[idx].__class__ = _multifold
2022
2022
2023 # Force an initial state file write, so the user can run --abort/continue
2023 # Force an initial state file write, so the user can run --abort/continue
2024 # even if there's an exception before the first transaction serialize.
2024 # even if there's an exception before the first transaction serialize.
2025 state.write()
2025 state.write()
2026
2026
2027 tr = None
2027 tr = None
2028 # Don't use singletransaction by default since it rolls the entire
2028 # Don't use singletransaction by default since it rolls the entire
2029 # transaction back if an unexpected exception happens (like a
2029 # transaction back if an unexpected exception happens (like a
2030 # pretxncommit hook throws, or the user aborts the commit msg editor).
2030 # pretxncommit hook throws, or the user aborts the commit msg editor).
2031 if ui.configbool(b"histedit", b"singletransaction"):
2031 if ui.configbool(b"histedit", b"singletransaction"):
2032 # Don't use a 'with' for the transaction, since actions may close
2032 # Don't use a 'with' for the transaction, since actions may close
2033 # and reopen a transaction. For example, if the action executes an
2033 # and reopen a transaction. For example, if the action executes an
2034 # external process it may choose to commit the transaction first.
2034 # external process it may choose to commit the transaction first.
2035 tr = repo.transaction(b'histedit')
2035 tr = repo.transaction(b'histedit')
2036 progress = ui.makeprogress(
2036 progress = ui.makeprogress(
2037 _(b"editing"), unit=_(b'changes'), total=len(state.actions)
2037 _(b"editing"), unit=_(b'changes'), total=len(state.actions)
2038 )
2038 )
2039 with progress, util.acceptintervention(tr):
2039 with progress, util.acceptintervention(tr):
2040 while state.actions:
2040 while state.actions:
2041 state.write(tr=tr)
2041 state.write(tr=tr)
2042 actobj = state.actions[0]
2042 actobj = state.actions[0]
2043 progress.increment(item=actobj.torule())
2043 progress.increment(item=actobj.torule())
2044 ui.debug(
2044 ui.debug(
2045 b'histedit: processing %s %s\n' % (actobj.verb, actobj.torule())
2045 b'histedit: processing %s %s\n' % (actobj.verb, actobj.torule())
2046 )
2046 )
2047 parentctx, replacement_ = actobj.run()
2047 parentctx, replacement_ = actobj.run()
2048 state.parentctxnode = parentctx.node()
2048 state.parentctxnode = parentctx.node()
2049 state.replacements.extend(replacement_)
2049 state.replacements.extend(replacement_)
2050 state.actions.pop(0)
2050 state.actions.pop(0)
2051
2051
2052 state.write()
2052 state.write()
2053
2053
2054
2054
2055 def _finishhistedit(ui, repo, state, fm):
2055 def _finishhistedit(ui, repo, state, fm):
2056 """This action runs when histedit is finishing its session"""
2056 """This action runs when histedit is finishing its session"""
2057 hg.updaterepo(repo, state.parentctxnode, overwrite=False)
2057 hg.updaterepo(repo, state.parentctxnode, overwrite=False)
2058
2058
2059 mapping, tmpnodes, created, ntm = processreplacement(state)
2059 mapping, tmpnodes, created, ntm = processreplacement(state)
2060 if mapping:
2060 if mapping:
2061 for prec, succs in pycompat.iteritems(mapping):
2061 for prec, succs in pycompat.iteritems(mapping):
2062 if not succs:
2062 if not succs:
2063 ui.debug(b'histedit: %s is dropped\n' % node.short(prec))
2063 ui.debug(b'histedit: %s is dropped\n' % node.short(prec))
2064 else:
2064 else:
2065 ui.debug(
2065 ui.debug(
2066 b'histedit: %s is replaced by %s\n'
2066 b'histedit: %s is replaced by %s\n'
2067 % (node.short(prec), node.short(succs[0]))
2067 % (node.short(prec), node.short(succs[0]))
2068 )
2068 )
2069 if len(succs) > 1:
2069 if len(succs) > 1:
2070 m = b'histedit: %s'
2070 m = b'histedit: %s'
2071 for n in succs[1:]:
2071 for n in succs[1:]:
2072 ui.debug(m % node.short(n))
2072 ui.debug(m % node.short(n))
2073
2073
2074 if not state.keep:
2074 if not state.keep:
2075 if mapping:
2075 if mapping:
2076 movetopmostbookmarks(repo, state.topmost, ntm)
2076 movetopmostbookmarks(repo, state.topmost, ntm)
2077 # TODO update mq state
2077 # TODO update mq state
2078 else:
2078 else:
2079 mapping = {}
2079 mapping = {}
2080
2080
2081 for n in tmpnodes:
2081 for n in tmpnodes:
2082 if n in repo:
2082 if n in repo:
2083 mapping[n] = ()
2083 mapping[n] = ()
2084
2084
2085 # remove entries about unknown nodes
2085 # remove entries about unknown nodes
2086 has_node = repo.unfiltered().changelog.index.has_node
2086 has_node = repo.unfiltered().changelog.index.has_node
2087 mapping = {
2087 mapping = {
2088 k: v
2088 k: v
2089 for k, v in mapping.items()
2089 for k, v in mapping.items()
2090 if has_node(k) and all(has_node(n) for n in v)
2090 if has_node(k) and all(has_node(n) for n in v)
2091 }
2091 }
2092 scmutil.cleanupnodes(repo, mapping, b'histedit')
2092 scmutil.cleanupnodes(repo, mapping, b'histedit')
2093 hf = fm.hexfunc
2093 hf = fm.hexfunc
2094 fl = fm.formatlist
2094 fl = fm.formatlist
2095 fd = fm.formatdict
2095 fd = fm.formatdict
2096 nodechanges = fd(
2096 nodechanges = fd(
2097 {
2097 {
2098 hf(oldn): fl([hf(n) for n in newn], name=b'node')
2098 hf(oldn): fl([hf(n) for n in newn], name=b'node')
2099 for oldn, newn in pycompat.iteritems(mapping)
2099 for oldn, newn in pycompat.iteritems(mapping)
2100 },
2100 },
2101 key=b"oldnode",
2101 key=b"oldnode",
2102 value=b"newnodes",
2102 value=b"newnodes",
2103 )
2103 )
2104 fm.data(nodechanges=nodechanges)
2104 fm.data(nodechanges=nodechanges)
2105
2105
2106 state.clear()
2106 state.clear()
2107 if os.path.exists(repo.sjoin(b'undo')):
2107 if os.path.exists(repo.sjoin(b'undo')):
2108 os.unlink(repo.sjoin(b'undo'))
2108 os.unlink(repo.sjoin(b'undo'))
2109 if repo.vfs.exists(b'histedit-last-edit.txt'):
2109 if repo.vfs.exists(b'histedit-last-edit.txt'):
2110 repo.vfs.unlink(b'histedit-last-edit.txt')
2110 repo.vfs.unlink(b'histedit-last-edit.txt')
2111
2111
2112
2112
2113 def _aborthistedit(ui, repo, state, nobackup=False):
2113 def _aborthistedit(ui, repo, state, nobackup=False):
2114 try:
2114 try:
2115 state.read()
2115 state.read()
2116 __, leafs, tmpnodes, __ = processreplacement(state)
2116 __, leafs, tmpnodes, __ = processreplacement(state)
2117 ui.debug(b'restore wc to old parent %s\n' % node.short(state.topmost))
2117 ui.debug(b'restore wc to old parent %s\n' % node.short(state.topmost))
2118
2118
2119 # Recover our old commits if necessary
2119 # Recover our old commits if necessary
2120 if not state.topmost in repo and state.backupfile:
2120 if not state.topmost in repo and state.backupfile:
2121 backupfile = repo.vfs.join(state.backupfile)
2121 backupfile = repo.vfs.join(state.backupfile)
2122 f = hg.openpath(ui, backupfile)
2122 f = hg.openpath(ui, backupfile)
2123 gen = exchange.readbundle(ui, f, backupfile)
2123 gen = exchange.readbundle(ui, f, backupfile)
2124 with repo.transaction(b'histedit.abort') as tr:
2124 with repo.transaction(b'histedit.abort') as tr:
2125 bundle2.applybundle(
2125 bundle2.applybundle(
2126 repo,
2126 repo,
2127 gen,
2127 gen,
2128 tr,
2128 tr,
2129 source=b'histedit',
2129 source=b'histedit',
2130 url=b'bundle:' + backupfile,
2130 url=b'bundle:' + backupfile,
2131 )
2131 )
2132
2132
2133 os.remove(backupfile)
2133 os.remove(backupfile)
2134
2134
2135 # check whether we should update away
2135 # check whether we should update away
2136 if repo.unfiltered().revs(
2136 if repo.unfiltered().revs(
2137 b'parents() and (%n or %ln::)',
2137 b'parents() and (%n or %ln::)',
2138 state.parentctxnode,
2138 state.parentctxnode,
2139 leafs | tmpnodes,
2139 leafs | tmpnodes,
2140 ):
2140 ):
2141 hg.clean(repo, state.topmost, show_stats=True, quietempty=True)
2141 hg.clean(repo, state.topmost, show_stats=True, quietempty=True)
2142 cleanupnode(ui, repo, tmpnodes, nobackup=nobackup)
2142 cleanupnode(ui, repo, tmpnodes, nobackup=nobackup)
2143 cleanupnode(ui, repo, leafs, nobackup=nobackup)
2143 cleanupnode(ui, repo, leafs, nobackup=nobackup)
2144 except Exception:
2144 except Exception:
2145 if state.inprogress():
2145 if state.inprogress():
2146 ui.warn(
2146 ui.warn(
2147 _(
2147 _(
2148 b'warning: encountered an exception during histedit '
2148 b'warning: encountered an exception during histedit '
2149 b'--abort; the repository may not have been completely '
2149 b'--abort; the repository may not have been completely '
2150 b'cleaned up\n'
2150 b'cleaned up\n'
2151 )
2151 )
2152 )
2152 )
2153 raise
2153 raise
2154 finally:
2154 finally:
2155 state.clear()
2155 state.clear()
2156
2156
2157
2157
2158 def hgaborthistedit(ui, repo):
2158 def hgaborthistedit(ui, repo):
2159 state = histeditstate(repo)
2159 state = histeditstate(repo)
2160 nobackup = not ui.configbool(b'rewrite', b'backup-bundle')
2160 nobackup = not ui.configbool(b'rewrite', b'backup-bundle')
2161 with repo.wlock() as wlock, repo.lock() as lock:
2161 with repo.wlock() as wlock, repo.lock() as lock:
2162 state.wlock = wlock
2162 state.wlock = wlock
2163 state.lock = lock
2163 state.lock = lock
2164 _aborthistedit(ui, repo, state, nobackup=nobackup)
2164 _aborthistedit(ui, repo, state, nobackup=nobackup)
2165
2165
2166
2166
2167 def _edithisteditplan(ui, repo, state, rules):
2167 def _edithisteditplan(ui, repo, state, rules):
2168 state.read()
2168 state.read()
2169 if not rules:
2169 if not rules:
2170 comment = geteditcomment(
2170 comment = geteditcomment(
2171 ui, node.short(state.parentctxnode), node.short(state.topmost)
2171 ui, node.short(state.parentctxnode), node.short(state.topmost)
2172 )
2172 )
2173 rules = ruleeditor(repo, ui, state.actions, comment)
2173 rules = ruleeditor(repo, ui, state.actions, comment)
2174 else:
2174 else:
2175 rules = _readfile(ui, rules)
2175 rules = _readfile(ui, rules)
2176 actions = parserules(rules, state)
2176 actions = parserules(rules, state)
2177 ctxs = [repo[act.node] for act in state.actions if act.node]
2177 ctxs = [repo[act.node] for act in state.actions if act.node]
2178 warnverifyactions(ui, repo, actions, state, ctxs)
2178 warnverifyactions(ui, repo, actions, state, ctxs)
2179 state.actions = actions
2179 state.actions = actions
2180 state.write()
2180 state.write()
2181
2181
2182
2182
2183 def _newhistedit(ui, repo, state, revs, freeargs, opts):
2183 def _newhistedit(ui, repo, state, revs, freeargs, opts):
2184 outg = opts.get(b'outgoing')
2184 outg = opts.get(b'outgoing')
2185 rules = opts.get(b'commands', b'')
2185 rules = opts.get(b'commands', b'')
2186 force = opts.get(b'force')
2186 force = opts.get(b'force')
2187
2187
2188 cmdutil.checkunfinished(repo)
2188 cmdutil.checkunfinished(repo)
2189 cmdutil.bailifchanged(repo)
2189 cmdutil.bailifchanged(repo)
2190
2190
2191 topmost = repo.dirstate.p1()
2191 topmost = repo.dirstate.p1()
2192 if outg:
2192 if outg:
2193 if freeargs:
2193 if freeargs:
2194 remote = freeargs[0]
2194 remote = freeargs[0]
2195 else:
2195 else:
2196 remote = None
2196 remote = None
2197 root = findoutgoing(ui, repo, remote, force, opts)
2197 root = findoutgoing(ui, repo, remote, force, opts)
2198 else:
2198 else:
2199 rr = list(repo.set(b'roots(%ld)', scmutil.revrange(repo, revs)))
2199 rr = list(repo.set(b'roots(%ld)', scmutil.revrange(repo, revs)))
2200 if len(rr) != 1:
2200 if len(rr) != 1:
2201 raise error.Abort(
2201 raise error.Abort(
2202 _(
2202 _(
2203 b'The specified revisions must have '
2203 b'The specified revisions must have '
2204 b'exactly one common root'
2204 b'exactly one common root'
2205 )
2205 )
2206 )
2206 )
2207 root = rr[0].node()
2207 root = rr[0].node()
2208
2208
2209 revs = between(repo, root, topmost, state.keep)
2209 revs = between(repo, root, topmost, state.keep)
2210 if not revs:
2210 if not revs:
2211 raise error.Abort(
2211 raise error.Abort(
2212 _(b'%s is not an ancestor of working directory') % node.short(root)
2212 _(b'%s is not an ancestor of working directory') % node.short(root)
2213 )
2213 )
2214
2214
2215 ctxs = [repo[r] for r in revs]
2215 ctxs = [repo[r] for r in revs]
2216
2216
2217 wctx = repo[None]
2217 wctx = repo[None]
2218 # Please don't ask me why `ancestors` is this value. I figured it
2218 # Please don't ask me why `ancestors` is this value. I figured it
2219 # out with print-debugging, not by actually understanding what the
2219 # out with print-debugging, not by actually understanding what the
2220 # merge code is doing. :(
2220 # merge code is doing. :(
2221 ancs = [repo[b'.']]
2221 ancs = [repo[b'.']]
2222 # Sniff-test to make sure we won't collide with untracked files in
2222 # Sniff-test to make sure we won't collide with untracked files in
2223 # the working directory. If we don't do this, we can get a
2223 # the working directory. If we don't do this, we can get a
2224 # collision after we've started histedit and backing out gets ugly
2224 # collision after we've started histedit and backing out gets ugly
2225 # for everyone, especially the user.
2225 # for everyone, especially the user.
2226 for c in [ctxs[0].p1()] + ctxs:
2226 for c in [ctxs[0].p1()] + ctxs:
2227 try:
2227 try:
2228 mergemod.calculateupdates(
2228 mergemod.calculateupdates(
2229 repo,
2229 repo,
2230 wctx,
2230 wctx,
2231 c,
2231 c,
2232 ancs,
2232 ancs,
2233 # These parameters were determined by print-debugging
2233 # These parameters were determined by print-debugging
2234 # what happens later on inside histedit.
2234 # what happens later on inside histedit.
2235 branchmerge=False,
2235 branchmerge=False,
2236 force=False,
2236 force=False,
2237 acceptremote=False,
2237 acceptremote=False,
2238 followcopies=False,
2238 followcopies=False,
2239 )
2239 )
2240 except error.Abort:
2240 except error.Abort:
2241 raise error.Abort(
2241 raise error.Abort(
2242 _(
2242 _(
2243 b"untracked files in working directory conflict with files in %s"
2243 b"untracked files in working directory conflict with files in %s"
2244 )
2244 )
2245 % c
2245 % c
2246 )
2246 )
2247
2247
2248 if not rules:
2248 if not rules:
2249 comment = geteditcomment(ui, node.short(root), node.short(topmost))
2249 comment = geteditcomment(ui, node.short(root), node.short(topmost))
2250 actions = [pick(state, r) for r in revs]
2250 actions = [pick(state, r) for r in revs]
2251 rules = ruleeditor(repo, ui, actions, comment)
2251 rules = ruleeditor(repo, ui, actions, comment)
2252 else:
2252 else:
2253 rules = _readfile(ui, rules)
2253 rules = _readfile(ui, rules)
2254 actions = parserules(rules, state)
2254 actions = parserules(rules, state)
2255 warnverifyactions(ui, repo, actions, state, ctxs)
2255 warnverifyactions(ui, repo, actions, state, ctxs)
2256
2256
2257 parentctxnode = repo[root].p1().node()
2257 parentctxnode = repo[root].p1().node()
2258
2258
2259 state.parentctxnode = parentctxnode
2259 state.parentctxnode = parentctxnode
2260 state.actions = actions
2260 state.actions = actions
2261 state.topmost = topmost
2261 state.topmost = topmost
2262 state.replacements = []
2262 state.replacements = []
2263
2263
2264 ui.log(
2264 ui.log(
2265 b"histedit",
2265 b"histedit",
2266 b"%d actions to histedit\n",
2266 b"%d actions to histedit\n",
2267 len(actions),
2267 len(actions),
2268 histedit_num_actions=len(actions),
2268 histedit_num_actions=len(actions),
2269 )
2269 )
2270
2270
2271 # Create a backup so we can always abort completely.
2271 # Create a backup so we can always abort completely.
2272 backupfile = None
2272 backupfile = None
2273 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2273 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2274 backupfile = repair.backupbundle(
2274 backupfile = repair.backupbundle(
2275 repo, [parentctxnode], [topmost], root, b'histedit'
2275 repo, [parentctxnode], [topmost], root, b'histedit'
2276 )
2276 )
2277 state.backupfile = backupfile
2277 state.backupfile = backupfile
2278
2278
2279
2279
2280 def _getsummary(ctx):
2280 def _getsummary(ctx):
2281 # a common pattern is to extract the summary but default to the empty
2281 # a common pattern is to extract the summary but default to the empty
2282 # string
2282 # string
2283 summary = ctx.description() or b''
2283 summary = ctx.description() or b''
2284 if summary:
2284 if summary:
2285 summary = summary.splitlines()[0]
2285 summary = summary.splitlines()[0]
2286 return summary
2286 return summary
2287
2287
2288
2288
2289 def bootstrapcontinue(ui, state, opts):
2289 def bootstrapcontinue(ui, state, opts):
2290 repo = state.repo
2290 repo = state.repo
2291
2291
2292 ms = mergemod.mergestate.read(repo)
2292 ms = mergemod.mergestate.read(repo)
2293 mergeutil.checkunresolved(ms)
2293 mergeutil.checkunresolved(ms)
2294
2294
2295 if state.actions:
2295 if state.actions:
2296 actobj = state.actions.pop(0)
2296 actobj = state.actions.pop(0)
2297
2297
2298 if _isdirtywc(repo):
2298 if _isdirtywc(repo):
2299 actobj.continuedirty()
2299 actobj.continuedirty()
2300 if _isdirtywc(repo):
2300 if _isdirtywc(repo):
2301 abortdirty()
2301 abortdirty()
2302
2302
2303 parentctx, replacements = actobj.continueclean()
2303 parentctx, replacements = actobj.continueclean()
2304
2304
2305 state.parentctxnode = parentctx.node()
2305 state.parentctxnode = parentctx.node()
2306 state.replacements.extend(replacements)
2306 state.replacements.extend(replacements)
2307
2307
2308 return state
2308 return state
2309
2309
2310
2310
2311 def between(repo, old, new, keep):
2311 def between(repo, old, new, keep):
2312 """select and validate the set of revision to edit
2312 """select and validate the set of revision to edit
2313
2313
2314 When keep is false, the specified set can't have children."""
2314 When keep is false, the specified set can't have children."""
2315 revs = repo.revs(b'%n::%n', old, new)
2315 revs = repo.revs(b'%n::%n', old, new)
2316 if revs and not keep:
2316 if revs and not keep:
2317 rewriteutil.precheck(repo, revs, b'edit')
2317 rewriteutil.precheck(repo, revs, b'edit')
2318 if repo.revs(b'(%ld) and merge()', revs):
2318 if repo.revs(b'(%ld) and merge()', revs):
2319 raise error.Abort(_(b'cannot edit history that contains merges'))
2319 raise error.Abort(_(b'cannot edit history that contains merges'))
2320 return pycompat.maplist(repo.changelog.node, revs)
2320 return pycompat.maplist(repo.changelog.node, revs)
2321
2321
2322
2322
2323 def ruleeditor(repo, ui, actions, editcomment=b""):
2323 def ruleeditor(repo, ui, actions, editcomment=b""):
2324 """open an editor to edit rules
2324 """open an editor to edit rules
2325
2325
2326 rules are in the format [ [act, ctx], ...] like in state.rules
2326 rules are in the format [ [act, ctx], ...] like in state.rules
2327 """
2327 """
2328 if repo.ui.configbool(b"experimental", b"histedit.autoverb"):
2328 if repo.ui.configbool(b"experimental", b"histedit.autoverb"):
2329 newact = util.sortdict()
2329 newact = util.sortdict()
2330 for act in actions:
2330 for act in actions:
2331 ctx = repo[act.node]
2331 ctx = repo[act.node]
2332 summary = _getsummary(ctx)
2332 summary = _getsummary(ctx)
2333 fword = summary.split(b' ', 1)[0].lower()
2333 fword = summary.split(b' ', 1)[0].lower()
2334 added = False
2334 added = False
2335
2335
2336 # if it doesn't end with the special character '!' just skip this
2336 # if it doesn't end with the special character '!' just skip this
2337 if fword.endswith(b'!'):
2337 if fword.endswith(b'!'):
2338 fword = fword[:-1]
2338 fword = fword[:-1]
2339 if fword in primaryactions | secondaryactions | tertiaryactions:
2339 if fword in primaryactions | secondaryactions | tertiaryactions:
2340 act.verb = fword
2340 act.verb = fword
2341 # get the target summary
2341 # get the target summary
2342 tsum = summary[len(fword) + 1 :].lstrip()
2342 tsum = summary[len(fword) + 1 :].lstrip()
2343 # safe but slow: reverse iterate over the actions so we
2343 # safe but slow: reverse iterate over the actions so we
2344 # don't clash on two commits having the same summary
2344 # don't clash on two commits having the same summary
2345 for na, l in reversed(list(pycompat.iteritems(newact))):
2345 for na, l in reversed(list(pycompat.iteritems(newact))):
2346 actx = repo[na.node]
2346 actx = repo[na.node]
2347 asum = _getsummary(actx)
2347 asum = _getsummary(actx)
2348 if asum == tsum:
2348 if asum == tsum:
2349 added = True
2349 added = True
2350 l.append(act)
2350 l.append(act)
2351 break
2351 break
2352
2352
2353 if not added:
2353 if not added:
2354 newact[act] = []
2354 newact[act] = []
2355
2355
2356 # copy over and flatten the new list
2356 # copy over and flatten the new list
2357 actions = []
2357 actions = []
2358 for na, l in pycompat.iteritems(newact):
2358 for na, l in pycompat.iteritems(newact):
2359 actions.append(na)
2359 actions.append(na)
2360 actions += l
2360 actions += l
2361
2361
2362 rules = b'\n'.join([act.torule() for act in actions])
2362 rules = b'\n'.join([act.torule() for act in actions])
2363 rules += b'\n\n'
2363 rules += b'\n\n'
2364 rules += editcomment
2364 rules += editcomment
2365 rules = ui.edit(
2365 rules = ui.edit(
2366 rules,
2366 rules,
2367 ui.username(),
2367 ui.username(),
2368 {b'prefix': b'histedit'},
2368 {b'prefix': b'histedit'},
2369 repopath=repo.path,
2369 repopath=repo.path,
2370 action=b'histedit',
2370 action=b'histedit',
2371 )
2371 )
2372
2372
2373 # Save edit rules in .hg/histedit-last-edit.txt in case
2373 # Save edit rules in .hg/histedit-last-edit.txt in case
2374 # the user needs to ask for help after something
2374 # the user needs to ask for help after something
2375 # surprising happens.
2375 # surprising happens.
2376 with repo.vfs(b'histedit-last-edit.txt', b'wb') as f:
2376 with repo.vfs(b'histedit-last-edit.txt', b'wb') as f:
2377 f.write(rules)
2377 f.write(rules)
2378
2378
2379 return rules
2379 return rules
2380
2380
2381
2381
2382 def parserules(rules, state):
2382 def parserules(rules, state):
2383 """Read the histedit rules string and return list of action objects """
2383 """Read the histedit rules string and return list of action objects """
2384 rules = [
2384 rules = [
2385 l
2385 l
2386 for l in (r.strip() for r in rules.splitlines())
2386 for l in (r.strip() for r in rules.splitlines())
2387 if l and not l.startswith(b'#')
2387 if l and not l.startswith(b'#')
2388 ]
2388 ]
2389 actions = []
2389 actions = []
2390 for r in rules:
2390 for r in rules:
2391 if b' ' not in r:
2391 if b' ' not in r:
2392 raise error.ParseError(_(b'malformed line "%s"') % r)
2392 raise error.ParseError(_(b'malformed line "%s"') % r)
2393 verb, rest = r.split(b' ', 1)
2393 verb, rest = r.split(b' ', 1)
2394
2394
2395 if verb not in actiontable:
2395 if verb not in actiontable:
2396 raise error.ParseError(_(b'unknown action "%s"') % verb)
2396 raise error.ParseError(_(b'unknown action "%s"') % verb)
2397
2397
2398 action = actiontable[verb].fromrule(state, rest)
2398 action = actiontable[verb].fromrule(state, rest)
2399 actions.append(action)
2399 actions.append(action)
2400 return actions
2400 return actions
2401
2401
2402
2402
2403 def warnverifyactions(ui, repo, actions, state, ctxs):
2403 def warnverifyactions(ui, repo, actions, state, ctxs):
2404 try:
2404 try:
2405 verifyactions(actions, state, ctxs)
2405 verifyactions(actions, state, ctxs)
2406 except error.ParseError:
2406 except error.ParseError:
2407 if repo.vfs.exists(b'histedit-last-edit.txt'):
2407 if repo.vfs.exists(b'histedit-last-edit.txt'):
2408 ui.warn(
2408 ui.warn(
2409 _(
2409 _(
2410 b'warning: histedit rules saved '
2410 b'warning: histedit rules saved '
2411 b'to: .hg/histedit-last-edit.txt\n'
2411 b'to: .hg/histedit-last-edit.txt\n'
2412 )
2412 )
2413 )
2413 )
2414 raise
2414 raise
2415
2415
2416
2416
2417 def verifyactions(actions, state, ctxs):
2417 def verifyactions(actions, state, ctxs):
2418 """Verify that there exists exactly one action per given changeset and
2418 """Verify that there exists exactly one action per given changeset and
2419 other constraints.
2419 other constraints.
2420
2420
2421 Will abort if there are to many or too few rules, a malformed rule,
2421 Will abort if there are to many or too few rules, a malformed rule,
2422 or a rule on a changeset outside of the user-given range.
2422 or a rule on a changeset outside of the user-given range.
2423 """
2423 """
2424 expected = {c.node() for c in ctxs}
2424 expected = {c.node() for c in ctxs}
2425 seen = set()
2425 seen = set()
2426 prev = None
2426 prev = None
2427
2427
2428 if actions and actions[0].verb in [b'roll', b'fold']:
2428 if actions and actions[0].verb in [b'roll', b'fold']:
2429 raise error.ParseError(
2429 raise error.ParseError(
2430 _(b'first changeset cannot use verb "%s"') % actions[0].verb
2430 _(b'first changeset cannot use verb "%s"') % actions[0].verb
2431 )
2431 )
2432
2432
2433 for action in actions:
2433 for action in actions:
2434 action.verify(prev, expected, seen)
2434 action.verify(prev, expected, seen)
2435 prev = action
2435 prev = action
2436 if action.node is not None:
2436 if action.node is not None:
2437 seen.add(action.node)
2437 seen.add(action.node)
2438 missing = sorted(expected - seen) # sort to stabilize output
2438 missing = sorted(expected - seen) # sort to stabilize output
2439
2439
2440 if state.repo.ui.configbool(b'histedit', b'dropmissing'):
2440 if state.repo.ui.configbool(b'histedit', b'dropmissing'):
2441 if len(actions) == 0:
2441 if len(actions) == 0:
2442 raise error.ParseError(
2442 raise error.ParseError(
2443 _(b'no rules provided'),
2443 _(b'no rules provided'),
2444 hint=_(b'use strip extension to remove commits'),
2444 hint=_(b'use strip extension to remove commits'),
2445 )
2445 )
2446
2446
2447 drops = [drop(state, n) for n in missing]
2447 drops = [drop(state, n) for n in missing]
2448 # put the in the beginning so they execute immediately and
2448 # put the in the beginning so they execute immediately and
2449 # don't show in the edit-plan in the future
2449 # don't show in the edit-plan in the future
2450 actions[:0] = drops
2450 actions[:0] = drops
2451 elif missing:
2451 elif missing:
2452 raise error.ParseError(
2452 raise error.ParseError(
2453 _(b'missing rules for changeset %s') % node.short(missing[0]),
2453 _(b'missing rules for changeset %s') % node.short(missing[0]),
2454 hint=_(
2454 hint=_(
2455 b'use "drop %s" to discard, see also: '
2455 b'use "drop %s" to discard, see also: '
2456 b"'hg help -e histedit.config'"
2456 b"'hg help -e histedit.config'"
2457 )
2457 )
2458 % node.short(missing[0]),
2458 % node.short(missing[0]),
2459 )
2459 )
2460
2460
2461
2461
2462 def adjustreplacementsfrommarkers(repo, oldreplacements):
2462 def adjustreplacementsfrommarkers(repo, oldreplacements):
2463 """Adjust replacements from obsolescence markers
2463 """Adjust replacements from obsolescence markers
2464
2464
2465 Replacements structure is originally generated based on
2465 Replacements structure is originally generated based on
2466 histedit's state and does not account for changes that are
2466 histedit's state and does not account for changes that are
2467 not recorded there. This function fixes that by adding
2467 not recorded there. This function fixes that by adding
2468 data read from obsolescence markers"""
2468 data read from obsolescence markers"""
2469 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2469 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2470 return oldreplacements
2470 return oldreplacements
2471
2471
2472 unfi = repo.unfiltered()
2472 unfi = repo.unfiltered()
2473 get_rev = unfi.changelog.index.get_rev
2473 get_rev = unfi.changelog.index.get_rev
2474 obsstore = repo.obsstore
2474 obsstore = repo.obsstore
2475 newreplacements = list(oldreplacements)
2475 newreplacements = list(oldreplacements)
2476 oldsuccs = [r[1] for r in oldreplacements]
2476 oldsuccs = [r[1] for r in oldreplacements]
2477 # successors that have already been added to succstocheck once
2477 # successors that have already been added to succstocheck once
2478 seensuccs = set().union(
2478 seensuccs = set().union(
2479 *oldsuccs
2479 *oldsuccs
2480 ) # create a set from an iterable of tuples
2480 ) # create a set from an iterable of tuples
2481 succstocheck = list(seensuccs)
2481 succstocheck = list(seensuccs)
2482 while succstocheck:
2482 while succstocheck:
2483 n = succstocheck.pop()
2483 n = succstocheck.pop()
2484 missing = get_rev(n) is None
2484 missing = get_rev(n) is None
2485 markers = obsstore.successors.get(n, ())
2485 markers = obsstore.successors.get(n, ())
2486 if missing and not markers:
2486 if missing and not markers:
2487 # dead end, mark it as such
2487 # dead end, mark it as such
2488 newreplacements.append((n, ()))
2488 newreplacements.append((n, ()))
2489 for marker in markers:
2489 for marker in markers:
2490 nsuccs = marker[1]
2490 nsuccs = marker[1]
2491 newreplacements.append((n, nsuccs))
2491 newreplacements.append((n, nsuccs))
2492 for nsucc in nsuccs:
2492 for nsucc in nsuccs:
2493 if nsucc not in seensuccs:
2493 if nsucc not in seensuccs:
2494 seensuccs.add(nsucc)
2494 seensuccs.add(nsucc)
2495 succstocheck.append(nsucc)
2495 succstocheck.append(nsucc)
2496
2496
2497 return newreplacements
2497 return newreplacements
2498
2498
2499
2499
2500 def processreplacement(state):
2500 def processreplacement(state):
2501 """process the list of replacements to return
2501 """process the list of replacements to return
2502
2502
2503 1) the final mapping between original and created nodes
2503 1) the final mapping between original and created nodes
2504 2) the list of temporary node created by histedit
2504 2) the list of temporary node created by histedit
2505 3) the list of new commit created by histedit"""
2505 3) the list of new commit created by histedit"""
2506 replacements = adjustreplacementsfrommarkers(state.repo, state.replacements)
2506 replacements = adjustreplacementsfrommarkers(state.repo, state.replacements)
2507 allsuccs = set()
2507 allsuccs = set()
2508 replaced = set()
2508 replaced = set()
2509 fullmapping = {}
2509 fullmapping = {}
2510 # initialize basic set
2510 # initialize basic set
2511 # fullmapping records all operations recorded in replacement
2511 # fullmapping records all operations recorded in replacement
2512 for rep in replacements:
2512 for rep in replacements:
2513 allsuccs.update(rep[1])
2513 allsuccs.update(rep[1])
2514 replaced.add(rep[0])
2514 replaced.add(rep[0])
2515 fullmapping.setdefault(rep[0], set()).update(rep[1])
2515 fullmapping.setdefault(rep[0], set()).update(rep[1])
2516 new = allsuccs - replaced
2516 new = allsuccs - replaced
2517 tmpnodes = allsuccs & replaced
2517 tmpnodes = allsuccs & replaced
2518 # Reduce content fullmapping into direct relation between original nodes
2518 # Reduce content fullmapping into direct relation between original nodes
2519 # and final node created during history edition
2519 # and final node created during history edition
2520 # Dropped changeset are replaced by an empty list
2520 # Dropped changeset are replaced by an empty list
2521 toproceed = set(fullmapping)
2521 toproceed = set(fullmapping)
2522 final = {}
2522 final = {}
2523 while toproceed:
2523 while toproceed:
2524 for x in list(toproceed):
2524 for x in list(toproceed):
2525 succs = fullmapping[x]
2525 succs = fullmapping[x]
2526 for s in list(succs):
2526 for s in list(succs):
2527 if s in toproceed:
2527 if s in toproceed:
2528 # non final node with unknown closure
2528 # non final node with unknown closure
2529 # We can't process this now
2529 # We can't process this now
2530 break
2530 break
2531 elif s in final:
2531 elif s in final:
2532 # non final node, replace with closure
2532 # non final node, replace with closure
2533 succs.remove(s)
2533 succs.remove(s)
2534 succs.update(final[s])
2534 succs.update(final[s])
2535 else:
2535 else:
2536 final[x] = succs
2536 final[x] = succs
2537 toproceed.remove(x)
2537 toproceed.remove(x)
2538 # remove tmpnodes from final mapping
2538 # remove tmpnodes from final mapping
2539 for n in tmpnodes:
2539 for n in tmpnodes:
2540 del final[n]
2540 del final[n]
2541 # we expect all changes involved in final to exist in the repo
2541 # we expect all changes involved in final to exist in the repo
2542 # turn `final` into list (topologically sorted)
2542 # turn `final` into list (topologically sorted)
2543 get_rev = state.repo.changelog.index.get_rev
2543 get_rev = state.repo.changelog.index.get_rev
2544 for prec, succs in final.items():
2544 for prec, succs in final.items():
2545 final[prec] = sorted(succs, key=get_rev)
2545 final[prec] = sorted(succs, key=get_rev)
2546
2546
2547 # computed topmost element (necessary for bookmark)
2547 # computed topmost element (necessary for bookmark)
2548 if new:
2548 if new:
2549 newtopmost = sorted(new, key=state.repo.changelog.rev)[-1]
2549 newtopmost = sorted(new, key=state.repo.changelog.rev)[-1]
2550 elif not final:
2550 elif not final:
2551 # Nothing rewritten at all. we won't need `newtopmost`
2551 # Nothing rewritten at all. we won't need `newtopmost`
2552 # It is the same as `oldtopmost` and `processreplacement` know it
2552 # It is the same as `oldtopmost` and `processreplacement` know it
2553 newtopmost = None
2553 newtopmost = None
2554 else:
2554 else:
2555 # every body died. The newtopmost is the parent of the root.
2555 # every body died. The newtopmost is the parent of the root.
2556 r = state.repo.changelog.rev
2556 r = state.repo.changelog.rev
2557 newtopmost = state.repo[sorted(final, key=r)[0]].p1().node()
2557 newtopmost = state.repo[sorted(final, key=r)[0]].p1().node()
2558
2558
2559 return final, tmpnodes, new, newtopmost
2559 return final, tmpnodes, new, newtopmost
2560
2560
2561
2561
2562 def movetopmostbookmarks(repo, oldtopmost, newtopmost):
2562 def movetopmostbookmarks(repo, oldtopmost, newtopmost):
2563 """Move bookmark from oldtopmost to newly created topmost
2563 """Move bookmark from oldtopmost to newly created topmost
2564
2564
2565 This is arguably a feature and we may only want that for the active
2565 This is arguably a feature and we may only want that for the active
2566 bookmark. But the behavior is kept compatible with the old version for now.
2566 bookmark. But the behavior is kept compatible with the old version for now.
2567 """
2567 """
2568 if not oldtopmost or not newtopmost:
2568 if not oldtopmost or not newtopmost:
2569 return
2569 return
2570 oldbmarks = repo.nodebookmarks(oldtopmost)
2570 oldbmarks = repo.nodebookmarks(oldtopmost)
2571 if oldbmarks:
2571 if oldbmarks:
2572 with repo.lock(), repo.transaction(b'histedit') as tr:
2572 with repo.lock(), repo.transaction(b'histedit') as tr:
2573 marks = repo._bookmarks
2573 marks = repo._bookmarks
2574 changes = []
2574 changes = []
2575 for name in oldbmarks:
2575 for name in oldbmarks:
2576 changes.append((name, newtopmost))
2576 changes.append((name, newtopmost))
2577 marks.applychanges(repo, tr, changes)
2577 marks.applychanges(repo, tr, changes)
2578
2578
2579
2579
2580 def cleanupnode(ui, repo, nodes, nobackup=False):
2580 def cleanupnode(ui, repo, nodes, nobackup=False):
2581 """strip a group of nodes from the repository
2581 """strip a group of nodes from the repository
2582
2582
2583 The set of node to strip may contains unknown nodes."""
2583 The set of node to strip may contains unknown nodes."""
2584 with repo.lock():
2584 with repo.lock():
2585 # do not let filtering get in the way of the cleanse
2585 # do not let filtering get in the way of the cleanse
2586 # we should probably get rid of obsolescence marker created during the
2586 # we should probably get rid of obsolescence marker created during the
2587 # histedit, but we currently do not have such information.
2587 # histedit, but we currently do not have such information.
2588 repo = repo.unfiltered()
2588 repo = repo.unfiltered()
2589 # Find all nodes that need to be stripped
2589 # Find all nodes that need to be stripped
2590 # (we use %lr instead of %ln to silently ignore unknown items)
2590 # (we use %lr instead of %ln to silently ignore unknown items)
2591 has_node = repo.changelog.index.has_node
2591 has_node = repo.changelog.index.has_node
2592 nodes = sorted(n for n in nodes if has_node(n))
2592 nodes = sorted(n for n in nodes if has_node(n))
2593 roots = [c.node() for c in repo.set(b"roots(%ln)", nodes)]
2593 roots = [c.node() for c in repo.set(b"roots(%ln)", nodes)]
2594 if roots:
2594 if roots:
2595 backup = not nobackup
2595 backup = not nobackup
2596 repair.strip(ui, repo, roots, backup=backup)
2596 repair.strip(ui, repo, roots, backup=backup)
2597
2597
2598
2598
2599 def stripwrapper(orig, ui, repo, nodelist, *args, **kwargs):
2599 def stripwrapper(orig, ui, repo, nodelist, *args, **kwargs):
2600 if isinstance(nodelist, bytes):
2600 if isinstance(nodelist, bytes):
2601 nodelist = [nodelist]
2601 nodelist = [nodelist]
2602 state = histeditstate(repo)
2602 state = histeditstate(repo)
2603 if state.inprogress():
2603 if state.inprogress():
2604 state.read()
2604 state.read()
2605 histedit_nodes = {
2605 histedit_nodes = {
2606 action.node for action in state.actions if action.node
2606 action.node for action in state.actions if action.node
2607 }
2607 }
2608 common_nodes = histedit_nodes & set(nodelist)
2608 common_nodes = histedit_nodes & set(nodelist)
2609 if common_nodes:
2609 if common_nodes:
2610 raise error.Abort(
2610 raise error.Abort(
2611 _(b"histedit in progress, can't strip %s")
2611 _(b"histedit in progress, can't strip %s")
2612 % b', '.join(node.short(x) for x in common_nodes)
2612 % b', '.join(node.short(x) for x in common_nodes)
2613 )
2613 )
2614 return orig(ui, repo, nodelist, *args, **kwargs)
2614 return orig(ui, repo, nodelist, *args, **kwargs)
2615
2615
2616
2616
2617 extensions.wrapfunction(repair, b'strip', stripwrapper)
2617 extensions.wrapfunction(repair, b'strip', stripwrapper)
2618
2618
2619
2619
2620 def summaryhook(ui, repo):
2620 def summaryhook(ui, repo):
2621 state = histeditstate(repo)
2621 state = histeditstate(repo)
2622 if not state.inprogress():
2622 if not state.inprogress():
2623 return
2623 return
2624 state.read()
2624 state.read()
2625 if state.actions:
2625 if state.actions:
2626 # i18n: column positioning for "hg summary"
2626 # i18n: column positioning for "hg summary"
2627 ui.write(
2627 ui.write(
2628 _(b'hist: %s (histedit --continue)\n')
2628 _(b'hist: %s (histedit --continue)\n')
2629 % (
2629 % (
2630 ui.label(_(b'%d remaining'), b'histedit.remaining')
2630 ui.label(_(b'%d remaining'), b'histedit.remaining')
2631 % len(state.actions)
2631 % len(state.actions)
2632 )
2632 )
2633 )
2633 )
2634
2634
2635
2635
2636 def extsetup(ui):
2636 def extsetup(ui):
2637 cmdutil.summaryhooks.add(b'histedit', summaryhook)
2637 cmdutil.summaryhooks.add(b'histedit', summaryhook)
2638 statemod.addunfinished(
2638 statemod.addunfinished(
2639 b'histedit',
2639 b'histedit',
2640 fname=b'histedit-state',
2640 fname=b'histedit-state',
2641 allowcommit=True,
2641 allowcommit=True,
2642 continueflag=True,
2642 continueflag=True,
2643 abortfunc=hgaborthistedit,
2643 abortfunc=hgaborthistedit,
2644 )
2644 )
@@ -1,632 +1,629 b''
1 # changelog.py - changelog class for mercurial
1 # changelog.py - changelog class for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from .i18n import _
10 from .i18n import _
11 from .node import (
11 from .node import (
12 bin,
12 bin,
13 hex,
13 hex,
14 nullid,
14 nullid,
15 )
15 )
16 from .thirdparty import attr
16 from .thirdparty import attr
17
17
18 from . import (
18 from . import (
19 copies,
19 copies,
20 encoding,
20 encoding,
21 error,
21 error,
22 pycompat,
22 pycompat,
23 revlog,
23 revlog,
24 )
24 )
25 from .utils import (
25 from .utils import (
26 dateutil,
26 dateutil,
27 stringutil,
27 stringutil,
28 )
28 )
29
29
30 from .revlogutils import sidedata as sidedatamod
30 from .revlogutils import sidedata as sidedatamod
31
31
32 _defaultextra = {b'branch': b'default'}
32 _defaultextra = {b'branch': b'default'}
33
33
34
34
35 def _string_escape(text):
35 def _string_escape(text):
36 """
36 """
37 >>> from .pycompat import bytechr as chr
37 >>> from .pycompat import bytechr as chr
38 >>> d = {b'nl': chr(10), b'bs': chr(92), b'cr': chr(13), b'nul': chr(0)}
38 >>> d = {b'nl': chr(10), b'bs': chr(92), b'cr': chr(13), b'nul': chr(0)}
39 >>> s = b"ab%(nl)scd%(bs)s%(bs)sn%(nul)s12ab%(cr)scd%(bs)s%(nl)s" % d
39 >>> s = b"ab%(nl)scd%(bs)s%(bs)sn%(nul)s12ab%(cr)scd%(bs)s%(nl)s" % d
40 >>> s
40 >>> s
41 'ab\\ncd\\\\\\\\n\\x0012ab\\rcd\\\\\\n'
41 'ab\\ncd\\\\\\\\n\\x0012ab\\rcd\\\\\\n'
42 >>> res = _string_escape(s)
42 >>> res = _string_escape(s)
43 >>> s == _string_unescape(res)
43 >>> s == _string_unescape(res)
44 True
44 True
45 """
45 """
46 # subset of the string_escape codec
46 # subset of the string_escape codec
47 text = (
47 text = (
48 text.replace(b'\\', b'\\\\')
48 text.replace(b'\\', b'\\\\')
49 .replace(b'\n', b'\\n')
49 .replace(b'\n', b'\\n')
50 .replace(b'\r', b'\\r')
50 .replace(b'\r', b'\\r')
51 )
51 )
52 return text.replace(b'\0', b'\\0')
52 return text.replace(b'\0', b'\\0')
53
53
54
54
55 def _string_unescape(text):
55 def _string_unescape(text):
56 if b'\\0' in text:
56 if b'\\0' in text:
57 # fix up \0 without getting into trouble with \\0
57 # fix up \0 without getting into trouble with \\0
58 text = text.replace(b'\\\\', b'\\\\\n')
58 text = text.replace(b'\\\\', b'\\\\\n')
59 text = text.replace(b'\\0', b'\0')
59 text = text.replace(b'\\0', b'\0')
60 text = text.replace(b'\n', b'')
60 text = text.replace(b'\n', b'')
61 return stringutil.unescapestr(text)
61 return stringutil.unescapestr(text)
62
62
63
63
64 def decodeextra(text):
64 def decodeextra(text):
65 """
65 """
66 >>> from .pycompat import bytechr as chr
66 >>> from .pycompat import bytechr as chr
67 >>> sorted(decodeextra(encodeextra({b'foo': b'bar', b'baz': chr(0) + b'2'})
67 >>> sorted(decodeextra(encodeextra({b'foo': b'bar', b'baz': chr(0) + b'2'})
68 ... ).items())
68 ... ).items())
69 [('baz', '\\x002'), ('branch', 'default'), ('foo', 'bar')]
69 [('baz', '\\x002'), ('branch', 'default'), ('foo', 'bar')]
70 >>> sorted(decodeextra(encodeextra({b'foo': b'bar',
70 >>> sorted(decodeextra(encodeextra({b'foo': b'bar',
71 ... b'baz': chr(92) + chr(0) + b'2'})
71 ... b'baz': chr(92) + chr(0) + b'2'})
72 ... ).items())
72 ... ).items())
73 [('baz', '\\\\\\x002'), ('branch', 'default'), ('foo', 'bar')]
73 [('baz', '\\\\\\x002'), ('branch', 'default'), ('foo', 'bar')]
74 """
74 """
75 extra = _defaultextra.copy()
75 extra = _defaultextra.copy()
76 for l in text.split(b'\0'):
76 for l in text.split(b'\0'):
77 if l:
77 if l:
78 k, v = _string_unescape(l).split(b':', 1)
78 k, v = _string_unescape(l).split(b':', 1)
79 extra[k] = v
79 extra[k] = v
80 return extra
80 return extra
81
81
82
82
83 def encodeextra(d):
83 def encodeextra(d):
84 # keys must be sorted to produce a deterministic changelog entry
84 # keys must be sorted to produce a deterministic changelog entry
85 items = [
85 items = [_string_escape(b'%s:%s' % (k, d[k])) for k in sorted(d)]
86 _string_escape(b'%s:%s' % (k, pycompat.bytestr(d[k])))
87 for k in sorted(d)
88 ]
89 return b"\0".join(items)
86 return b"\0".join(items)
90
87
91
88
92 def stripdesc(desc):
89 def stripdesc(desc):
93 """strip trailing whitespace and leading and trailing empty lines"""
90 """strip trailing whitespace and leading and trailing empty lines"""
94 return b'\n'.join([l.rstrip() for l in desc.splitlines()]).strip(b'\n')
91 return b'\n'.join([l.rstrip() for l in desc.splitlines()]).strip(b'\n')
95
92
96
93
97 class appender(object):
94 class appender(object):
98 '''the changelog index must be updated last on disk, so we use this class
95 '''the changelog index must be updated last on disk, so we use this class
99 to delay writes to it'''
96 to delay writes to it'''
100
97
101 def __init__(self, vfs, name, mode, buf):
98 def __init__(self, vfs, name, mode, buf):
102 self.data = buf
99 self.data = buf
103 fp = vfs(name, mode)
100 fp = vfs(name, mode)
104 self.fp = fp
101 self.fp = fp
105 self.offset = fp.tell()
102 self.offset = fp.tell()
106 self.size = vfs.fstat(fp).st_size
103 self.size = vfs.fstat(fp).st_size
107 self._end = self.size
104 self._end = self.size
108
105
109 def end(self):
106 def end(self):
110 return self._end
107 return self._end
111
108
112 def tell(self):
109 def tell(self):
113 return self.offset
110 return self.offset
114
111
115 def flush(self):
112 def flush(self):
116 pass
113 pass
117
114
118 @property
115 @property
119 def closed(self):
116 def closed(self):
120 return self.fp.closed
117 return self.fp.closed
121
118
122 def close(self):
119 def close(self):
123 self.fp.close()
120 self.fp.close()
124
121
125 def seek(self, offset, whence=0):
122 def seek(self, offset, whence=0):
126 '''virtual file offset spans real file and data'''
123 '''virtual file offset spans real file and data'''
127 if whence == 0:
124 if whence == 0:
128 self.offset = offset
125 self.offset = offset
129 elif whence == 1:
126 elif whence == 1:
130 self.offset += offset
127 self.offset += offset
131 elif whence == 2:
128 elif whence == 2:
132 self.offset = self.end() + offset
129 self.offset = self.end() + offset
133 if self.offset < self.size:
130 if self.offset < self.size:
134 self.fp.seek(self.offset)
131 self.fp.seek(self.offset)
135
132
136 def read(self, count=-1):
133 def read(self, count=-1):
137 '''only trick here is reads that span real file and data'''
134 '''only trick here is reads that span real file and data'''
138 ret = b""
135 ret = b""
139 if self.offset < self.size:
136 if self.offset < self.size:
140 s = self.fp.read(count)
137 s = self.fp.read(count)
141 ret = s
138 ret = s
142 self.offset += len(s)
139 self.offset += len(s)
143 if count > 0:
140 if count > 0:
144 count -= len(s)
141 count -= len(s)
145 if count != 0:
142 if count != 0:
146 doff = self.offset - self.size
143 doff = self.offset - self.size
147 self.data.insert(0, b"".join(self.data))
144 self.data.insert(0, b"".join(self.data))
148 del self.data[1:]
145 del self.data[1:]
149 s = self.data[0][doff : doff + count]
146 s = self.data[0][doff : doff + count]
150 self.offset += len(s)
147 self.offset += len(s)
151 ret += s
148 ret += s
152 return ret
149 return ret
153
150
154 def write(self, s):
151 def write(self, s):
155 self.data.append(bytes(s))
152 self.data.append(bytes(s))
156 self.offset += len(s)
153 self.offset += len(s)
157 self._end += len(s)
154 self._end += len(s)
158
155
159 def __enter__(self):
156 def __enter__(self):
160 self.fp.__enter__()
157 self.fp.__enter__()
161 return self
158 return self
162
159
163 def __exit__(self, *args):
160 def __exit__(self, *args):
164 return self.fp.__exit__(*args)
161 return self.fp.__exit__(*args)
165
162
166
163
167 class _divertopener(object):
164 class _divertopener(object):
168 def __init__(self, opener, target):
165 def __init__(self, opener, target):
169 self._opener = opener
166 self._opener = opener
170 self._target = target
167 self._target = target
171
168
172 def __call__(self, name, mode=b'r', checkambig=False, **kwargs):
169 def __call__(self, name, mode=b'r', checkambig=False, **kwargs):
173 if name != self._target:
170 if name != self._target:
174 return self._opener(name, mode, **kwargs)
171 return self._opener(name, mode, **kwargs)
175 return self._opener(name + b".a", mode, **kwargs)
172 return self._opener(name + b".a", mode, **kwargs)
176
173
177 def __getattr__(self, attr):
174 def __getattr__(self, attr):
178 return getattr(self._opener, attr)
175 return getattr(self._opener, attr)
179
176
180
177
181 def _delayopener(opener, target, buf):
178 def _delayopener(opener, target, buf):
182 """build an opener that stores chunks in 'buf' instead of 'target'"""
179 """build an opener that stores chunks in 'buf' instead of 'target'"""
183
180
184 def _delay(name, mode=b'r', checkambig=False, **kwargs):
181 def _delay(name, mode=b'r', checkambig=False, **kwargs):
185 if name != target:
182 if name != target:
186 return opener(name, mode, **kwargs)
183 return opener(name, mode, **kwargs)
187 assert not kwargs
184 assert not kwargs
188 return appender(opener, name, mode, buf)
185 return appender(opener, name, mode, buf)
189
186
190 return _delay
187 return _delay
191
188
192
189
193 @attr.s
190 @attr.s
194 class _changelogrevision(object):
191 class _changelogrevision(object):
195 # Extensions might modify _defaultextra, so let the constructor below pass
192 # Extensions might modify _defaultextra, so let the constructor below pass
196 # it in
193 # it in
197 extra = attr.ib()
194 extra = attr.ib()
198 manifest = attr.ib(default=nullid)
195 manifest = attr.ib(default=nullid)
199 user = attr.ib(default=b'')
196 user = attr.ib(default=b'')
200 date = attr.ib(default=(0, 0))
197 date = attr.ib(default=(0, 0))
201 files = attr.ib(default=attr.Factory(list))
198 files = attr.ib(default=attr.Factory(list))
202 filesadded = attr.ib(default=None)
199 filesadded = attr.ib(default=None)
203 filesremoved = attr.ib(default=None)
200 filesremoved = attr.ib(default=None)
204 p1copies = attr.ib(default=None)
201 p1copies = attr.ib(default=None)
205 p2copies = attr.ib(default=None)
202 p2copies = attr.ib(default=None)
206 description = attr.ib(default=b'')
203 description = attr.ib(default=b'')
207
204
208
205
209 class changelogrevision(object):
206 class changelogrevision(object):
210 """Holds results of a parsed changelog revision.
207 """Holds results of a parsed changelog revision.
211
208
212 Changelog revisions consist of multiple pieces of data, including
209 Changelog revisions consist of multiple pieces of data, including
213 the manifest node, user, and date. This object exposes a view into
210 the manifest node, user, and date. This object exposes a view into
214 the parsed object.
211 the parsed object.
215 """
212 """
216
213
217 __slots__ = (
214 __slots__ = (
218 '_offsets',
215 '_offsets',
219 '_text',
216 '_text',
220 '_sidedata',
217 '_sidedata',
221 '_cpsd',
218 '_cpsd',
222 )
219 )
223
220
224 def __new__(cls, text, sidedata, cpsd):
221 def __new__(cls, text, sidedata, cpsd):
225 if not text:
222 if not text:
226 return _changelogrevision(extra=_defaultextra)
223 return _changelogrevision(extra=_defaultextra)
227
224
228 self = super(changelogrevision, cls).__new__(cls)
225 self = super(changelogrevision, cls).__new__(cls)
229 # We could return here and implement the following as an __init__.
226 # We could return here and implement the following as an __init__.
230 # But doing it here is equivalent and saves an extra function call.
227 # But doing it here is equivalent and saves an extra function call.
231
228
232 # format used:
229 # format used:
233 # nodeid\n : manifest node in ascii
230 # nodeid\n : manifest node in ascii
234 # user\n : user, no \n or \r allowed
231 # user\n : user, no \n or \r allowed
235 # time tz extra\n : date (time is int or float, timezone is int)
232 # time tz extra\n : date (time is int or float, timezone is int)
236 # : extra is metadata, encoded and separated by '\0'
233 # : extra is metadata, encoded and separated by '\0'
237 # : older versions ignore it
234 # : older versions ignore it
238 # files\n\n : files modified by the cset, no \n or \r allowed
235 # files\n\n : files modified by the cset, no \n or \r allowed
239 # (.*) : comment (free text, ideally utf-8)
236 # (.*) : comment (free text, ideally utf-8)
240 #
237 #
241 # changelog v0 doesn't use extra
238 # changelog v0 doesn't use extra
242
239
243 nl1 = text.index(b'\n')
240 nl1 = text.index(b'\n')
244 nl2 = text.index(b'\n', nl1 + 1)
241 nl2 = text.index(b'\n', nl1 + 1)
245 nl3 = text.index(b'\n', nl2 + 1)
242 nl3 = text.index(b'\n', nl2 + 1)
246
243
247 # The list of files may be empty. Which means nl3 is the first of the
244 # The list of files may be empty. Which means nl3 is the first of the
248 # double newline that precedes the description.
245 # double newline that precedes the description.
249 if text[nl3 + 1 : nl3 + 2] == b'\n':
246 if text[nl3 + 1 : nl3 + 2] == b'\n':
250 doublenl = nl3
247 doublenl = nl3
251 else:
248 else:
252 doublenl = text.index(b'\n\n', nl3 + 1)
249 doublenl = text.index(b'\n\n', nl3 + 1)
253
250
254 self._offsets = (nl1, nl2, nl3, doublenl)
251 self._offsets = (nl1, nl2, nl3, doublenl)
255 self._text = text
252 self._text = text
256 self._sidedata = sidedata
253 self._sidedata = sidedata
257 self._cpsd = cpsd
254 self._cpsd = cpsd
258
255
259 return self
256 return self
260
257
261 @property
258 @property
262 def manifest(self):
259 def manifest(self):
263 return bin(self._text[0 : self._offsets[0]])
260 return bin(self._text[0 : self._offsets[0]])
264
261
265 @property
262 @property
266 def user(self):
263 def user(self):
267 off = self._offsets
264 off = self._offsets
268 return encoding.tolocal(self._text[off[0] + 1 : off[1]])
265 return encoding.tolocal(self._text[off[0] + 1 : off[1]])
269
266
270 @property
267 @property
271 def _rawdate(self):
268 def _rawdate(self):
272 off = self._offsets
269 off = self._offsets
273 dateextra = self._text[off[1] + 1 : off[2]]
270 dateextra = self._text[off[1] + 1 : off[2]]
274 return dateextra.split(b' ', 2)[0:2]
271 return dateextra.split(b' ', 2)[0:2]
275
272
276 @property
273 @property
277 def _rawextra(self):
274 def _rawextra(self):
278 off = self._offsets
275 off = self._offsets
279 dateextra = self._text[off[1] + 1 : off[2]]
276 dateextra = self._text[off[1] + 1 : off[2]]
280 fields = dateextra.split(b' ', 2)
277 fields = dateextra.split(b' ', 2)
281 if len(fields) != 3:
278 if len(fields) != 3:
282 return None
279 return None
283
280
284 return fields[2]
281 return fields[2]
285
282
286 @property
283 @property
287 def date(self):
284 def date(self):
288 raw = self._rawdate
285 raw = self._rawdate
289 time = float(raw[0])
286 time = float(raw[0])
290 # Various tools did silly things with the timezone.
287 # Various tools did silly things with the timezone.
291 try:
288 try:
292 timezone = int(raw[1])
289 timezone = int(raw[1])
293 except ValueError:
290 except ValueError:
294 timezone = 0
291 timezone = 0
295
292
296 return time, timezone
293 return time, timezone
297
294
298 @property
295 @property
299 def extra(self):
296 def extra(self):
300 raw = self._rawextra
297 raw = self._rawextra
301 if raw is None:
298 if raw is None:
302 return _defaultextra
299 return _defaultextra
303
300
304 return decodeextra(raw)
301 return decodeextra(raw)
305
302
306 @property
303 @property
307 def files(self):
304 def files(self):
308 off = self._offsets
305 off = self._offsets
309 if off[2] == off[3]:
306 if off[2] == off[3]:
310 return []
307 return []
311
308
312 return self._text[off[2] + 1 : off[3]].split(b'\n')
309 return self._text[off[2] + 1 : off[3]].split(b'\n')
313
310
314 @property
311 @property
315 def filesadded(self):
312 def filesadded(self):
316 if self._cpsd:
313 if self._cpsd:
317 rawindices = self._sidedata.get(sidedatamod.SD_FILESADDED)
314 rawindices = self._sidedata.get(sidedatamod.SD_FILESADDED)
318 if not rawindices:
315 if not rawindices:
319 return []
316 return []
320 else:
317 else:
321 rawindices = self.extra.get(b'filesadded')
318 rawindices = self.extra.get(b'filesadded')
322 if rawindices is None:
319 if rawindices is None:
323 return None
320 return None
324 return copies.decodefileindices(self.files, rawindices)
321 return copies.decodefileindices(self.files, rawindices)
325
322
326 @property
323 @property
327 def filesremoved(self):
324 def filesremoved(self):
328 if self._cpsd:
325 if self._cpsd:
329 rawindices = self._sidedata.get(sidedatamod.SD_FILESREMOVED)
326 rawindices = self._sidedata.get(sidedatamod.SD_FILESREMOVED)
330 if not rawindices:
327 if not rawindices:
331 return []
328 return []
332 else:
329 else:
333 rawindices = self.extra.get(b'filesremoved')
330 rawindices = self.extra.get(b'filesremoved')
334 if rawindices is None:
331 if rawindices is None:
335 return None
332 return None
336 return copies.decodefileindices(self.files, rawindices)
333 return copies.decodefileindices(self.files, rawindices)
337
334
338 @property
335 @property
339 def p1copies(self):
336 def p1copies(self):
340 if self._cpsd:
337 if self._cpsd:
341 rawcopies = self._sidedata.get(sidedatamod.SD_P1COPIES)
338 rawcopies = self._sidedata.get(sidedatamod.SD_P1COPIES)
342 if not rawcopies:
339 if not rawcopies:
343 return {}
340 return {}
344 else:
341 else:
345 rawcopies = self.extra.get(b'p1copies')
342 rawcopies = self.extra.get(b'p1copies')
346 if rawcopies is None:
343 if rawcopies is None:
347 return None
344 return None
348 return copies.decodecopies(self.files, rawcopies)
345 return copies.decodecopies(self.files, rawcopies)
349
346
350 @property
347 @property
351 def p2copies(self):
348 def p2copies(self):
352 if self._cpsd:
349 if self._cpsd:
353 rawcopies = self._sidedata.get(sidedatamod.SD_P2COPIES)
350 rawcopies = self._sidedata.get(sidedatamod.SD_P2COPIES)
354 if not rawcopies:
351 if not rawcopies:
355 return {}
352 return {}
356 else:
353 else:
357 rawcopies = self.extra.get(b'p2copies')
354 rawcopies = self.extra.get(b'p2copies')
358 if rawcopies is None:
355 if rawcopies is None:
359 return None
356 return None
360 return copies.decodecopies(self.files, rawcopies)
357 return copies.decodecopies(self.files, rawcopies)
361
358
362 @property
359 @property
363 def description(self):
360 def description(self):
364 return encoding.tolocal(self._text[self._offsets[3] + 2 :])
361 return encoding.tolocal(self._text[self._offsets[3] + 2 :])
365
362
366
363
367 class changelog(revlog.revlog):
364 class changelog(revlog.revlog):
368 def __init__(self, opener, trypending=False):
365 def __init__(self, opener, trypending=False):
369 """Load a changelog revlog using an opener.
366 """Load a changelog revlog using an opener.
370
367
371 If ``trypending`` is true, we attempt to load the index from a
368 If ``trypending`` is true, we attempt to load the index from a
372 ``00changelog.i.a`` file instead of the default ``00changelog.i``.
369 ``00changelog.i.a`` file instead of the default ``00changelog.i``.
373 The ``00changelog.i.a`` file contains index (and possibly inline
370 The ``00changelog.i.a`` file contains index (and possibly inline
374 revision) data for a transaction that hasn't been finalized yet.
371 revision) data for a transaction that hasn't been finalized yet.
375 It exists in a separate file to facilitate readers (such as
372 It exists in a separate file to facilitate readers (such as
376 hooks processes) accessing data before a transaction is finalized.
373 hooks processes) accessing data before a transaction is finalized.
377 """
374 """
378 if trypending and opener.exists(b'00changelog.i.a'):
375 if trypending and opener.exists(b'00changelog.i.a'):
379 indexfile = b'00changelog.i.a'
376 indexfile = b'00changelog.i.a'
380 else:
377 else:
381 indexfile = b'00changelog.i'
378 indexfile = b'00changelog.i'
382
379
383 datafile = b'00changelog.d'
380 datafile = b'00changelog.d'
384 revlog.revlog.__init__(
381 revlog.revlog.__init__(
385 self,
382 self,
386 opener,
383 opener,
387 indexfile,
384 indexfile,
388 datafile=datafile,
385 datafile=datafile,
389 checkambig=True,
386 checkambig=True,
390 mmaplargeindex=True,
387 mmaplargeindex=True,
391 persistentnodemap=opener.options.get(
388 persistentnodemap=opener.options.get(
392 b'exp-persistent-nodemap', False
389 b'exp-persistent-nodemap', False
393 ),
390 ),
394 )
391 )
395
392
396 if self._initempty and (self.version & 0xFFFF == revlog.REVLOGV1):
393 if self._initempty and (self.version & 0xFFFF == revlog.REVLOGV1):
397 # changelogs don't benefit from generaldelta.
394 # changelogs don't benefit from generaldelta.
398
395
399 self.version &= ~revlog.FLAG_GENERALDELTA
396 self.version &= ~revlog.FLAG_GENERALDELTA
400 self._generaldelta = False
397 self._generaldelta = False
401
398
402 # Delta chains for changelogs tend to be very small because entries
399 # Delta chains for changelogs tend to be very small because entries
403 # tend to be small and don't delta well with each. So disable delta
400 # tend to be small and don't delta well with each. So disable delta
404 # chains.
401 # chains.
405 self._storedeltachains = False
402 self._storedeltachains = False
406
403
407 self._realopener = opener
404 self._realopener = opener
408 self._delayed = False
405 self._delayed = False
409 self._delaybuf = None
406 self._delaybuf = None
410 self._divert = False
407 self._divert = False
411 self.filteredrevs = frozenset()
408 self.filteredrevs = frozenset()
412 self._copiesstorage = opener.options.get(b'copies-storage')
409 self._copiesstorage = opener.options.get(b'copies-storage')
413
410
414 def delayupdate(self, tr):
411 def delayupdate(self, tr):
415 """delay visibility of index updates to other readers"""
412 """delay visibility of index updates to other readers"""
416
413
417 if not self._delayed:
414 if not self._delayed:
418 if len(self) == 0:
415 if len(self) == 0:
419 self._divert = True
416 self._divert = True
420 if self._realopener.exists(self.indexfile + b'.a'):
417 if self._realopener.exists(self.indexfile + b'.a'):
421 self._realopener.unlink(self.indexfile + b'.a')
418 self._realopener.unlink(self.indexfile + b'.a')
422 self.opener = _divertopener(self._realopener, self.indexfile)
419 self.opener = _divertopener(self._realopener, self.indexfile)
423 else:
420 else:
424 self._delaybuf = []
421 self._delaybuf = []
425 self.opener = _delayopener(
422 self.opener = _delayopener(
426 self._realopener, self.indexfile, self._delaybuf
423 self._realopener, self.indexfile, self._delaybuf
427 )
424 )
428 self._delayed = True
425 self._delayed = True
429 tr.addpending(b'cl-%i' % id(self), self._writepending)
426 tr.addpending(b'cl-%i' % id(self), self._writepending)
430 tr.addfinalize(b'cl-%i' % id(self), self._finalize)
427 tr.addfinalize(b'cl-%i' % id(self), self._finalize)
431
428
432 def _finalize(self, tr):
429 def _finalize(self, tr):
433 """finalize index updates"""
430 """finalize index updates"""
434 self._delayed = False
431 self._delayed = False
435 self.opener = self._realopener
432 self.opener = self._realopener
436 # move redirected index data back into place
433 # move redirected index data back into place
437 if self._divert:
434 if self._divert:
438 assert not self._delaybuf
435 assert not self._delaybuf
439 tmpname = self.indexfile + b".a"
436 tmpname = self.indexfile + b".a"
440 nfile = self.opener.open(tmpname)
437 nfile = self.opener.open(tmpname)
441 nfile.close()
438 nfile.close()
442 self.opener.rename(tmpname, self.indexfile, checkambig=True)
439 self.opener.rename(tmpname, self.indexfile, checkambig=True)
443 elif self._delaybuf:
440 elif self._delaybuf:
444 fp = self.opener(self.indexfile, b'a', checkambig=True)
441 fp = self.opener(self.indexfile, b'a', checkambig=True)
445 fp.write(b"".join(self._delaybuf))
442 fp.write(b"".join(self._delaybuf))
446 fp.close()
443 fp.close()
447 self._delaybuf = None
444 self._delaybuf = None
448 self._divert = False
445 self._divert = False
449 # split when we're done
446 # split when we're done
450 self._enforceinlinesize(tr)
447 self._enforceinlinesize(tr)
451
448
452 def _writepending(self, tr):
449 def _writepending(self, tr):
453 """create a file containing the unfinalized state for
450 """create a file containing the unfinalized state for
454 pretxnchangegroup"""
451 pretxnchangegroup"""
455 if self._delaybuf:
452 if self._delaybuf:
456 # make a temporary copy of the index
453 # make a temporary copy of the index
457 fp1 = self._realopener(self.indexfile)
454 fp1 = self._realopener(self.indexfile)
458 pendingfilename = self.indexfile + b".a"
455 pendingfilename = self.indexfile + b".a"
459 # register as a temp file to ensure cleanup on failure
456 # register as a temp file to ensure cleanup on failure
460 tr.registertmp(pendingfilename)
457 tr.registertmp(pendingfilename)
461 # write existing data
458 # write existing data
462 fp2 = self._realopener(pendingfilename, b"w")
459 fp2 = self._realopener(pendingfilename, b"w")
463 fp2.write(fp1.read())
460 fp2.write(fp1.read())
464 # add pending data
461 # add pending data
465 fp2.write(b"".join(self._delaybuf))
462 fp2.write(b"".join(self._delaybuf))
466 fp2.close()
463 fp2.close()
467 # switch modes so finalize can simply rename
464 # switch modes so finalize can simply rename
468 self._delaybuf = None
465 self._delaybuf = None
469 self._divert = True
466 self._divert = True
470 self.opener = _divertopener(self._realopener, self.indexfile)
467 self.opener = _divertopener(self._realopener, self.indexfile)
471
468
472 if self._divert:
469 if self._divert:
473 return True
470 return True
474
471
475 return False
472 return False
476
473
477 def _enforceinlinesize(self, tr, fp=None):
474 def _enforceinlinesize(self, tr, fp=None):
478 if not self._delayed:
475 if not self._delayed:
479 revlog.revlog._enforceinlinesize(self, tr, fp)
476 revlog.revlog._enforceinlinesize(self, tr, fp)
480
477
481 def read(self, node):
478 def read(self, node):
482 """Obtain data from a parsed changelog revision.
479 """Obtain data from a parsed changelog revision.
483
480
484 Returns a 6-tuple of:
481 Returns a 6-tuple of:
485
482
486 - manifest node in binary
483 - manifest node in binary
487 - author/user as a localstr
484 - author/user as a localstr
488 - date as a 2-tuple of (time, timezone)
485 - date as a 2-tuple of (time, timezone)
489 - list of files
486 - list of files
490 - commit message as a localstr
487 - commit message as a localstr
491 - dict of extra metadata
488 - dict of extra metadata
492
489
493 Unless you need to access all fields, consider calling
490 Unless you need to access all fields, consider calling
494 ``changelogrevision`` instead, as it is faster for partial object
491 ``changelogrevision`` instead, as it is faster for partial object
495 access.
492 access.
496 """
493 """
497 d, s = self._revisiondata(node)
494 d, s = self._revisiondata(node)
498 c = changelogrevision(
495 c = changelogrevision(
499 d, s, self._copiesstorage == b'changeset-sidedata'
496 d, s, self._copiesstorage == b'changeset-sidedata'
500 )
497 )
501 return (c.manifest, c.user, c.date, c.files, c.description, c.extra)
498 return (c.manifest, c.user, c.date, c.files, c.description, c.extra)
502
499
503 def changelogrevision(self, nodeorrev):
500 def changelogrevision(self, nodeorrev):
504 """Obtain a ``changelogrevision`` for a node or revision."""
501 """Obtain a ``changelogrevision`` for a node or revision."""
505 text, sidedata = self._revisiondata(nodeorrev)
502 text, sidedata = self._revisiondata(nodeorrev)
506 return changelogrevision(
503 return changelogrevision(
507 text, sidedata, self._copiesstorage == b'changeset-sidedata'
504 text, sidedata, self._copiesstorage == b'changeset-sidedata'
508 )
505 )
509
506
510 def readfiles(self, node):
507 def readfiles(self, node):
511 """
508 """
512 short version of read that only returns the files modified by the cset
509 short version of read that only returns the files modified by the cset
513 """
510 """
514 text = self.revision(node)
511 text = self.revision(node)
515 if not text:
512 if not text:
516 return []
513 return []
517 last = text.index(b"\n\n")
514 last = text.index(b"\n\n")
518 l = text[:last].split(b'\n')
515 l = text[:last].split(b'\n')
519 return l[3:]
516 return l[3:]
520
517
521 def add(
518 def add(
522 self,
519 self,
523 manifest,
520 manifest,
524 files,
521 files,
525 desc,
522 desc,
526 transaction,
523 transaction,
527 p1,
524 p1,
528 p2,
525 p2,
529 user,
526 user,
530 date=None,
527 date=None,
531 extra=None,
528 extra=None,
532 p1copies=None,
529 p1copies=None,
533 p2copies=None,
530 p2copies=None,
534 filesadded=None,
531 filesadded=None,
535 filesremoved=None,
532 filesremoved=None,
536 ):
533 ):
537 # Convert to UTF-8 encoded bytestrings as the very first
534 # Convert to UTF-8 encoded bytestrings as the very first
538 # thing: calling any method on a localstr object will turn it
535 # thing: calling any method on a localstr object will turn it
539 # into a str object and the cached UTF-8 string is thus lost.
536 # into a str object and the cached UTF-8 string is thus lost.
540 user, desc = encoding.fromlocal(user), encoding.fromlocal(desc)
537 user, desc = encoding.fromlocal(user), encoding.fromlocal(desc)
541
538
542 user = user.strip()
539 user = user.strip()
543 # An empty username or a username with a "\n" will make the
540 # An empty username or a username with a "\n" will make the
544 # revision text contain two "\n\n" sequences -> corrupt
541 # revision text contain two "\n\n" sequences -> corrupt
545 # repository since read cannot unpack the revision.
542 # repository since read cannot unpack the revision.
546 if not user:
543 if not user:
547 raise error.StorageError(_(b"empty username"))
544 raise error.StorageError(_(b"empty username"))
548 if b"\n" in user:
545 if b"\n" in user:
549 raise error.StorageError(
546 raise error.StorageError(
550 _(b"username %r contains a newline") % pycompat.bytestr(user)
547 _(b"username %r contains a newline") % pycompat.bytestr(user)
551 )
548 )
552
549
553 desc = stripdesc(desc)
550 desc = stripdesc(desc)
554
551
555 if date:
552 if date:
556 parseddate = b"%d %d" % dateutil.parsedate(date)
553 parseddate = b"%d %d" % dateutil.parsedate(date)
557 else:
554 else:
558 parseddate = b"%d %d" % dateutil.makedate()
555 parseddate = b"%d %d" % dateutil.makedate()
559 if extra:
556 if extra:
560 branch = extra.get(b"branch")
557 branch = extra.get(b"branch")
561 if branch in (b"default", b""):
558 if branch in (b"default", b""):
562 del extra[b"branch"]
559 del extra[b"branch"]
563 elif branch in (b".", b"null", b"tip"):
560 elif branch in (b".", b"null", b"tip"):
564 raise error.StorageError(
561 raise error.StorageError(
565 _(b'the name \'%s\' is reserved') % branch
562 _(b'the name \'%s\' is reserved') % branch
566 )
563 )
567 sortedfiles = sorted(files)
564 sortedfiles = sorted(files)
568 sidedata = None
565 sidedata = None
569 if extra is not None:
566 if extra is not None:
570 for name in (
567 for name in (
571 b'p1copies',
568 b'p1copies',
572 b'p2copies',
569 b'p2copies',
573 b'filesadded',
570 b'filesadded',
574 b'filesremoved',
571 b'filesremoved',
575 ):
572 ):
576 extra.pop(name, None)
573 extra.pop(name, None)
577 if p1copies is not None:
574 if p1copies is not None:
578 p1copies = copies.encodecopies(sortedfiles, p1copies)
575 p1copies = copies.encodecopies(sortedfiles, p1copies)
579 if p2copies is not None:
576 if p2copies is not None:
580 p2copies = copies.encodecopies(sortedfiles, p2copies)
577 p2copies = copies.encodecopies(sortedfiles, p2copies)
581 if filesadded is not None:
578 if filesadded is not None:
582 filesadded = copies.encodefileindices(sortedfiles, filesadded)
579 filesadded = copies.encodefileindices(sortedfiles, filesadded)
583 if filesremoved is not None:
580 if filesremoved is not None:
584 filesremoved = copies.encodefileindices(sortedfiles, filesremoved)
581 filesremoved = copies.encodefileindices(sortedfiles, filesremoved)
585 if self._copiesstorage == b'extra':
582 if self._copiesstorage == b'extra':
586 extrasentries = p1copies, p2copies, filesadded, filesremoved
583 extrasentries = p1copies, p2copies, filesadded, filesremoved
587 if extra is None and any(x is not None for x in extrasentries):
584 if extra is None and any(x is not None for x in extrasentries):
588 extra = {}
585 extra = {}
589 if p1copies is not None:
586 if p1copies is not None:
590 extra[b'p1copies'] = p1copies
587 extra[b'p1copies'] = p1copies
591 if p2copies is not None:
588 if p2copies is not None:
592 extra[b'p2copies'] = p2copies
589 extra[b'p2copies'] = p2copies
593 if filesadded is not None:
590 if filesadded is not None:
594 extra[b'filesadded'] = filesadded
591 extra[b'filesadded'] = filesadded
595 if filesremoved is not None:
592 if filesremoved is not None:
596 extra[b'filesremoved'] = filesremoved
593 extra[b'filesremoved'] = filesremoved
597 elif self._copiesstorage == b'changeset-sidedata':
594 elif self._copiesstorage == b'changeset-sidedata':
598 sidedata = {}
595 sidedata = {}
599 if p1copies:
596 if p1copies:
600 sidedata[sidedatamod.SD_P1COPIES] = p1copies
597 sidedata[sidedatamod.SD_P1COPIES] = p1copies
601 if p2copies:
598 if p2copies:
602 sidedata[sidedatamod.SD_P2COPIES] = p2copies
599 sidedata[sidedatamod.SD_P2COPIES] = p2copies
603 if filesadded:
600 if filesadded:
604 sidedata[sidedatamod.SD_FILESADDED] = filesadded
601 sidedata[sidedatamod.SD_FILESADDED] = filesadded
605 if filesremoved:
602 if filesremoved:
606 sidedata[sidedatamod.SD_FILESREMOVED] = filesremoved
603 sidedata[sidedatamod.SD_FILESREMOVED] = filesremoved
607 if not sidedata:
604 if not sidedata:
608 sidedata = None
605 sidedata = None
609
606
610 if extra:
607 if extra:
611 extra = encodeextra(extra)
608 extra = encodeextra(extra)
612 parseddate = b"%s %s" % (parseddate, extra)
609 parseddate = b"%s %s" % (parseddate, extra)
613 l = [hex(manifest), user, parseddate] + sortedfiles + [b"", desc]
610 l = [hex(manifest), user, parseddate] + sortedfiles + [b"", desc]
614 text = b"\n".join(l)
611 text = b"\n".join(l)
615 return self.addrevision(
612 return self.addrevision(
616 text, transaction, len(self), p1, p2, sidedata=sidedata
613 text, transaction, len(self), p1, p2, sidedata=sidedata
617 )
614 )
618
615
619 def branchinfo(self, rev):
616 def branchinfo(self, rev):
620 """return the branch name and open/close state of a revision
617 """return the branch name and open/close state of a revision
621
618
622 This function exists because creating a changectx object
619 This function exists because creating a changectx object
623 just to access this is costly."""
620 just to access this is costly."""
624 extra = self.read(rev)[5]
621 extra = self.read(rev)[5]
625 return encoding.tolocal(extra.get(b"branch")), b'close' in extra
622 return encoding.tolocal(extra.get(b"branch")), b'close' in extra
626
623
627 def _nodeduplicatecallback(self, transaction, node):
624 def _nodeduplicatecallback(self, transaction, node):
628 # keep track of revisions that got "re-added", eg: unbunde of know rev.
625 # keep track of revisions that got "re-added", eg: unbunde of know rev.
629 #
626 #
630 # We track them in a list to preserve their order from the source bundle
627 # We track them in a list to preserve their order from the source bundle
631 duplicates = transaction.changes.setdefault(b'revduplicates', [])
628 duplicates = transaction.changes.setdefault(b'revduplicates', [])
632 duplicates.append(self.rev(node))
629 duplicates.append(self.rev(node))
@@ -1,2329 +1,2335 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import collections
10 import collections
11 import contextlib
11 import contextlib
12 import errno
12 import errno
13 import getpass
13 import getpass
14 import inspect
14 import inspect
15 import os
15 import os
16 import re
16 import re
17 import signal
17 import signal
18 import socket
18 import socket
19 import subprocess
19 import subprocess
20 import sys
20 import sys
21 import traceback
21 import traceback
22
22
23 from .i18n import _
23 from .i18n import _
24 from .node import hex
24 from .node import hex
25 from .pycompat import (
25 from .pycompat import (
26 getattr,
26 getattr,
27 open,
27 open,
28 setattr,
28 setattr,
29 )
29 )
30
30
31 from . import (
31 from . import (
32 color,
32 color,
33 config,
33 config,
34 configitems,
34 configitems,
35 encoding,
35 encoding,
36 error,
36 error,
37 formatter,
37 formatter,
38 loggingutil,
38 loggingutil,
39 progress,
39 progress,
40 pycompat,
40 pycompat,
41 rcutil,
41 rcutil,
42 scmutil,
42 scmutil,
43 util,
43 util,
44 )
44 )
45 from .utils import (
45 from .utils import (
46 dateutil,
46 dateutil,
47 procutil,
47 procutil,
48 resourceutil,
48 resourceutil,
49 stringutil,
49 stringutil,
50 )
50 )
51
51
52 urlreq = util.urlreq
52 urlreq = util.urlreq
53
53
54 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
54 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
55 _keepalnum = b''.join(
55 _keepalnum = b''.join(
56 c for c in map(pycompat.bytechr, range(256)) if not c.isalnum()
56 c for c in map(pycompat.bytechr, range(256)) if not c.isalnum()
57 )
57 )
58
58
59 # The config knobs that will be altered (if unset) by ui.tweakdefaults.
59 # The config knobs that will be altered (if unset) by ui.tweakdefaults.
60 tweakrc = b"""
60 tweakrc = b"""
61 [ui]
61 [ui]
62 # The rollback command is dangerous. As a rule, don't use it.
62 # The rollback command is dangerous. As a rule, don't use it.
63 rollback = False
63 rollback = False
64 # Make `hg status` report copy information
64 # Make `hg status` report copy information
65 statuscopies = yes
65 statuscopies = yes
66 # Prefer curses UIs when available. Revert to plain-text with `text`.
66 # Prefer curses UIs when available. Revert to plain-text with `text`.
67 interface = curses
67 interface = curses
68 # Make compatible commands emit cwd-relative paths by default.
68 # Make compatible commands emit cwd-relative paths by default.
69 relative-paths = yes
69 relative-paths = yes
70
70
71 [commands]
71 [commands]
72 # Grep working directory by default.
72 # Grep working directory by default.
73 grep.all-files = True
73 grep.all-files = True
74 # Refuse to perform an `hg update` that would cause a file content merge
74 # Refuse to perform an `hg update` that would cause a file content merge
75 update.check = noconflict
75 update.check = noconflict
76 # Show conflicts information in `hg status`
76 # Show conflicts information in `hg status`
77 status.verbose = True
77 status.verbose = True
78 # Make `hg resolve` with no action (like `-m`) fail instead of re-merging.
78 # Make `hg resolve` with no action (like `-m`) fail instead of re-merging.
79 resolve.explicit-re-merge = True
79 resolve.explicit-re-merge = True
80
80
81 [diff]
81 [diff]
82 git = 1
82 git = 1
83 showfunc = 1
83 showfunc = 1
84 word-diff = 1
84 word-diff = 1
85 """
85 """
86
86
87 samplehgrcs = {
87 samplehgrcs = {
88 b'user': b"""# example user config (see 'hg help config' for more info)
88 b'user': b"""# example user config (see 'hg help config' for more info)
89 [ui]
89 [ui]
90 # name and email, e.g.
90 # name and email, e.g.
91 # username = Jane Doe <jdoe@example.com>
91 # username = Jane Doe <jdoe@example.com>
92 username =
92 username =
93
93
94 # We recommend enabling tweakdefaults to get slight improvements to
94 # We recommend enabling tweakdefaults to get slight improvements to
95 # the UI over time. Make sure to set HGPLAIN in the environment when
95 # the UI over time. Make sure to set HGPLAIN in the environment when
96 # writing scripts!
96 # writing scripts!
97 # tweakdefaults = True
97 # tweakdefaults = True
98
98
99 # uncomment to disable color in command output
99 # uncomment to disable color in command output
100 # (see 'hg help color' for details)
100 # (see 'hg help color' for details)
101 # color = never
101 # color = never
102
102
103 # uncomment to disable command output pagination
103 # uncomment to disable command output pagination
104 # (see 'hg help pager' for details)
104 # (see 'hg help pager' for details)
105 # paginate = never
105 # paginate = never
106
106
107 [extensions]
107 [extensions]
108 # uncomment the lines below to enable some popular extensions
108 # uncomment the lines below to enable some popular extensions
109 # (see 'hg help extensions' for more info)
109 # (see 'hg help extensions' for more info)
110 #
110 #
111 # histedit =
111 # histedit =
112 # rebase =
112 # rebase =
113 # uncommit =
113 # uncommit =
114 """,
114 """,
115 b'cloned': b"""# example repository config (see 'hg help config' for more info)
115 b'cloned': b"""# example repository config (see 'hg help config' for more info)
116 [paths]
116 [paths]
117 default = %s
117 default = %s
118
118
119 # path aliases to other clones of this repo in URLs or filesystem paths
119 # path aliases to other clones of this repo in URLs or filesystem paths
120 # (see 'hg help config.paths' for more info)
120 # (see 'hg help config.paths' for more info)
121 #
121 #
122 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
122 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
123 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
123 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
124 # my-clone = /home/jdoe/jdoes-clone
124 # my-clone = /home/jdoe/jdoes-clone
125
125
126 [ui]
126 [ui]
127 # name and email (local to this repository, optional), e.g.
127 # name and email (local to this repository, optional), e.g.
128 # username = Jane Doe <jdoe@example.com>
128 # username = Jane Doe <jdoe@example.com>
129 """,
129 """,
130 b'local': b"""# example repository config (see 'hg help config' for more info)
130 b'local': b"""# example repository config (see 'hg help config' for more info)
131 [paths]
131 [paths]
132 # path aliases to other clones of this repo in URLs or filesystem paths
132 # path aliases to other clones of this repo in URLs or filesystem paths
133 # (see 'hg help config.paths' for more info)
133 # (see 'hg help config.paths' for more info)
134 #
134 #
135 # default = http://example.com/hg/example-repo
135 # default = http://example.com/hg/example-repo
136 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
136 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
137 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
137 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
138 # my-clone = /home/jdoe/jdoes-clone
138 # my-clone = /home/jdoe/jdoes-clone
139
139
140 [ui]
140 [ui]
141 # name and email (local to this repository, optional), e.g.
141 # name and email (local to this repository, optional), e.g.
142 # username = Jane Doe <jdoe@example.com>
142 # username = Jane Doe <jdoe@example.com>
143 """,
143 """,
144 b'global': b"""# example system-wide hg config (see 'hg help config' for more info)
144 b'global': b"""# example system-wide hg config (see 'hg help config' for more info)
145
145
146 [ui]
146 [ui]
147 # uncomment to disable color in command output
147 # uncomment to disable color in command output
148 # (see 'hg help color' for details)
148 # (see 'hg help color' for details)
149 # color = never
149 # color = never
150
150
151 # uncomment to disable command output pagination
151 # uncomment to disable command output pagination
152 # (see 'hg help pager' for details)
152 # (see 'hg help pager' for details)
153 # paginate = never
153 # paginate = never
154
154
155 [extensions]
155 [extensions]
156 # uncomment the lines below to enable some popular extensions
156 # uncomment the lines below to enable some popular extensions
157 # (see 'hg help extensions' for more info)
157 # (see 'hg help extensions' for more info)
158 #
158 #
159 # blackbox =
159 # blackbox =
160 # churn =
160 # churn =
161 """,
161 """,
162 }
162 }
163
163
164
164
165 def _maybestrurl(maybebytes):
165 def _maybestrurl(maybebytes):
166 return pycompat.rapply(pycompat.strurl, maybebytes)
166 return pycompat.rapply(pycompat.strurl, maybebytes)
167
167
168
168
169 def _maybebytesurl(maybestr):
169 def _maybebytesurl(maybestr):
170 return pycompat.rapply(pycompat.bytesurl, maybestr)
170 return pycompat.rapply(pycompat.bytesurl, maybestr)
171
171
172
172
173 class httppasswordmgrdbproxy(object):
173 class httppasswordmgrdbproxy(object):
174 """Delays loading urllib2 until it's needed."""
174 """Delays loading urllib2 until it's needed."""
175
175
176 def __init__(self):
176 def __init__(self):
177 self._mgr = None
177 self._mgr = None
178
178
179 def _get_mgr(self):
179 def _get_mgr(self):
180 if self._mgr is None:
180 if self._mgr is None:
181 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
181 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
182 return self._mgr
182 return self._mgr
183
183
184 def add_password(self, realm, uris, user, passwd):
184 def add_password(self, realm, uris, user, passwd):
185 return self._get_mgr().add_password(
185 return self._get_mgr().add_password(
186 _maybestrurl(realm),
186 _maybestrurl(realm),
187 _maybestrurl(uris),
187 _maybestrurl(uris),
188 _maybestrurl(user),
188 _maybestrurl(user),
189 _maybestrurl(passwd),
189 _maybestrurl(passwd),
190 )
190 )
191
191
192 def find_user_password(self, realm, uri):
192 def find_user_password(self, realm, uri):
193 mgr = self._get_mgr()
193 mgr = self._get_mgr()
194 return _maybebytesurl(
194 return _maybebytesurl(
195 mgr.find_user_password(_maybestrurl(realm), _maybestrurl(uri))
195 mgr.find_user_password(_maybestrurl(realm), _maybestrurl(uri))
196 )
196 )
197
197
198
198
199 def _catchterm(*args):
199 def _catchterm(*args):
200 raise error.SignalInterrupt
200 raise error.SignalInterrupt
201
201
202
202
203 # unique object used to detect no default value has been provided when
203 # unique object used to detect no default value has been provided when
204 # retrieving configuration value.
204 # retrieving configuration value.
205 _unset = object()
205 _unset = object()
206
206
207 # _reqexithandlers: callbacks run at the end of a request
207 # _reqexithandlers: callbacks run at the end of a request
208 _reqexithandlers = []
208 _reqexithandlers = []
209
209
210
210
211 class ui(object):
211 class ui(object):
212 def __init__(self, src=None):
212 def __init__(self, src=None):
213 """Create a fresh new ui object if no src given
213 """Create a fresh new ui object if no src given
214
214
215 Use uimod.ui.load() to create a ui which knows global and user configs.
215 Use uimod.ui.load() to create a ui which knows global and user configs.
216 In most cases, you should use ui.copy() to create a copy of an existing
216 In most cases, you should use ui.copy() to create a copy of an existing
217 ui object.
217 ui object.
218 """
218 """
219 # _buffers: used for temporary capture of output
219 # _buffers: used for temporary capture of output
220 self._buffers = []
220 self._buffers = []
221 # 3-tuple describing how each buffer in the stack behaves.
221 # 3-tuple describing how each buffer in the stack behaves.
222 # Values are (capture stderr, capture subprocesses, apply labels).
222 # Values are (capture stderr, capture subprocesses, apply labels).
223 self._bufferstates = []
223 self._bufferstates = []
224 # When a buffer is active, defines whether we are expanding labels.
224 # When a buffer is active, defines whether we are expanding labels.
225 # This exists to prevent an extra list lookup.
225 # This exists to prevent an extra list lookup.
226 self._bufferapplylabels = None
226 self._bufferapplylabels = None
227 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
227 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
228 self._reportuntrusted = True
228 self._reportuntrusted = True
229 self._knownconfig = configitems.coreitems
229 self._knownconfig = configitems.coreitems
230 self._ocfg = config.config() # overlay
230 self._ocfg = config.config() # overlay
231 self._tcfg = config.config() # trusted
231 self._tcfg = config.config() # trusted
232 self._ucfg = config.config() # untrusted
232 self._ucfg = config.config() # untrusted
233 self._trustusers = set()
233 self._trustusers = set()
234 self._trustgroups = set()
234 self._trustgroups = set()
235 self.callhooks = True
235 self.callhooks = True
236 # Insecure server connections requested.
236 # Insecure server connections requested.
237 self.insecureconnections = False
237 self.insecureconnections = False
238 # Blocked time
238 # Blocked time
239 self.logblockedtimes = False
239 self.logblockedtimes = False
240 # color mode: see mercurial/color.py for possible value
240 # color mode: see mercurial/color.py for possible value
241 self._colormode = None
241 self._colormode = None
242 self._terminfoparams = {}
242 self._terminfoparams = {}
243 self._styles = {}
243 self._styles = {}
244 self._uninterruptible = False
244 self._uninterruptible = False
245
245
246 if src:
246 if src:
247 self._fout = src._fout
247 self._fout = src._fout
248 self._ferr = src._ferr
248 self._ferr = src._ferr
249 self._fin = src._fin
249 self._fin = src._fin
250 self._fmsg = src._fmsg
250 self._fmsg = src._fmsg
251 self._fmsgout = src._fmsgout
251 self._fmsgout = src._fmsgout
252 self._fmsgerr = src._fmsgerr
252 self._fmsgerr = src._fmsgerr
253 self._finoutredirected = src._finoutredirected
253 self._finoutredirected = src._finoutredirected
254 self._loggers = src._loggers.copy()
254 self._loggers = src._loggers.copy()
255 self.pageractive = src.pageractive
255 self.pageractive = src.pageractive
256 self._disablepager = src._disablepager
256 self._disablepager = src._disablepager
257 self._tweaked = src._tweaked
257 self._tweaked = src._tweaked
258
258
259 self._tcfg = src._tcfg.copy()
259 self._tcfg = src._tcfg.copy()
260 self._ucfg = src._ucfg.copy()
260 self._ucfg = src._ucfg.copy()
261 self._ocfg = src._ocfg.copy()
261 self._ocfg = src._ocfg.copy()
262 self._trustusers = src._trustusers.copy()
262 self._trustusers = src._trustusers.copy()
263 self._trustgroups = src._trustgroups.copy()
263 self._trustgroups = src._trustgroups.copy()
264 self.environ = src.environ
264 self.environ = src.environ
265 self.callhooks = src.callhooks
265 self.callhooks = src.callhooks
266 self.insecureconnections = src.insecureconnections
266 self.insecureconnections = src.insecureconnections
267 self._colormode = src._colormode
267 self._colormode = src._colormode
268 self._terminfoparams = src._terminfoparams.copy()
268 self._terminfoparams = src._terminfoparams.copy()
269 self._styles = src._styles.copy()
269 self._styles = src._styles.copy()
270
270
271 self.fixconfig()
271 self.fixconfig()
272
272
273 self.httppasswordmgrdb = src.httppasswordmgrdb
273 self.httppasswordmgrdb = src.httppasswordmgrdb
274 self._blockedtimes = src._blockedtimes
274 self._blockedtimes = src._blockedtimes
275 else:
275 else:
276 self._fout = procutil.stdout
276 self._fout = procutil.stdout
277 self._ferr = procutil.stderr
277 self._ferr = procutil.stderr
278 self._fin = procutil.stdin
278 self._fin = procutil.stdin
279 self._fmsg = None
279 self._fmsg = None
280 self._fmsgout = self.fout # configurable
280 self._fmsgout = self.fout # configurable
281 self._fmsgerr = self.ferr # configurable
281 self._fmsgerr = self.ferr # configurable
282 self._finoutredirected = False
282 self._finoutredirected = False
283 self._loggers = {}
283 self._loggers = {}
284 self.pageractive = False
284 self.pageractive = False
285 self._disablepager = False
285 self._disablepager = False
286 self._tweaked = False
286 self._tweaked = False
287
287
288 # shared read-only environment
288 # shared read-only environment
289 self.environ = encoding.environ
289 self.environ = encoding.environ
290
290
291 self.httppasswordmgrdb = httppasswordmgrdbproxy()
291 self.httppasswordmgrdb = httppasswordmgrdbproxy()
292 self._blockedtimes = collections.defaultdict(int)
292 self._blockedtimes = collections.defaultdict(int)
293
293
294 allowed = self.configlist(b'experimental', b'exportableenviron')
294 allowed = self.configlist(b'experimental', b'exportableenviron')
295 if b'*' in allowed:
295 if b'*' in allowed:
296 self._exportableenviron = self.environ
296 self._exportableenviron = self.environ
297 else:
297 else:
298 self._exportableenviron = {}
298 self._exportableenviron = {}
299 for k in allowed:
299 for k in allowed:
300 if k in self.environ:
300 if k in self.environ:
301 self._exportableenviron[k] = self.environ[k]
301 self._exportableenviron[k] = self.environ[k]
302
302
303 @classmethod
303 @classmethod
304 def load(cls):
304 def load(cls):
305 """Create a ui and load global and user configs"""
305 """Create a ui and load global and user configs"""
306 u = cls()
306 u = cls()
307 # we always trust global config files and environment variables
307 # we always trust global config files and environment variables
308 for t, f in rcutil.rccomponents():
308 for t, f in rcutil.rccomponents():
309 if t == b'path':
309 if t == b'path':
310 u.readconfig(f, trust=True)
310 u.readconfig(f, trust=True)
311 elif t == b'resource':
311 elif t == b'resource':
312 u.read_resource_config(f, trust=True)
312 u.read_resource_config(f, trust=True)
313 elif t == b'items':
313 elif t == b'items':
314 sections = set()
314 sections = set()
315 for section, name, value, source in f:
315 for section, name, value, source in f:
316 # do not set u._ocfg
316 # do not set u._ocfg
317 # XXX clean this up once immutable config object is a thing
317 # XXX clean this up once immutable config object is a thing
318 u._tcfg.set(section, name, value, source)
318 u._tcfg.set(section, name, value, source)
319 u._ucfg.set(section, name, value, source)
319 u._ucfg.set(section, name, value, source)
320 sections.add(section)
320 sections.add(section)
321 for section in sections:
321 for section in sections:
322 u.fixconfig(section=section)
322 u.fixconfig(section=section)
323 else:
323 else:
324 raise error.ProgrammingError(b'unknown rctype: %s' % t)
324 raise error.ProgrammingError(b'unknown rctype: %s' % t)
325 u._maybetweakdefaults()
325 u._maybetweakdefaults()
326 return u
326 return u
327
327
328 def _maybetweakdefaults(self):
328 def _maybetweakdefaults(self):
329 if not self.configbool(b'ui', b'tweakdefaults'):
329 if not self.configbool(b'ui', b'tweakdefaults'):
330 return
330 return
331 if self._tweaked or self.plain(b'tweakdefaults'):
331 if self._tweaked or self.plain(b'tweakdefaults'):
332 return
332 return
333
333
334 # Note: it is SUPER IMPORTANT that you set self._tweaked to
334 # Note: it is SUPER IMPORTANT that you set self._tweaked to
335 # True *before* any calls to setconfig(), otherwise you'll get
335 # True *before* any calls to setconfig(), otherwise you'll get
336 # infinite recursion between setconfig and this method.
336 # infinite recursion between setconfig and this method.
337 #
337 #
338 # TODO: We should extract an inner method in setconfig() to
338 # TODO: We should extract an inner method in setconfig() to
339 # avoid this weirdness.
339 # avoid this weirdness.
340 self._tweaked = True
340 self._tweaked = True
341 tmpcfg = config.config()
341 tmpcfg = config.config()
342 tmpcfg.parse(b'<tweakdefaults>', tweakrc)
342 tmpcfg.parse(b'<tweakdefaults>', tweakrc)
343 for section in tmpcfg:
343 for section in tmpcfg:
344 for name, value in tmpcfg.items(section):
344 for name, value in tmpcfg.items(section):
345 if not self.hasconfig(section, name):
345 if not self.hasconfig(section, name):
346 self.setconfig(section, name, value, b"<tweakdefaults>")
346 self.setconfig(section, name, value, b"<tweakdefaults>")
347
347
348 def copy(self):
348 def copy(self):
349 return self.__class__(self)
349 return self.__class__(self)
350
350
351 def resetstate(self):
351 def resetstate(self):
352 """Clear internal state that shouldn't persist across commands"""
352 """Clear internal state that shouldn't persist across commands"""
353 if self._progbar:
353 if self._progbar:
354 self._progbar.resetstate() # reset last-print time of progress bar
354 self._progbar.resetstate() # reset last-print time of progress bar
355 self.httppasswordmgrdb = httppasswordmgrdbproxy()
355 self.httppasswordmgrdb = httppasswordmgrdbproxy()
356
356
357 @contextlib.contextmanager
357 @contextlib.contextmanager
358 def timeblockedsection(self, key):
358 def timeblockedsection(self, key):
359 # this is open-coded below - search for timeblockedsection to find them
359 # this is open-coded below - search for timeblockedsection to find them
360 starttime = util.timer()
360 starttime = util.timer()
361 try:
361 try:
362 yield
362 yield
363 finally:
363 finally:
364 self._blockedtimes[key + b'_blocked'] += (
364 self._blockedtimes[key + b'_blocked'] += (
365 util.timer() - starttime
365 util.timer() - starttime
366 ) * 1000
366 ) * 1000
367
367
368 @contextlib.contextmanager
368 @contextlib.contextmanager
369 def uninterruptible(self):
369 def uninterruptible(self):
370 """Mark an operation as unsafe.
370 """Mark an operation as unsafe.
371
371
372 Most operations on a repository are safe to interrupt, but a
372 Most operations on a repository are safe to interrupt, but a
373 few are risky (for example repair.strip). This context manager
373 few are risky (for example repair.strip). This context manager
374 lets you advise Mercurial that something risky is happening so
374 lets you advise Mercurial that something risky is happening so
375 that control-C etc can be blocked if desired.
375 that control-C etc can be blocked if desired.
376 """
376 """
377 enabled = self.configbool(b'experimental', b'nointerrupt')
377 enabled = self.configbool(b'experimental', b'nointerrupt')
378 if enabled and self.configbool(
378 if enabled and self.configbool(
379 b'experimental', b'nointerrupt-interactiveonly'
379 b'experimental', b'nointerrupt-interactiveonly'
380 ):
380 ):
381 enabled = self.interactive()
381 enabled = self.interactive()
382 if self._uninterruptible or not enabled:
382 if self._uninterruptible or not enabled:
383 # if nointerrupt support is turned off, the process isn't
383 # if nointerrupt support is turned off, the process isn't
384 # interactive, or we're already in an uninterruptible
384 # interactive, or we're already in an uninterruptible
385 # block, do nothing.
385 # block, do nothing.
386 yield
386 yield
387 return
387 return
388
388
389 def warn():
389 def warn():
390 self.warn(_(b"shutting down cleanly\n"))
390 self.warn(_(b"shutting down cleanly\n"))
391 self.warn(
391 self.warn(
392 _(b"press ^C again to terminate immediately (dangerous)\n")
392 _(b"press ^C again to terminate immediately (dangerous)\n")
393 )
393 )
394 return True
394 return True
395
395
396 with procutil.uninterruptible(warn):
396 with procutil.uninterruptible(warn):
397 try:
397 try:
398 self._uninterruptible = True
398 self._uninterruptible = True
399 yield
399 yield
400 finally:
400 finally:
401 self._uninterruptible = False
401 self._uninterruptible = False
402
402
403 def formatter(self, topic, opts):
403 def formatter(self, topic, opts):
404 return formatter.formatter(self, self, topic, opts)
404 return formatter.formatter(self, self, topic, opts)
405
405
406 def _trusted(self, fp, f):
406 def _trusted(self, fp, f):
407 st = util.fstat(fp)
407 st = util.fstat(fp)
408 if util.isowner(st):
408 if util.isowner(st):
409 return True
409 return True
410
410
411 tusers, tgroups = self._trustusers, self._trustgroups
411 tusers, tgroups = self._trustusers, self._trustgroups
412 if b'*' in tusers or b'*' in tgroups:
412 if b'*' in tusers or b'*' in tgroups:
413 return True
413 return True
414
414
415 user = util.username(st.st_uid)
415 user = util.username(st.st_uid)
416 group = util.groupname(st.st_gid)
416 group = util.groupname(st.st_gid)
417 if user in tusers or group in tgroups or user == util.username():
417 if user in tusers or group in tgroups or user == util.username():
418 return True
418 return True
419
419
420 if self._reportuntrusted:
420 if self._reportuntrusted:
421 self.warn(
421 self.warn(
422 _(
422 _(
423 b'not trusting file %s from untrusted '
423 b'not trusting file %s from untrusted '
424 b'user %s, group %s\n'
424 b'user %s, group %s\n'
425 )
425 )
426 % (f, user, group)
426 % (f, user, group)
427 )
427 )
428 return False
428 return False
429
429
430 def read_resource_config(
430 def read_resource_config(
431 self, name, root=None, trust=False, sections=None, remap=None
431 self, name, root=None, trust=False, sections=None, remap=None
432 ):
432 ):
433 try:
433 try:
434 fp = resourceutil.open_resource(name[0], name[1])
434 fp = resourceutil.open_resource(name[0], name[1])
435 except IOError:
435 except IOError:
436 if not sections: # ignore unless we were looking for something
436 if not sections: # ignore unless we were looking for something
437 return
437 return
438 raise
438 raise
439
439
440 self._readconfig(
440 self._readconfig(
441 b'resource:%s.%s' % name, fp, root, trust, sections, remap
441 b'resource:%s.%s' % name, fp, root, trust, sections, remap
442 )
442 )
443
443
444 def readconfig(
444 def readconfig(
445 self, filename, root=None, trust=False, sections=None, remap=None
445 self, filename, root=None, trust=False, sections=None, remap=None
446 ):
446 ):
447 try:
447 try:
448 fp = open(filename, 'rb')
448 fp = open(filename, 'rb')
449 except IOError:
449 except IOError:
450 if not sections: # ignore unless we were looking for something
450 if not sections: # ignore unless we were looking for something
451 return
451 return
452 raise
452 raise
453
453
454 self._readconfig(filename, fp, root, trust, sections, remap)
454 self._readconfig(filename, fp, root, trust, sections, remap)
455
455
456 def _readconfig(
456 def _readconfig(
457 self, filename, fp, root=None, trust=False, sections=None, remap=None
457 self, filename, fp, root=None, trust=False, sections=None, remap=None
458 ):
458 ):
459 with fp:
459 with fp:
460 cfg = config.config()
460 cfg = config.config()
461 trusted = sections or trust or self._trusted(fp, filename)
461 trusted = sections or trust or self._trusted(fp, filename)
462
462
463 try:
463 try:
464 cfg.read(filename, fp, sections=sections, remap=remap)
464 cfg.read(filename, fp, sections=sections, remap=remap)
465 except error.ParseError as inst:
465 except error.ParseError as inst:
466 if trusted:
466 if trusted:
467 raise
467 raise
468 self.warn(_(b'ignored: %s\n') % stringutil.forcebytestr(inst))
468 self.warn(_(b'ignored: %s\n') % stringutil.forcebytestr(inst))
469
469
470 self._applyconfig(cfg, trusted, root)
470 self._applyconfig(cfg, trusted, root)
471
471
472 def applyconfig(self, configitems, source=b"", root=None):
472 def applyconfig(self, configitems, source=b"", root=None):
473 """Add configitems from a non-file source. Unlike with ``setconfig()``,
473 """Add configitems from a non-file source. Unlike with ``setconfig()``,
474 they can be overridden by subsequent config file reads. The items are
474 they can be overridden by subsequent config file reads. The items are
475 in the same format as ``configoverride()``, namely a dict of the
475 in the same format as ``configoverride()``, namely a dict of the
476 following structures: {(section, name) : value}
476 following structures: {(section, name) : value}
477
477
478 Typically this is used by extensions that inject themselves into the
478 Typically this is used by extensions that inject themselves into the
479 config file load procedure by monkeypatching ``localrepo.loadhgrc()``.
479 config file load procedure by monkeypatching ``localrepo.loadhgrc()``.
480 """
480 """
481 cfg = config.config()
481 cfg = config.config()
482
482
483 for (section, name), value in configitems.items():
483 for (section, name), value in configitems.items():
484 cfg.set(section, name, value, source)
484 cfg.set(section, name, value, source)
485
485
486 self._applyconfig(cfg, True, root)
486 self._applyconfig(cfg, True, root)
487
487
488 def _applyconfig(self, cfg, trusted, root):
488 def _applyconfig(self, cfg, trusted, root):
489 if self.plain():
489 if self.plain():
490 for k in (
490 for k in (
491 b'debug',
491 b'debug',
492 b'fallbackencoding',
492 b'fallbackencoding',
493 b'quiet',
493 b'quiet',
494 b'slash',
494 b'slash',
495 b'logtemplate',
495 b'logtemplate',
496 b'message-output',
496 b'message-output',
497 b'statuscopies',
497 b'statuscopies',
498 b'style',
498 b'style',
499 b'traceback',
499 b'traceback',
500 b'verbose',
500 b'verbose',
501 ):
501 ):
502 if k in cfg[b'ui']:
502 if k in cfg[b'ui']:
503 del cfg[b'ui'][k]
503 del cfg[b'ui'][k]
504 for k, v in cfg.items(b'defaults'):
504 for k, v in cfg.items(b'defaults'):
505 del cfg[b'defaults'][k]
505 del cfg[b'defaults'][k]
506 for k, v in cfg.items(b'commands'):
506 for k, v in cfg.items(b'commands'):
507 del cfg[b'commands'][k]
507 del cfg[b'commands'][k]
508 # Don't remove aliases from the configuration if in the exceptionlist
508 # Don't remove aliases from the configuration if in the exceptionlist
509 if self.plain(b'alias'):
509 if self.plain(b'alias'):
510 for k, v in cfg.items(b'alias'):
510 for k, v in cfg.items(b'alias'):
511 del cfg[b'alias'][k]
511 del cfg[b'alias'][k]
512 if self.plain(b'revsetalias'):
512 if self.plain(b'revsetalias'):
513 for k, v in cfg.items(b'revsetalias'):
513 for k, v in cfg.items(b'revsetalias'):
514 del cfg[b'revsetalias'][k]
514 del cfg[b'revsetalias'][k]
515 if self.plain(b'templatealias'):
515 if self.plain(b'templatealias'):
516 for k, v in cfg.items(b'templatealias'):
516 for k, v in cfg.items(b'templatealias'):
517 del cfg[b'templatealias'][k]
517 del cfg[b'templatealias'][k]
518
518
519 if trusted:
519 if trusted:
520 self._tcfg.update(cfg)
520 self._tcfg.update(cfg)
521 self._tcfg.update(self._ocfg)
521 self._tcfg.update(self._ocfg)
522 self._ucfg.update(cfg)
522 self._ucfg.update(cfg)
523 self._ucfg.update(self._ocfg)
523 self._ucfg.update(self._ocfg)
524
524
525 if root is None:
525 if root is None:
526 root = os.path.expanduser(b'~')
526 root = os.path.expanduser(b'~')
527 self.fixconfig(root=root)
527 self.fixconfig(root=root)
528
528
529 def fixconfig(self, root=None, section=None):
529 def fixconfig(self, root=None, section=None):
530 if section in (None, b'paths'):
530 if section in (None, b'paths'):
531 # expand vars and ~
531 # expand vars and ~
532 # translate paths relative to root (or home) into absolute paths
532 # translate paths relative to root (or home) into absolute paths
533 root = root or encoding.getcwd()
533 root = root or encoding.getcwd()
534 for c in self._tcfg, self._ucfg, self._ocfg:
534 for c in self._tcfg, self._ucfg, self._ocfg:
535 for n, p in c.items(b'paths'):
535 for n, p in c.items(b'paths'):
536 # Ignore sub-options.
536 # Ignore sub-options.
537 if b':' in n:
537 if b':' in n:
538 continue
538 continue
539 if not p:
539 if not p:
540 continue
540 continue
541 if b'%%' in p:
541 if b'%%' in p:
542 s = self.configsource(b'paths', n) or b'none'
542 s = self.configsource(b'paths', n) or b'none'
543 self.warn(
543 self.warn(
544 _(b"(deprecated '%%' in path %s=%s from %s)\n")
544 _(b"(deprecated '%%' in path %s=%s from %s)\n")
545 % (n, p, s)
545 % (n, p, s)
546 )
546 )
547 p = p.replace(b'%%', b'%')
547 p = p.replace(b'%%', b'%')
548 p = util.expandpath(p)
548 p = util.expandpath(p)
549 if not util.hasscheme(p) and not os.path.isabs(p):
549 if not util.hasscheme(p) and not os.path.isabs(p):
550 p = os.path.normpath(os.path.join(root, p))
550 p = os.path.normpath(os.path.join(root, p))
551 c.set(b"paths", n, p)
551 c.set(b"paths", n, p)
552
552
553 if section in (None, b'ui'):
553 if section in (None, b'ui'):
554 # update ui options
554 # update ui options
555 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
555 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
556 self.debugflag = self.configbool(b'ui', b'debug')
556 self.debugflag = self.configbool(b'ui', b'debug')
557 self.verbose = self.debugflag or self.configbool(b'ui', b'verbose')
557 self.verbose = self.debugflag or self.configbool(b'ui', b'verbose')
558 self.quiet = not self.debugflag and self.configbool(b'ui', b'quiet')
558 self.quiet = not self.debugflag and self.configbool(b'ui', b'quiet')
559 if self.verbose and self.quiet:
559 if self.verbose and self.quiet:
560 self.quiet = self.verbose = False
560 self.quiet = self.verbose = False
561 self._reportuntrusted = self.debugflag or self.configbool(
561 self._reportuntrusted = self.debugflag or self.configbool(
562 b"ui", b"report_untrusted"
562 b"ui", b"report_untrusted"
563 )
563 )
564 self.tracebackflag = self.configbool(b'ui', b'traceback')
564 self.tracebackflag = self.configbool(b'ui', b'traceback')
565 self.logblockedtimes = self.configbool(b'ui', b'logblockedtimes')
565 self.logblockedtimes = self.configbool(b'ui', b'logblockedtimes')
566
566
567 if section in (None, b'trusted'):
567 if section in (None, b'trusted'):
568 # update trust information
568 # update trust information
569 self._trustusers.update(self.configlist(b'trusted', b'users'))
569 self._trustusers.update(self.configlist(b'trusted', b'users'))
570 self._trustgroups.update(self.configlist(b'trusted', b'groups'))
570 self._trustgroups.update(self.configlist(b'trusted', b'groups'))
571
571
572 if section in (None, b'devel', b'ui') and self.debugflag:
572 if section in (None, b'devel', b'ui') and self.debugflag:
573 tracked = set()
573 tracked = set()
574 if self.configbool(b'devel', b'debug.extensions'):
574 if self.configbool(b'devel', b'debug.extensions'):
575 tracked.add(b'extension')
575 tracked.add(b'extension')
576 if tracked:
576 if tracked:
577 logger = loggingutil.fileobjectlogger(self._ferr, tracked)
577 logger = loggingutil.fileobjectlogger(self._ferr, tracked)
578 self.setlogger(b'debug', logger)
578 self.setlogger(b'debug', logger)
579
579
580 def backupconfig(self, section, item):
580 def backupconfig(self, section, item):
581 return (
581 return (
582 self._ocfg.backup(section, item),
582 self._ocfg.backup(section, item),
583 self._tcfg.backup(section, item),
583 self._tcfg.backup(section, item),
584 self._ucfg.backup(section, item),
584 self._ucfg.backup(section, item),
585 )
585 )
586
586
587 def restoreconfig(self, data):
587 def restoreconfig(self, data):
588 self._ocfg.restore(data[0])
588 self._ocfg.restore(data[0])
589 self._tcfg.restore(data[1])
589 self._tcfg.restore(data[1])
590 self._ucfg.restore(data[2])
590 self._ucfg.restore(data[2])
591
591
592 def setconfig(self, section, name, value, source=b''):
592 def setconfig(self, section, name, value, source=b''):
593 for cfg in (self._ocfg, self._tcfg, self._ucfg):
593 for cfg in (self._ocfg, self._tcfg, self._ucfg):
594 cfg.set(section, name, value, source)
594 cfg.set(section, name, value, source)
595 self.fixconfig(section=section)
595 self.fixconfig(section=section)
596 self._maybetweakdefaults()
596 self._maybetweakdefaults()
597
597
598 def _data(self, untrusted):
598 def _data(self, untrusted):
599 return untrusted and self._ucfg or self._tcfg
599 return untrusted and self._ucfg or self._tcfg
600
600
601 def configsource(self, section, name, untrusted=False):
601 def configsource(self, section, name, untrusted=False):
602 return self._data(untrusted).source(section, name)
602 return self._data(untrusted).source(section, name)
603
603
604 def config(self, section, name, default=_unset, untrusted=False):
604 def config(self, section, name, default=_unset, untrusted=False):
605 """return the plain string version of a config"""
605 """return the plain string version of a config"""
606 value = self._config(
606 value = self._config(
607 section, name, default=default, untrusted=untrusted
607 section, name, default=default, untrusted=untrusted
608 )
608 )
609 if value is _unset:
609 if value is _unset:
610 return None
610 return None
611 return value
611 return value
612
612
613 def _config(self, section, name, default=_unset, untrusted=False):
613 def _config(self, section, name, default=_unset, untrusted=False):
614 value = itemdefault = default
614 value = itemdefault = default
615 item = self._knownconfig.get(section, {}).get(name)
615 item = self._knownconfig.get(section, {}).get(name)
616 alternates = [(section, name)]
616 alternates = [(section, name)]
617
617
618 if item is not None:
618 if item is not None:
619 alternates.extend(item.alias)
619 alternates.extend(item.alias)
620 if callable(item.default):
620 if callable(item.default):
621 itemdefault = item.default()
621 itemdefault = item.default()
622 else:
622 else:
623 itemdefault = item.default
623 itemdefault = item.default
624 else:
624 else:
625 msg = b"accessing unregistered config item: '%s.%s'"
625 msg = b"accessing unregistered config item: '%s.%s'"
626 msg %= (section, name)
626 msg %= (section, name)
627 self.develwarn(msg, 2, b'warn-config-unknown')
627 self.develwarn(msg, 2, b'warn-config-unknown')
628
628
629 if default is _unset:
629 if default is _unset:
630 if item is None:
630 if item is None:
631 value = default
631 value = default
632 elif item.default is configitems.dynamicdefault:
632 elif item.default is configitems.dynamicdefault:
633 value = None
633 value = None
634 msg = b"config item requires an explicit default value: '%s.%s'"
634 msg = b"config item requires an explicit default value: '%s.%s'"
635 msg %= (section, name)
635 msg %= (section, name)
636 self.develwarn(msg, 2, b'warn-config-default')
636 self.develwarn(msg, 2, b'warn-config-default')
637 else:
637 else:
638 value = itemdefault
638 value = itemdefault
639 elif (
639 elif (
640 item is not None
640 item is not None
641 and item.default is not configitems.dynamicdefault
641 and item.default is not configitems.dynamicdefault
642 and default != itemdefault
642 and default != itemdefault
643 ):
643 ):
644 msg = (
644 msg = (
645 b"specifying a mismatched default value for a registered "
645 b"specifying a mismatched default value for a registered "
646 b"config item: '%s.%s' '%s'"
646 b"config item: '%s.%s' '%s'"
647 )
647 )
648 msg %= (section, name, pycompat.bytestr(default))
648 msg %= (section, name, pycompat.bytestr(default))
649 self.develwarn(msg, 2, b'warn-config-default')
649 self.develwarn(msg, 2, b'warn-config-default')
650
650
651 for s, n in alternates:
651 for s, n in alternates:
652 candidate = self._data(untrusted).get(s, n, None)
652 candidate = self._data(untrusted).get(s, n, None)
653 if candidate is not None:
653 if candidate is not None:
654 value = candidate
654 value = candidate
655 break
655 break
656
656
657 if self.debugflag and not untrusted and self._reportuntrusted:
657 if self.debugflag and not untrusted and self._reportuntrusted:
658 for s, n in alternates:
658 for s, n in alternates:
659 uvalue = self._ucfg.get(s, n)
659 uvalue = self._ucfg.get(s, n)
660 if uvalue is not None and uvalue != value:
660 if uvalue is not None and uvalue != value:
661 self.debug(
661 self.debug(
662 b"ignoring untrusted configuration option "
662 b"ignoring untrusted configuration option "
663 b"%s.%s = %s\n" % (s, n, uvalue)
663 b"%s.%s = %s\n" % (s, n, uvalue)
664 )
664 )
665 return value
665 return value
666
666
667 def configsuboptions(self, section, name, default=_unset, untrusted=False):
667 def configsuboptions(self, section, name, default=_unset, untrusted=False):
668 """Get a config option and all sub-options.
668 """Get a config option and all sub-options.
669
669
670 Some config options have sub-options that are declared with the
670 Some config options have sub-options that are declared with the
671 format "key:opt = value". This method is used to return the main
671 format "key:opt = value". This method is used to return the main
672 option and all its declared sub-options.
672 option and all its declared sub-options.
673
673
674 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
674 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
675 is a dict of defined sub-options where keys and values are strings.
675 is a dict of defined sub-options where keys and values are strings.
676 """
676 """
677 main = self.config(section, name, default, untrusted=untrusted)
677 main = self.config(section, name, default, untrusted=untrusted)
678 data = self._data(untrusted)
678 data = self._data(untrusted)
679 sub = {}
679 sub = {}
680 prefix = b'%s:' % name
680 prefix = b'%s:' % name
681 for k, v in data.items(section):
681 for k, v in data.items(section):
682 if k.startswith(prefix):
682 if k.startswith(prefix):
683 sub[k[len(prefix) :]] = v
683 sub[k[len(prefix) :]] = v
684
684
685 if self.debugflag and not untrusted and self._reportuntrusted:
685 if self.debugflag and not untrusted and self._reportuntrusted:
686 for k, v in sub.items():
686 for k, v in sub.items():
687 uvalue = self._ucfg.get(section, b'%s:%s' % (name, k))
687 uvalue = self._ucfg.get(section, b'%s:%s' % (name, k))
688 if uvalue is not None and uvalue != v:
688 if uvalue is not None and uvalue != v:
689 self.debug(
689 self.debug(
690 b'ignoring untrusted configuration option '
690 b'ignoring untrusted configuration option '
691 b'%s:%s.%s = %s\n' % (section, name, k, uvalue)
691 b'%s:%s.%s = %s\n' % (section, name, k, uvalue)
692 )
692 )
693
693
694 return main, sub
694 return main, sub
695
695
696 def configpath(self, section, name, default=_unset, untrusted=False):
696 def configpath(self, section, name, default=_unset, untrusted=False):
697 """get a path config item, expanded relative to repo root or config
697 """get a path config item, expanded relative to repo root or config
698 file"""
698 file"""
699 v = self.config(section, name, default, untrusted)
699 v = self.config(section, name, default, untrusted)
700 if v is None:
700 if v is None:
701 return None
701 return None
702 if not os.path.isabs(v) or b"://" not in v:
702 if not os.path.isabs(v) or b"://" not in v:
703 src = self.configsource(section, name, untrusted)
703 src = self.configsource(section, name, untrusted)
704 if b':' in src:
704 if b':' in src:
705 base = os.path.dirname(src.rsplit(b':')[0])
705 base = os.path.dirname(src.rsplit(b':')[0])
706 v = os.path.join(base, os.path.expanduser(v))
706 v = os.path.join(base, os.path.expanduser(v))
707 return v
707 return v
708
708
709 def configbool(self, section, name, default=_unset, untrusted=False):
709 def configbool(self, section, name, default=_unset, untrusted=False):
710 """parse a configuration element as a boolean
710 """parse a configuration element as a boolean
711
711
712 >>> u = ui(); s = b'foo'
712 >>> u = ui(); s = b'foo'
713 >>> u.setconfig(s, b'true', b'yes')
713 >>> u.setconfig(s, b'true', b'yes')
714 >>> u.configbool(s, b'true')
714 >>> u.configbool(s, b'true')
715 True
715 True
716 >>> u.setconfig(s, b'false', b'no')
716 >>> u.setconfig(s, b'false', b'no')
717 >>> u.configbool(s, b'false')
717 >>> u.configbool(s, b'false')
718 False
718 False
719 >>> u.configbool(s, b'unknown')
719 >>> u.configbool(s, b'unknown')
720 False
720 False
721 >>> u.configbool(s, b'unknown', True)
721 >>> u.configbool(s, b'unknown', True)
722 True
722 True
723 >>> u.setconfig(s, b'invalid', b'somevalue')
723 >>> u.setconfig(s, b'invalid', b'somevalue')
724 >>> u.configbool(s, b'invalid')
724 >>> u.configbool(s, b'invalid')
725 Traceback (most recent call last):
725 Traceback (most recent call last):
726 ...
726 ...
727 ConfigError: foo.invalid is not a boolean ('somevalue')
727 ConfigError: foo.invalid is not a boolean ('somevalue')
728 """
728 """
729
729
730 v = self._config(section, name, default, untrusted=untrusted)
730 v = self._config(section, name, default, untrusted=untrusted)
731 if v is None:
731 if v is None:
732 return v
732 return v
733 if v is _unset:
733 if v is _unset:
734 if default is _unset:
734 if default is _unset:
735 return False
735 return False
736 return default
736 return default
737 if isinstance(v, bool):
737 if isinstance(v, bool):
738 return v
738 return v
739 b = stringutil.parsebool(v)
739 b = stringutil.parsebool(v)
740 if b is None:
740 if b is None:
741 raise error.ConfigError(
741 raise error.ConfigError(
742 _(b"%s.%s is not a boolean ('%s')") % (section, name, v)
742 _(b"%s.%s is not a boolean ('%s')") % (section, name, v)
743 )
743 )
744 return b
744 return b
745
745
746 def configwith(
746 def configwith(
747 self, convert, section, name, default=_unset, desc=None, untrusted=False
747 self, convert, section, name, default=_unset, desc=None, untrusted=False
748 ):
748 ):
749 """parse a configuration element with a conversion function
749 """parse a configuration element with a conversion function
750
750
751 >>> u = ui(); s = b'foo'
751 >>> u = ui(); s = b'foo'
752 >>> u.setconfig(s, b'float1', b'42')
752 >>> u.setconfig(s, b'float1', b'42')
753 >>> u.configwith(float, s, b'float1')
753 >>> u.configwith(float, s, b'float1')
754 42.0
754 42.0
755 >>> u.setconfig(s, b'float2', b'-4.25')
755 >>> u.setconfig(s, b'float2', b'-4.25')
756 >>> u.configwith(float, s, b'float2')
756 >>> u.configwith(float, s, b'float2')
757 -4.25
757 -4.25
758 >>> u.configwith(float, s, b'unknown', 7)
758 >>> u.configwith(float, s, b'unknown', 7)
759 7.0
759 7.0
760 >>> u.setconfig(s, b'invalid', b'somevalue')
760 >>> u.setconfig(s, b'invalid', b'somevalue')
761 >>> u.configwith(float, s, b'invalid')
761 >>> u.configwith(float, s, b'invalid')
762 Traceback (most recent call last):
762 Traceback (most recent call last):
763 ...
763 ...
764 ConfigError: foo.invalid is not a valid float ('somevalue')
764 ConfigError: foo.invalid is not a valid float ('somevalue')
765 >>> u.configwith(float, s, b'invalid', desc=b'womble')
765 >>> u.configwith(float, s, b'invalid', desc=b'womble')
766 Traceback (most recent call last):
766 Traceback (most recent call last):
767 ...
767 ...
768 ConfigError: foo.invalid is not a valid womble ('somevalue')
768 ConfigError: foo.invalid is not a valid womble ('somevalue')
769 """
769 """
770
770
771 v = self.config(section, name, default, untrusted)
771 v = self.config(section, name, default, untrusted)
772 if v is None:
772 if v is None:
773 return v # do not attempt to convert None
773 return v # do not attempt to convert None
774 try:
774 try:
775 return convert(v)
775 return convert(v)
776 except (ValueError, error.ParseError):
776 except (ValueError, error.ParseError):
777 if desc is None:
777 if desc is None:
778 desc = pycompat.sysbytes(convert.__name__)
778 desc = pycompat.sysbytes(convert.__name__)
779 raise error.ConfigError(
779 raise error.ConfigError(
780 _(b"%s.%s is not a valid %s ('%s')") % (section, name, desc, v)
780 _(b"%s.%s is not a valid %s ('%s')") % (section, name, desc, v)
781 )
781 )
782
782
783 def configint(self, section, name, default=_unset, untrusted=False):
783 def configint(self, section, name, default=_unset, untrusted=False):
784 """parse a configuration element as an integer
784 """parse a configuration element as an integer
785
785
786 >>> u = ui(); s = b'foo'
786 >>> u = ui(); s = b'foo'
787 >>> u.setconfig(s, b'int1', b'42')
787 >>> u.setconfig(s, b'int1', b'42')
788 >>> u.configint(s, b'int1')
788 >>> u.configint(s, b'int1')
789 42
789 42
790 >>> u.setconfig(s, b'int2', b'-42')
790 >>> u.setconfig(s, b'int2', b'-42')
791 >>> u.configint(s, b'int2')
791 >>> u.configint(s, b'int2')
792 -42
792 -42
793 >>> u.configint(s, b'unknown', 7)
793 >>> u.configint(s, b'unknown', 7)
794 7
794 7
795 >>> u.setconfig(s, b'invalid', b'somevalue')
795 >>> u.setconfig(s, b'invalid', b'somevalue')
796 >>> u.configint(s, b'invalid')
796 >>> u.configint(s, b'invalid')
797 Traceback (most recent call last):
797 Traceback (most recent call last):
798 ...
798 ...
799 ConfigError: foo.invalid is not a valid integer ('somevalue')
799 ConfigError: foo.invalid is not a valid integer ('somevalue')
800 """
800 """
801
801
802 return self.configwith(
802 return self.configwith(
803 int, section, name, default, b'integer', untrusted
803 int, section, name, default, b'integer', untrusted
804 )
804 )
805
805
806 def configbytes(self, section, name, default=_unset, untrusted=False):
806 def configbytes(self, section, name, default=_unset, untrusted=False):
807 """parse a configuration element as a quantity in bytes
807 """parse a configuration element as a quantity in bytes
808
808
809 Units can be specified as b (bytes), k or kb (kilobytes), m or
809 Units can be specified as b (bytes), k or kb (kilobytes), m or
810 mb (megabytes), g or gb (gigabytes).
810 mb (megabytes), g or gb (gigabytes).
811
811
812 >>> u = ui(); s = b'foo'
812 >>> u = ui(); s = b'foo'
813 >>> u.setconfig(s, b'val1', b'42')
813 >>> u.setconfig(s, b'val1', b'42')
814 >>> u.configbytes(s, b'val1')
814 >>> u.configbytes(s, b'val1')
815 42
815 42
816 >>> u.setconfig(s, b'val2', b'42.5 kb')
816 >>> u.setconfig(s, b'val2', b'42.5 kb')
817 >>> u.configbytes(s, b'val2')
817 >>> u.configbytes(s, b'val2')
818 43520
818 43520
819 >>> u.configbytes(s, b'unknown', b'7 MB')
819 >>> u.configbytes(s, b'unknown', b'7 MB')
820 7340032
820 7340032
821 >>> u.setconfig(s, b'invalid', b'somevalue')
821 >>> u.setconfig(s, b'invalid', b'somevalue')
822 >>> u.configbytes(s, b'invalid')
822 >>> u.configbytes(s, b'invalid')
823 Traceback (most recent call last):
823 Traceback (most recent call last):
824 ...
824 ...
825 ConfigError: foo.invalid is not a byte quantity ('somevalue')
825 ConfigError: foo.invalid is not a byte quantity ('somevalue')
826 """
826 """
827
827
828 value = self._config(section, name, default, untrusted)
828 value = self._config(section, name, default, untrusted)
829 if value is _unset:
829 if value is _unset:
830 if default is _unset:
830 if default is _unset:
831 default = 0
831 default = 0
832 value = default
832 value = default
833 if not isinstance(value, bytes):
833 if not isinstance(value, bytes):
834 return value
834 return value
835 try:
835 try:
836 return util.sizetoint(value)
836 return util.sizetoint(value)
837 except error.ParseError:
837 except error.ParseError:
838 raise error.ConfigError(
838 raise error.ConfigError(
839 _(b"%s.%s is not a byte quantity ('%s')")
839 _(b"%s.%s is not a byte quantity ('%s')")
840 % (section, name, value)
840 % (section, name, value)
841 )
841 )
842
842
843 def configlist(self, section, name, default=_unset, untrusted=False):
843 def configlist(self, section, name, default=_unset, untrusted=False):
844 """parse a configuration element as a list of comma/space separated
844 """parse a configuration element as a list of comma/space separated
845 strings
845 strings
846
846
847 >>> u = ui(); s = b'foo'
847 >>> u = ui(); s = b'foo'
848 >>> u.setconfig(s, b'list1', b'this,is "a small" ,test')
848 >>> u.setconfig(s, b'list1', b'this,is "a small" ,test')
849 >>> u.configlist(s, b'list1')
849 >>> u.configlist(s, b'list1')
850 ['this', 'is', 'a small', 'test']
850 ['this', 'is', 'a small', 'test']
851 >>> u.setconfig(s, b'list2', b'this, is "a small" , test ')
851 >>> u.setconfig(s, b'list2', b'this, is "a small" , test ')
852 >>> u.configlist(s, b'list2')
852 >>> u.configlist(s, b'list2')
853 ['this', 'is', 'a small', 'test']
853 ['this', 'is', 'a small', 'test']
854 """
854 """
855 # default is not always a list
855 # default is not always a list
856 v = self.configwith(
856 v = self.configwith(
857 config.parselist, section, name, default, b'list', untrusted
857 config.parselist, section, name, default, b'list', untrusted
858 )
858 )
859 if isinstance(v, bytes):
859 if isinstance(v, bytes):
860 return config.parselist(v)
860 return config.parselist(v)
861 elif v is None:
861 elif v is None:
862 return []
862 return []
863 return v
863 return v
864
864
865 def configdate(self, section, name, default=_unset, untrusted=False):
865 def configdate(self, section, name, default=_unset, untrusted=False):
866 """parse a configuration element as a tuple of ints
866 """parse a configuration element as a tuple of ints
867
867
868 >>> u = ui(); s = b'foo'
868 >>> u = ui(); s = b'foo'
869 >>> u.setconfig(s, b'date', b'0 0')
869 >>> u.setconfig(s, b'date', b'0 0')
870 >>> u.configdate(s, b'date')
870 >>> u.configdate(s, b'date')
871 (0, 0)
871 (0, 0)
872 """
872 """
873 if self.config(section, name, default, untrusted):
873 if self.config(section, name, default, untrusted):
874 return self.configwith(
874 return self.configwith(
875 dateutil.parsedate, section, name, default, b'date', untrusted
875 dateutil.parsedate, section, name, default, b'date', untrusted
876 )
876 )
877 if default is _unset:
877 if default is _unset:
878 return None
878 return None
879 return default
879 return default
880
880
881 def configdefault(self, section, name):
881 def configdefault(self, section, name):
882 """returns the default value of the config item"""
882 """returns the default value of the config item"""
883 item = self._knownconfig.get(section, {}).get(name)
883 item = self._knownconfig.get(section, {}).get(name)
884 itemdefault = None
884 itemdefault = None
885 if item is not None:
885 if item is not None:
886 if callable(item.default):
886 if callable(item.default):
887 itemdefault = item.default()
887 itemdefault = item.default()
888 else:
888 else:
889 itemdefault = item.default
889 itemdefault = item.default
890 return itemdefault
890 return itemdefault
891
891
892 def hasconfig(self, section, name, untrusted=False):
892 def hasconfig(self, section, name, untrusted=False):
893 return self._data(untrusted).hasitem(section, name)
893 return self._data(untrusted).hasitem(section, name)
894
894
895 def has_section(self, section, untrusted=False):
895 def has_section(self, section, untrusted=False):
896 '''tell whether section exists in config.'''
896 '''tell whether section exists in config.'''
897 return section in self._data(untrusted)
897 return section in self._data(untrusted)
898
898
899 def configitems(self, section, untrusted=False, ignoresub=False):
899 def configitems(self, section, untrusted=False, ignoresub=False):
900 items = self._data(untrusted).items(section)
900 items = self._data(untrusted).items(section)
901 if ignoresub:
901 if ignoresub:
902 items = [i for i in items if b':' not in i[0]]
902 items = [i for i in items if b':' not in i[0]]
903 if self.debugflag and not untrusted and self._reportuntrusted:
903 if self.debugflag and not untrusted and self._reportuntrusted:
904 for k, v in self._ucfg.items(section):
904 for k, v in self._ucfg.items(section):
905 if self._tcfg.get(section, k) != v:
905 if self._tcfg.get(section, k) != v:
906 self.debug(
906 self.debug(
907 b"ignoring untrusted configuration option "
907 b"ignoring untrusted configuration option "
908 b"%s.%s = %s\n" % (section, k, v)
908 b"%s.%s = %s\n" % (section, k, v)
909 )
909 )
910 return items
910 return items
911
911
912 def walkconfig(self, untrusted=False):
912 def walkconfig(self, untrusted=False):
913 cfg = self._data(untrusted)
913 cfg = self._data(untrusted)
914 for section in cfg.sections():
914 for section in cfg.sections():
915 for name, value in self.configitems(section, untrusted):
915 for name, value in self.configitems(section, untrusted):
916 yield section, name, value
916 yield section, name, value
917
917
918 def plain(self, feature=None):
918 def plain(self, feature=None):
919 '''is plain mode active?
919 '''is plain mode active?
920
920
921 Plain mode means that all configuration variables which affect
921 Plain mode means that all configuration variables which affect
922 the behavior and output of Mercurial should be
922 the behavior and output of Mercurial should be
923 ignored. Additionally, the output should be stable,
923 ignored. Additionally, the output should be stable,
924 reproducible and suitable for use in scripts or applications.
924 reproducible and suitable for use in scripts or applications.
925
925
926 The only way to trigger plain mode is by setting either the
926 The only way to trigger plain mode is by setting either the
927 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
927 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
928
928
929 The return value can either be
929 The return value can either be
930 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
930 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
931 - False if feature is disabled by default and not included in HGPLAIN
931 - False if feature is disabled by default and not included in HGPLAIN
932 - True otherwise
932 - True otherwise
933 '''
933 '''
934 if (
934 if (
935 b'HGPLAIN' not in encoding.environ
935 b'HGPLAIN' not in encoding.environ
936 and b'HGPLAINEXCEPT' not in encoding.environ
936 and b'HGPLAINEXCEPT' not in encoding.environ
937 ):
937 ):
938 return False
938 return False
939 exceptions = (
939 exceptions = (
940 encoding.environ.get(b'HGPLAINEXCEPT', b'').strip().split(b',')
940 encoding.environ.get(b'HGPLAINEXCEPT', b'').strip().split(b',')
941 )
941 )
942 # TODO: add support for HGPLAIN=+feature,-feature syntax
942 # TODO: add support for HGPLAIN=+feature,-feature syntax
943 if b'+strictflags' not in encoding.environ.get(b'HGPLAIN', b'').split(
943 if b'+strictflags' not in encoding.environ.get(b'HGPLAIN', b'').split(
944 b','
944 b','
945 ):
945 ):
946 exceptions.append(b'strictflags')
946 exceptions.append(b'strictflags')
947 if feature and exceptions:
947 if feature and exceptions:
948 return feature not in exceptions
948 return feature not in exceptions
949 return True
949 return True
950
950
951 def username(self, acceptempty=False):
951 def username(self, acceptempty=False):
952 """Return default username to be used in commits.
952 """Return default username to be used in commits.
953
953
954 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
954 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
955 and stop searching if one of these is set.
955 and stop searching if one of these is set.
956 If not found and acceptempty is True, returns None.
956 If not found and acceptempty is True, returns None.
957 If not found and ui.askusername is True, ask the user, else use
957 If not found and ui.askusername is True, ask the user, else use
958 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
958 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
959 If no username could be found, raise an Abort error.
959 If no username could be found, raise an Abort error.
960 """
960 """
961 user = encoding.environ.get(b"HGUSER")
961 user = encoding.environ.get(b"HGUSER")
962 if user is None:
962 if user is None:
963 user = self.config(b"ui", b"username")
963 user = self.config(b"ui", b"username")
964 if user is not None:
964 if user is not None:
965 user = os.path.expandvars(user)
965 user = os.path.expandvars(user)
966 if user is None:
966 if user is None:
967 user = encoding.environ.get(b"EMAIL")
967 user = encoding.environ.get(b"EMAIL")
968 if user is None and acceptempty:
968 if user is None and acceptempty:
969 return user
969 return user
970 if user is None and self.configbool(b"ui", b"askusername"):
970 if user is None and self.configbool(b"ui", b"askusername"):
971 user = self.prompt(_(b"enter a commit username:"), default=None)
971 user = self.prompt(_(b"enter a commit username:"), default=None)
972 if user is None and not self.interactive():
972 if user is None and not self.interactive():
973 try:
973 try:
974 user = b'%s@%s' % (
974 user = b'%s@%s' % (
975 procutil.getuser(),
975 procutil.getuser(),
976 encoding.strtolocal(socket.getfqdn()),
976 encoding.strtolocal(socket.getfqdn()),
977 )
977 )
978 self.warn(_(b"no username found, using '%s' instead\n") % user)
978 self.warn(_(b"no username found, using '%s' instead\n") % user)
979 except KeyError:
979 except KeyError:
980 pass
980 pass
981 if not user:
981 if not user:
982 raise error.Abort(
982 raise error.Abort(
983 _(b'no username supplied'),
983 _(b'no username supplied'),
984 hint=_(b"use 'hg config --edit' " b'to set your username'),
984 hint=_(b"use 'hg config --edit' " b'to set your username'),
985 )
985 )
986 if b"\n" in user:
986 if b"\n" in user:
987 raise error.Abort(
987 raise error.Abort(
988 _(b"username %r contains a newline\n") % pycompat.bytestr(user)
988 _(b"username %r contains a newline\n") % pycompat.bytestr(user)
989 )
989 )
990 return user
990 return user
991
991
992 def shortuser(self, user):
992 def shortuser(self, user):
993 """Return a short representation of a user name or email address."""
993 """Return a short representation of a user name or email address."""
994 if not self.verbose:
994 if not self.verbose:
995 user = stringutil.shortuser(user)
995 user = stringutil.shortuser(user)
996 return user
996 return user
997
997
998 def expandpath(self, loc, default=None):
998 def expandpath(self, loc, default=None):
999 """Return repository location relative to cwd or from [paths]"""
999 """Return repository location relative to cwd or from [paths]"""
1000 try:
1000 try:
1001 p = self.paths.getpath(loc)
1001 p = self.paths.getpath(loc)
1002 if p:
1002 if p:
1003 return p.rawloc
1003 return p.rawloc
1004 except error.RepoError:
1004 except error.RepoError:
1005 pass
1005 pass
1006
1006
1007 if default:
1007 if default:
1008 try:
1008 try:
1009 p = self.paths.getpath(default)
1009 p = self.paths.getpath(default)
1010 if p:
1010 if p:
1011 return p.rawloc
1011 return p.rawloc
1012 except error.RepoError:
1012 except error.RepoError:
1013 pass
1013 pass
1014
1014
1015 return loc
1015 return loc
1016
1016
1017 @util.propertycache
1017 @util.propertycache
1018 def paths(self):
1018 def paths(self):
1019 return paths(self)
1019 return paths(self)
1020
1020
1021 @property
1021 @property
1022 def fout(self):
1022 def fout(self):
1023 return self._fout
1023 return self._fout
1024
1024
1025 @fout.setter
1025 @fout.setter
1026 def fout(self, f):
1026 def fout(self, f):
1027 self._fout = f
1027 self._fout = f
1028 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1028 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1029
1029
1030 @property
1030 @property
1031 def ferr(self):
1031 def ferr(self):
1032 return self._ferr
1032 return self._ferr
1033
1033
1034 @ferr.setter
1034 @ferr.setter
1035 def ferr(self, f):
1035 def ferr(self, f):
1036 self._ferr = f
1036 self._ferr = f
1037 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1037 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1038
1038
1039 @property
1039 @property
1040 def fin(self):
1040 def fin(self):
1041 return self._fin
1041 return self._fin
1042
1042
1043 @fin.setter
1043 @fin.setter
1044 def fin(self, f):
1044 def fin(self, f):
1045 self._fin = f
1045 self._fin = f
1046
1046
1047 @property
1047 @property
1048 def fmsg(self):
1048 def fmsg(self):
1049 """Stream dedicated for status/error messages; may be None if
1049 """Stream dedicated for status/error messages; may be None if
1050 fout/ferr are used"""
1050 fout/ferr are used"""
1051 return self._fmsg
1051 return self._fmsg
1052
1052
1053 @fmsg.setter
1053 @fmsg.setter
1054 def fmsg(self, f):
1054 def fmsg(self, f):
1055 self._fmsg = f
1055 self._fmsg = f
1056 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1056 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1057
1057
1058 def pushbuffer(self, error=False, subproc=False, labeled=False):
1058 def pushbuffer(self, error=False, subproc=False, labeled=False):
1059 """install a buffer to capture standard output of the ui object
1059 """install a buffer to capture standard output of the ui object
1060
1060
1061 If error is True, the error output will be captured too.
1061 If error is True, the error output will be captured too.
1062
1062
1063 If subproc is True, output from subprocesses (typically hooks) will be
1063 If subproc is True, output from subprocesses (typically hooks) will be
1064 captured too.
1064 captured too.
1065
1065
1066 If labeled is True, any labels associated with buffered
1066 If labeled is True, any labels associated with buffered
1067 output will be handled. By default, this has no effect
1067 output will be handled. By default, this has no effect
1068 on the output returned, but extensions and GUI tools may
1068 on the output returned, but extensions and GUI tools may
1069 handle this argument and returned styled output. If output
1069 handle this argument and returned styled output. If output
1070 is being buffered so it can be captured and parsed or
1070 is being buffered so it can be captured and parsed or
1071 processed, labeled should not be set to True.
1071 processed, labeled should not be set to True.
1072 """
1072 """
1073 self._buffers.append([])
1073 self._buffers.append([])
1074 self._bufferstates.append((error, subproc, labeled))
1074 self._bufferstates.append((error, subproc, labeled))
1075 self._bufferapplylabels = labeled
1075 self._bufferapplylabels = labeled
1076
1076
1077 def popbuffer(self):
1077 def popbuffer(self):
1078 '''pop the last buffer and return the buffered output'''
1078 '''pop the last buffer and return the buffered output'''
1079 self._bufferstates.pop()
1079 self._bufferstates.pop()
1080 if self._bufferstates:
1080 if self._bufferstates:
1081 self._bufferapplylabels = self._bufferstates[-1][2]
1081 self._bufferapplylabels = self._bufferstates[-1][2]
1082 else:
1082 else:
1083 self._bufferapplylabels = None
1083 self._bufferapplylabels = None
1084
1084
1085 return b"".join(self._buffers.pop())
1085 return b"".join(self._buffers.pop())
1086
1086
1087 def _isbuffered(self, dest):
1087 def _isbuffered(self, dest):
1088 if dest is self._fout:
1088 if dest is self._fout:
1089 return bool(self._buffers)
1089 return bool(self._buffers)
1090 if dest is self._ferr:
1090 if dest is self._ferr:
1091 return bool(self._bufferstates and self._bufferstates[-1][0])
1091 return bool(self._bufferstates and self._bufferstates[-1][0])
1092 return False
1092 return False
1093
1093
1094 def canwritewithoutlabels(self):
1094 def canwritewithoutlabels(self):
1095 '''check if write skips the label'''
1095 '''check if write skips the label'''
1096 if self._buffers and not self._bufferapplylabels:
1096 if self._buffers and not self._bufferapplylabels:
1097 return True
1097 return True
1098 return self._colormode is None
1098 return self._colormode is None
1099
1099
1100 def canbatchlabeledwrites(self):
1100 def canbatchlabeledwrites(self):
1101 '''check if write calls with labels are batchable'''
1101 '''check if write calls with labels are batchable'''
1102 # Windows color printing is special, see ``write``.
1102 # Windows color printing is special, see ``write``.
1103 return self._colormode != b'win32'
1103 return self._colormode != b'win32'
1104
1104
1105 def write(self, *args, **opts):
1105 def write(self, *args, **opts):
1106 '''write args to output
1106 '''write args to output
1107
1107
1108 By default, this method simply writes to the buffer or stdout.
1108 By default, this method simply writes to the buffer or stdout.
1109 Color mode can be set on the UI class to have the output decorated
1109 Color mode can be set on the UI class to have the output decorated
1110 with color modifier before being written to stdout.
1110 with color modifier before being written to stdout.
1111
1111
1112 The color used is controlled by an optional keyword argument, "label".
1112 The color used is controlled by an optional keyword argument, "label".
1113 This should be a string containing label names separated by space.
1113 This should be a string containing label names separated by space.
1114 Label names take the form of "topic.type". For example, ui.debug()
1114 Label names take the form of "topic.type". For example, ui.debug()
1115 issues a label of "ui.debug".
1115 issues a label of "ui.debug".
1116
1116
1117 Progress reports via stderr are normally cleared before writing as
1117 Progress reports via stderr are normally cleared before writing as
1118 stdout and stderr go to the same terminal. This can be skipped with
1118 stdout and stderr go to the same terminal. This can be skipped with
1119 the optional keyword argument "keepprogressbar". The progress bar
1119 the optional keyword argument "keepprogressbar". The progress bar
1120 will continue to occupy a partial line on stderr in that case.
1120 will continue to occupy a partial line on stderr in that case.
1121 This functionality is intended when Mercurial acts as data source
1121 This functionality is intended when Mercurial acts as data source
1122 in a pipe.
1122 in a pipe.
1123
1123
1124 When labeling output for a specific command, a label of
1124 When labeling output for a specific command, a label of
1125 "cmdname.type" is recommended. For example, status issues
1125 "cmdname.type" is recommended. For example, status issues
1126 a label of "status.modified" for modified files.
1126 a label of "status.modified" for modified files.
1127 '''
1127 '''
1128 dest = self._fout
1128 dest = self._fout
1129
1129
1130 # inlined _write() for speed
1130 # inlined _write() for speed
1131 if self._buffers:
1131 if self._buffers:
1132 label = opts.get('label', b'')
1132 label = opts.get('label', b'')
1133 if label and self._bufferapplylabels:
1133 if label and self._bufferapplylabels:
1134 self._buffers[-1].extend(self.label(a, label) for a in args)
1134 self._buffers[-1].extend(self.label(a, label) for a in args)
1135 else:
1135 else:
1136 self._buffers[-1].extend(args)
1136 self._buffers[-1].extend(args)
1137 return
1137 return
1138
1138
1139 # inlined _writenobuf() for speed
1139 # inlined _writenobuf() for speed
1140 if not opts.get('keepprogressbar', False):
1140 if not opts.get('keepprogressbar', False):
1141 self._progclear()
1141 self._progclear()
1142 msg = b''.join(args)
1142 msg = b''.join(args)
1143
1143
1144 # opencode timeblockedsection because this is a critical path
1144 # opencode timeblockedsection because this is a critical path
1145 starttime = util.timer()
1145 starttime = util.timer()
1146 try:
1146 try:
1147 if self._colormode == b'win32':
1147 if self._colormode == b'win32':
1148 # windows color printing is its own can of crab, defer to
1148 # windows color printing is its own can of crab, defer to
1149 # the color module and that is it.
1149 # the color module and that is it.
1150 color.win32print(self, dest.write, msg, **opts)
1150 color.win32print(self, dest.write, msg, **opts)
1151 else:
1151 else:
1152 if self._colormode is not None:
1152 if self._colormode is not None:
1153 label = opts.get('label', b'')
1153 label = opts.get('label', b'')
1154 msg = self.label(msg, label)
1154 msg = self.label(msg, label)
1155 dest.write(msg)
1155 dest.write(msg)
1156 except IOError as err:
1156 except IOError as err:
1157 raise error.StdioError(err)
1157 raise error.StdioError(err)
1158 finally:
1158 finally:
1159 self._blockedtimes[b'stdio_blocked'] += (
1159 self._blockedtimes[b'stdio_blocked'] += (
1160 util.timer() - starttime
1160 util.timer() - starttime
1161 ) * 1000
1161 ) * 1000
1162
1162
1163 def write_err(self, *args, **opts):
1163 def write_err(self, *args, **opts):
1164 self._write(self._ferr, *args, **opts)
1164 self._write(self._ferr, *args, **opts)
1165
1165
1166 def _write(self, dest, *args, **opts):
1166 def _write(self, dest, *args, **opts):
1167 # update write() as well if you touch this code
1167 # update write() as well if you touch this code
1168 if self._isbuffered(dest):
1168 if self._isbuffered(dest):
1169 label = opts.get('label', b'')
1169 label = opts.get('label', b'')
1170 if label and self._bufferapplylabels:
1170 if label and self._bufferapplylabels:
1171 self._buffers[-1].extend(self.label(a, label) for a in args)
1171 self._buffers[-1].extend(self.label(a, label) for a in args)
1172 else:
1172 else:
1173 self._buffers[-1].extend(args)
1173 self._buffers[-1].extend(args)
1174 else:
1174 else:
1175 self._writenobuf(dest, *args, **opts)
1175 self._writenobuf(dest, *args, **opts)
1176
1176
1177 def _writenobuf(self, dest, *args, **opts):
1177 def _writenobuf(self, dest, *args, **opts):
1178 # update write() as well if you touch this code
1178 # update write() as well if you touch this code
1179 if not opts.get('keepprogressbar', False):
1179 if not opts.get('keepprogressbar', False):
1180 self._progclear()
1180 self._progclear()
1181 msg = b''.join(args)
1181 msg = b''.join(args)
1182
1182
1183 # opencode timeblockedsection because this is a critical path
1183 # opencode timeblockedsection because this is a critical path
1184 starttime = util.timer()
1184 starttime = util.timer()
1185 try:
1185 try:
1186 if dest is self._ferr and not getattr(self._fout, 'closed', False):
1186 if dest is self._ferr and not getattr(self._fout, 'closed', False):
1187 self._fout.flush()
1187 self._fout.flush()
1188 if getattr(dest, 'structured', False):
1188 if getattr(dest, 'structured', False):
1189 # channel for machine-readable output with metadata, where
1189 # channel for machine-readable output with metadata, where
1190 # no extra colorization is necessary.
1190 # no extra colorization is necessary.
1191 dest.write(msg, **opts)
1191 dest.write(msg, **opts)
1192 elif self._colormode == b'win32':
1192 elif self._colormode == b'win32':
1193 # windows color printing is its own can of crab, defer to
1193 # windows color printing is its own can of crab, defer to
1194 # the color module and that is it.
1194 # the color module and that is it.
1195 color.win32print(self, dest.write, msg, **opts)
1195 color.win32print(self, dest.write, msg, **opts)
1196 else:
1196 else:
1197 if self._colormode is not None:
1197 if self._colormode is not None:
1198 label = opts.get('label', b'')
1198 label = opts.get('label', b'')
1199 msg = self.label(msg, label)
1199 msg = self.label(msg, label)
1200 dest.write(msg)
1200 dest.write(msg)
1201 # stderr may be buffered under win32 when redirected to files,
1201 # stderr may be buffered under win32 when redirected to files,
1202 # including stdout.
1202 # including stdout.
1203 if dest is self._ferr and not getattr(self._ferr, 'closed', False):
1203 if dest is self._ferr and not getattr(self._ferr, 'closed', False):
1204 dest.flush()
1204 dest.flush()
1205 except IOError as err:
1205 except IOError as err:
1206 if dest is self._ferr and err.errno in (
1206 if dest is self._ferr and err.errno in (
1207 errno.EPIPE,
1207 errno.EPIPE,
1208 errno.EIO,
1208 errno.EIO,
1209 errno.EBADF,
1209 errno.EBADF,
1210 ):
1210 ):
1211 # no way to report the error, so ignore it
1211 # no way to report the error, so ignore it
1212 return
1212 return
1213 raise error.StdioError(err)
1213 raise error.StdioError(err)
1214 finally:
1214 finally:
1215 self._blockedtimes[b'stdio_blocked'] += (
1215 self._blockedtimes[b'stdio_blocked'] += (
1216 util.timer() - starttime
1216 util.timer() - starttime
1217 ) * 1000
1217 ) * 1000
1218
1218
1219 def _writemsg(self, dest, *args, **opts):
1219 def _writemsg(self, dest, *args, **opts):
1220 _writemsgwith(self._write, dest, *args, **opts)
1220 _writemsgwith(self._write, dest, *args, **opts)
1221
1221
1222 def _writemsgnobuf(self, dest, *args, **opts):
1222 def _writemsgnobuf(self, dest, *args, **opts):
1223 _writemsgwith(self._writenobuf, dest, *args, **opts)
1223 _writemsgwith(self._writenobuf, dest, *args, **opts)
1224
1224
1225 def flush(self):
1225 def flush(self):
1226 # opencode timeblockedsection because this is a critical path
1226 # opencode timeblockedsection because this is a critical path
1227 starttime = util.timer()
1227 starttime = util.timer()
1228 try:
1228 try:
1229 try:
1229 try:
1230 self._fout.flush()
1230 self._fout.flush()
1231 except IOError as err:
1231 except IOError as err:
1232 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1232 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1233 raise error.StdioError(err)
1233 raise error.StdioError(err)
1234 finally:
1234 finally:
1235 try:
1235 try:
1236 self._ferr.flush()
1236 self._ferr.flush()
1237 except IOError as err:
1237 except IOError as err:
1238 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1238 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1239 raise error.StdioError(err)
1239 raise error.StdioError(err)
1240 finally:
1240 finally:
1241 self._blockedtimes[b'stdio_blocked'] += (
1241 self._blockedtimes[b'stdio_blocked'] += (
1242 util.timer() - starttime
1242 util.timer() - starttime
1243 ) * 1000
1243 ) * 1000
1244
1244
1245 def _isatty(self, fh):
1245 def _isatty(self, fh):
1246 if self.configbool(b'ui', b'nontty'):
1246 if self.configbool(b'ui', b'nontty'):
1247 return False
1247 return False
1248 return procutil.isatty(fh)
1248 return procutil.isatty(fh)
1249
1249
1250 def protectfinout(self):
1250 def protectfinout(self):
1251 """Duplicate ui streams and redirect original if they are stdio
1251 """Duplicate ui streams and redirect original if they are stdio
1252
1252
1253 Returns (fin, fout) which point to the original ui fds, but may be
1253 Returns (fin, fout) which point to the original ui fds, but may be
1254 copy of them. The returned streams can be considered "owned" in that
1254 copy of them. The returned streams can be considered "owned" in that
1255 print(), exec(), etc. never reach to them.
1255 print(), exec(), etc. never reach to them.
1256 """
1256 """
1257 if self._finoutredirected:
1257 if self._finoutredirected:
1258 # if already redirected, protectstdio() would just create another
1258 # if already redirected, protectstdio() would just create another
1259 # nullfd pair, which is equivalent to returning self._fin/_fout.
1259 # nullfd pair, which is equivalent to returning self._fin/_fout.
1260 return self._fin, self._fout
1260 return self._fin, self._fout
1261 fin, fout = procutil.protectstdio(self._fin, self._fout)
1261 fin, fout = procutil.protectstdio(self._fin, self._fout)
1262 self._finoutredirected = (fin, fout) != (self._fin, self._fout)
1262 self._finoutredirected = (fin, fout) != (self._fin, self._fout)
1263 return fin, fout
1263 return fin, fout
1264
1264
1265 def restorefinout(self, fin, fout):
1265 def restorefinout(self, fin, fout):
1266 """Restore ui streams from possibly duplicated (fin, fout)"""
1266 """Restore ui streams from possibly duplicated (fin, fout)"""
1267 if (fin, fout) == (self._fin, self._fout):
1267 if (fin, fout) == (self._fin, self._fout):
1268 return
1268 return
1269 procutil.restorestdio(self._fin, self._fout, fin, fout)
1269 procutil.restorestdio(self._fin, self._fout, fin, fout)
1270 # protectfinout() won't create more than one duplicated streams,
1270 # protectfinout() won't create more than one duplicated streams,
1271 # so we can just turn the redirection flag off.
1271 # so we can just turn the redirection flag off.
1272 self._finoutredirected = False
1272 self._finoutredirected = False
1273
1273
1274 @contextlib.contextmanager
1274 @contextlib.contextmanager
1275 def protectedfinout(self):
1275 def protectedfinout(self):
1276 """Run code block with protected standard streams"""
1276 """Run code block with protected standard streams"""
1277 fin, fout = self.protectfinout()
1277 fin, fout = self.protectfinout()
1278 try:
1278 try:
1279 yield fin, fout
1279 yield fin, fout
1280 finally:
1280 finally:
1281 self.restorefinout(fin, fout)
1281 self.restorefinout(fin, fout)
1282
1282
1283 def disablepager(self):
1283 def disablepager(self):
1284 self._disablepager = True
1284 self._disablepager = True
1285
1285
1286 def pager(self, command):
1286 def pager(self, command):
1287 """Start a pager for subsequent command output.
1287 """Start a pager for subsequent command output.
1288
1288
1289 Commands which produce a long stream of output should call
1289 Commands which produce a long stream of output should call
1290 this function to activate the user's preferred pagination
1290 this function to activate the user's preferred pagination
1291 mechanism (which may be no pager). Calling this function
1291 mechanism (which may be no pager). Calling this function
1292 precludes any future use of interactive functionality, such as
1292 precludes any future use of interactive functionality, such as
1293 prompting the user or activating curses.
1293 prompting the user or activating curses.
1294
1294
1295 Args:
1295 Args:
1296 command: The full, non-aliased name of the command. That is, "log"
1296 command: The full, non-aliased name of the command. That is, "log"
1297 not "history, "summary" not "summ", etc.
1297 not "history, "summary" not "summ", etc.
1298 """
1298 """
1299 if self._disablepager or self.pageractive:
1299 if self._disablepager or self.pageractive:
1300 # how pager should do is already determined
1300 # how pager should do is already determined
1301 return
1301 return
1302
1302
1303 if not command.startswith(b'internal-always-') and (
1303 if not command.startswith(b'internal-always-') and (
1304 # explicit --pager=on (= 'internal-always-' prefix) should
1304 # explicit --pager=on (= 'internal-always-' prefix) should
1305 # take precedence over disabling factors below
1305 # take precedence over disabling factors below
1306 command in self.configlist(b'pager', b'ignore')
1306 command in self.configlist(b'pager', b'ignore')
1307 or not self.configbool(b'ui', b'paginate')
1307 or not self.configbool(b'ui', b'paginate')
1308 or not self.configbool(b'pager', b'attend-' + command, True)
1308 or not self.configbool(b'pager', b'attend-' + command, True)
1309 or encoding.environ.get(b'TERM') == b'dumb'
1309 or encoding.environ.get(b'TERM') == b'dumb'
1310 # TODO: if we want to allow HGPLAINEXCEPT=pager,
1310 # TODO: if we want to allow HGPLAINEXCEPT=pager,
1311 # formatted() will need some adjustment.
1311 # formatted() will need some adjustment.
1312 or not self.formatted()
1312 or not self.formatted()
1313 or self.plain()
1313 or self.plain()
1314 or self._buffers
1314 or self._buffers
1315 # TODO: expose debugger-enabled on the UI object
1315 # TODO: expose debugger-enabled on the UI object
1316 or b'--debugger' in pycompat.sysargv
1316 or b'--debugger' in pycompat.sysargv
1317 ):
1317 ):
1318 # We only want to paginate if the ui appears to be
1318 # We only want to paginate if the ui appears to be
1319 # interactive, the user didn't say HGPLAIN or
1319 # interactive, the user didn't say HGPLAIN or
1320 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
1320 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
1321 return
1321 return
1322
1322
1323 pagercmd = self.config(b'pager', b'pager', rcutil.fallbackpager)
1323 pagercmd = self.config(b'pager', b'pager', rcutil.fallbackpager)
1324 if not pagercmd:
1324 if not pagercmd:
1325 return
1325 return
1326
1326
1327 pagerenv = {}
1327 pagerenv = {}
1328 for name, value in rcutil.defaultpagerenv().items():
1328 for name, value in rcutil.defaultpagerenv().items():
1329 if name not in encoding.environ:
1329 if name not in encoding.environ:
1330 pagerenv[name] = value
1330 pagerenv[name] = value
1331
1331
1332 self.debug(
1332 self.debug(
1333 b'starting pager for command %s\n' % stringutil.pprint(command)
1333 b'starting pager for command %s\n' % stringutil.pprint(command)
1334 )
1334 )
1335 self.flush()
1335 self.flush()
1336
1336
1337 wasformatted = self.formatted()
1337 wasformatted = self.formatted()
1338 if util.safehasattr(signal, b"SIGPIPE"):
1338 if util.safehasattr(signal, b"SIGPIPE"):
1339 signal.signal(signal.SIGPIPE, _catchterm)
1339 signal.signal(signal.SIGPIPE, _catchterm)
1340 if self._runpager(pagercmd, pagerenv):
1340 if self._runpager(pagercmd, pagerenv):
1341 self.pageractive = True
1341 self.pageractive = True
1342 # Preserve the formatted-ness of the UI. This is important
1342 # Preserve the formatted-ness of the UI. This is important
1343 # because we mess with stdout, which might confuse
1343 # because we mess with stdout, which might confuse
1344 # auto-detection of things being formatted.
1344 # auto-detection of things being formatted.
1345 self.setconfig(b'ui', b'formatted', wasformatted, b'pager')
1345 self.setconfig(b'ui', b'formatted', wasformatted, b'pager')
1346 self.setconfig(b'ui', b'interactive', False, b'pager')
1346 self.setconfig(b'ui', b'interactive', False, b'pager')
1347
1347
1348 # If pagermode differs from color.mode, reconfigure color now that
1348 # If pagermode differs from color.mode, reconfigure color now that
1349 # pageractive is set.
1349 # pageractive is set.
1350 cm = self._colormode
1350 cm = self._colormode
1351 if cm != self.config(b'color', b'pagermode', cm):
1351 if cm != self.config(b'color', b'pagermode', cm):
1352 color.setup(self)
1352 color.setup(self)
1353 else:
1353 else:
1354 # If the pager can't be spawned in dispatch when --pager=on is
1354 # If the pager can't be spawned in dispatch when --pager=on is
1355 # given, don't try again when the command runs, to avoid a duplicate
1355 # given, don't try again when the command runs, to avoid a duplicate
1356 # warning about a missing pager command.
1356 # warning about a missing pager command.
1357 self.disablepager()
1357 self.disablepager()
1358
1358
1359 def _runpager(self, command, env=None):
1359 def _runpager(self, command, env=None):
1360 """Actually start the pager and set up file descriptors.
1360 """Actually start the pager and set up file descriptors.
1361
1361
1362 This is separate in part so that extensions (like chg) can
1362 This is separate in part so that extensions (like chg) can
1363 override how a pager is invoked.
1363 override how a pager is invoked.
1364 """
1364 """
1365 if command == b'cat':
1365 if command == b'cat':
1366 # Save ourselves some work.
1366 # Save ourselves some work.
1367 return False
1367 return False
1368 # If the command doesn't contain any of these characters, we
1368 # If the command doesn't contain any of these characters, we
1369 # assume it's a binary and exec it directly. This means for
1369 # assume it's a binary and exec it directly. This means for
1370 # simple pager command configurations, we can degrade
1370 # simple pager command configurations, we can degrade
1371 # gracefully and tell the user about their broken pager.
1371 # gracefully and tell the user about their broken pager.
1372 shell = any(c in command for c in b"|&;<>()$`\\\"' \t\n*?[#~=%")
1372 shell = any(c in command for c in b"|&;<>()$`\\\"' \t\n*?[#~=%")
1373
1373
1374 if pycompat.iswindows and not shell:
1374 if pycompat.iswindows and not shell:
1375 # Window's built-in `more` cannot be invoked with shell=False, but
1375 # Window's built-in `more` cannot be invoked with shell=False, but
1376 # its `more.com` can. Hide this implementation detail from the
1376 # its `more.com` can. Hide this implementation detail from the
1377 # user so we can also get sane bad PAGER behavior. MSYS has
1377 # user so we can also get sane bad PAGER behavior. MSYS has
1378 # `more.exe`, so do a cmd.exe style resolution of the executable to
1378 # `more.exe`, so do a cmd.exe style resolution of the executable to
1379 # determine which one to use.
1379 # determine which one to use.
1380 fullcmd = procutil.findexe(command)
1380 fullcmd = procutil.findexe(command)
1381 if not fullcmd:
1381 if not fullcmd:
1382 self.warn(
1382 self.warn(
1383 _(b"missing pager command '%s', skipping pager\n") % command
1383 _(b"missing pager command '%s', skipping pager\n") % command
1384 )
1384 )
1385 return False
1385 return False
1386
1386
1387 command = fullcmd
1387 command = fullcmd
1388
1388
1389 try:
1389 try:
1390 pager = subprocess.Popen(
1390 pager = subprocess.Popen(
1391 procutil.tonativestr(command),
1391 procutil.tonativestr(command),
1392 shell=shell,
1392 shell=shell,
1393 bufsize=-1,
1393 bufsize=-1,
1394 close_fds=procutil.closefds,
1394 close_fds=procutil.closefds,
1395 stdin=subprocess.PIPE,
1395 stdin=subprocess.PIPE,
1396 stdout=procutil.stdout,
1396 stdout=procutil.stdout,
1397 stderr=procutil.stderr,
1397 stderr=procutil.stderr,
1398 env=procutil.tonativeenv(procutil.shellenviron(env)),
1398 env=procutil.tonativeenv(procutil.shellenviron(env)),
1399 )
1399 )
1400 except OSError as e:
1400 except OSError as e:
1401 if e.errno == errno.ENOENT and not shell:
1401 if e.errno == errno.ENOENT and not shell:
1402 self.warn(
1402 self.warn(
1403 _(b"missing pager command '%s', skipping pager\n") % command
1403 _(b"missing pager command '%s', skipping pager\n") % command
1404 )
1404 )
1405 return False
1405 return False
1406 raise
1406 raise
1407
1407
1408 # back up original file descriptors
1408 # back up original file descriptors
1409 stdoutfd = os.dup(procutil.stdout.fileno())
1409 stdoutfd = os.dup(procutil.stdout.fileno())
1410 stderrfd = os.dup(procutil.stderr.fileno())
1410 stderrfd = os.dup(procutil.stderr.fileno())
1411
1411
1412 os.dup2(pager.stdin.fileno(), procutil.stdout.fileno())
1412 os.dup2(pager.stdin.fileno(), procutil.stdout.fileno())
1413 if self._isatty(procutil.stderr):
1413 if self._isatty(procutil.stderr):
1414 os.dup2(pager.stdin.fileno(), procutil.stderr.fileno())
1414 os.dup2(pager.stdin.fileno(), procutil.stderr.fileno())
1415
1415
1416 @self.atexit
1416 @self.atexit
1417 def killpager():
1417 def killpager():
1418 if util.safehasattr(signal, b"SIGINT"):
1418 if util.safehasattr(signal, b"SIGINT"):
1419 signal.signal(signal.SIGINT, signal.SIG_IGN)
1419 signal.signal(signal.SIGINT, signal.SIG_IGN)
1420 # restore original fds, closing pager.stdin copies in the process
1420 # restore original fds, closing pager.stdin copies in the process
1421 os.dup2(stdoutfd, procutil.stdout.fileno())
1421 os.dup2(stdoutfd, procutil.stdout.fileno())
1422 os.dup2(stderrfd, procutil.stderr.fileno())
1422 os.dup2(stderrfd, procutil.stderr.fileno())
1423 pager.stdin.close()
1423 pager.stdin.close()
1424 pager.wait()
1424 pager.wait()
1425
1425
1426 return True
1426 return True
1427
1427
1428 @property
1428 @property
1429 def _exithandlers(self):
1429 def _exithandlers(self):
1430 return _reqexithandlers
1430 return _reqexithandlers
1431
1431
1432 def atexit(self, func, *args, **kwargs):
1432 def atexit(self, func, *args, **kwargs):
1433 '''register a function to run after dispatching a request
1433 '''register a function to run after dispatching a request
1434
1434
1435 Handlers do not stay registered across request boundaries.'''
1435 Handlers do not stay registered across request boundaries.'''
1436 self._exithandlers.append((func, args, kwargs))
1436 self._exithandlers.append((func, args, kwargs))
1437 return func
1437 return func
1438
1438
1439 def interface(self, feature):
1439 def interface(self, feature):
1440 """what interface to use for interactive console features?
1440 """what interface to use for interactive console features?
1441
1441
1442 The interface is controlled by the value of `ui.interface` but also by
1442 The interface is controlled by the value of `ui.interface` but also by
1443 the value of feature-specific configuration. For example:
1443 the value of feature-specific configuration. For example:
1444
1444
1445 ui.interface.histedit = text
1445 ui.interface.histedit = text
1446 ui.interface.chunkselector = curses
1446 ui.interface.chunkselector = curses
1447
1447
1448 Here the features are "histedit" and "chunkselector".
1448 Here the features are "histedit" and "chunkselector".
1449
1449
1450 The configuration above means that the default interfaces for commands
1450 The configuration above means that the default interfaces for commands
1451 is curses, the interface for histedit is text and the interface for
1451 is curses, the interface for histedit is text and the interface for
1452 selecting chunk is crecord (the best curses interface available).
1452 selecting chunk is crecord (the best curses interface available).
1453
1453
1454 Consider the following example:
1454 Consider the following example:
1455 ui.interface = curses
1455 ui.interface = curses
1456 ui.interface.histedit = text
1456 ui.interface.histedit = text
1457
1457
1458 Then histedit will use the text interface and chunkselector will use
1458 Then histedit will use the text interface and chunkselector will use
1459 the default curses interface (crecord at the moment).
1459 the default curses interface (crecord at the moment).
1460 """
1460 """
1461 alldefaults = frozenset([b"text", b"curses"])
1461 alldefaults = frozenset([b"text", b"curses"])
1462
1462
1463 featureinterfaces = {
1463 featureinterfaces = {
1464 b"chunkselector": [b"text", b"curses",],
1464 b"chunkselector": [b"text", b"curses",],
1465 b"histedit": [b"text", b"curses",],
1465 b"histedit": [b"text", b"curses",],
1466 }
1466 }
1467
1467
1468 # Feature-specific interface
1468 # Feature-specific interface
1469 if feature not in featureinterfaces.keys():
1469 if feature not in featureinterfaces.keys():
1470 # Programming error, not user error
1470 # Programming error, not user error
1471 raise ValueError(b"Unknown feature requested %s" % feature)
1471 raise ValueError(b"Unknown feature requested %s" % feature)
1472
1472
1473 availableinterfaces = frozenset(featureinterfaces[feature])
1473 availableinterfaces = frozenset(featureinterfaces[feature])
1474 if alldefaults > availableinterfaces:
1474 if alldefaults > availableinterfaces:
1475 # Programming error, not user error. We need a use case to
1475 # Programming error, not user error. We need a use case to
1476 # define the right thing to do here.
1476 # define the right thing to do here.
1477 raise ValueError(
1477 raise ValueError(
1478 b"Feature %s does not handle all default interfaces" % feature
1478 b"Feature %s does not handle all default interfaces" % feature
1479 )
1479 )
1480
1480
1481 if self.plain() or encoding.environ.get(b'TERM') == b'dumb':
1481 if self.plain() or encoding.environ.get(b'TERM') == b'dumb':
1482 return b"text"
1482 return b"text"
1483
1483
1484 # Default interface for all the features
1484 # Default interface for all the features
1485 defaultinterface = b"text"
1485 defaultinterface = b"text"
1486 i = self.config(b"ui", b"interface")
1486 i = self.config(b"ui", b"interface")
1487 if i in alldefaults:
1487 if i in alldefaults:
1488 defaultinterface = i
1488 defaultinterface = i
1489
1489
1490 choseninterface = defaultinterface
1490 choseninterface = defaultinterface
1491 f = self.config(b"ui", b"interface.%s" % feature)
1491 f = self.config(b"ui", b"interface.%s" % feature)
1492 if f in availableinterfaces:
1492 if f in availableinterfaces:
1493 choseninterface = f
1493 choseninterface = f
1494
1494
1495 if i is not None and defaultinterface != i:
1495 if i is not None and defaultinterface != i:
1496 if f is not None:
1496 if f is not None:
1497 self.warn(_(b"invalid value for ui.interface: %s\n") % (i,))
1497 self.warn(_(b"invalid value for ui.interface: %s\n") % (i,))
1498 else:
1498 else:
1499 self.warn(
1499 self.warn(
1500 _(b"invalid value for ui.interface: %s (using %s)\n")
1500 _(b"invalid value for ui.interface: %s (using %s)\n")
1501 % (i, choseninterface)
1501 % (i, choseninterface)
1502 )
1502 )
1503 if f is not None and choseninterface != f:
1503 if f is not None and choseninterface != f:
1504 self.warn(
1504 self.warn(
1505 _(b"invalid value for ui.interface.%s: %s (using %s)\n")
1505 _(b"invalid value for ui.interface.%s: %s (using %s)\n")
1506 % (feature, f, choseninterface)
1506 % (feature, f, choseninterface)
1507 )
1507 )
1508
1508
1509 return choseninterface
1509 return choseninterface
1510
1510
1511 def interactive(self):
1511 def interactive(self):
1512 '''is interactive input allowed?
1512 '''is interactive input allowed?
1513
1513
1514 An interactive session is a session where input can be reasonably read
1514 An interactive session is a session where input can be reasonably read
1515 from `sys.stdin'. If this function returns false, any attempt to read
1515 from `sys.stdin'. If this function returns false, any attempt to read
1516 from stdin should fail with an error, unless a sensible default has been
1516 from stdin should fail with an error, unless a sensible default has been
1517 specified.
1517 specified.
1518
1518
1519 Interactiveness is triggered by the value of the `ui.interactive'
1519 Interactiveness is triggered by the value of the `ui.interactive'
1520 configuration variable or - if it is unset - when `sys.stdin' points
1520 configuration variable or - if it is unset - when `sys.stdin' points
1521 to a terminal device.
1521 to a terminal device.
1522
1522
1523 This function refers to input only; for output, see `ui.formatted()'.
1523 This function refers to input only; for output, see `ui.formatted()'.
1524 '''
1524 '''
1525 i = self.configbool(b"ui", b"interactive")
1525 i = self.configbool(b"ui", b"interactive")
1526 if i is None:
1526 if i is None:
1527 # some environments replace stdin without implementing isatty
1527 # some environments replace stdin without implementing isatty
1528 # usually those are non-interactive
1528 # usually those are non-interactive
1529 return self._isatty(self._fin)
1529 return self._isatty(self._fin)
1530
1530
1531 return i
1531 return i
1532
1532
1533 def termwidth(self):
1533 def termwidth(self):
1534 '''how wide is the terminal in columns?
1534 '''how wide is the terminal in columns?
1535 '''
1535 '''
1536 if b'COLUMNS' in encoding.environ:
1536 if b'COLUMNS' in encoding.environ:
1537 try:
1537 try:
1538 return int(encoding.environ[b'COLUMNS'])
1538 return int(encoding.environ[b'COLUMNS'])
1539 except ValueError:
1539 except ValueError:
1540 pass
1540 pass
1541 return scmutil.termsize(self)[0]
1541 return scmutil.termsize(self)[0]
1542
1542
1543 def formatted(self):
1543 def formatted(self):
1544 '''should formatted output be used?
1544 '''should formatted output be used?
1545
1545
1546 It is often desirable to format the output to suite the output medium.
1546 It is often desirable to format the output to suite the output medium.
1547 Examples of this are truncating long lines or colorizing messages.
1547 Examples of this are truncating long lines or colorizing messages.
1548 However, this is not often not desirable when piping output into other
1548 However, this is not often not desirable when piping output into other
1549 utilities, e.g. `grep'.
1549 utilities, e.g. `grep'.
1550
1550
1551 Formatted output is triggered by the value of the `ui.formatted'
1551 Formatted output is triggered by the value of the `ui.formatted'
1552 configuration variable or - if it is unset - when `sys.stdout' points
1552 configuration variable or - if it is unset - when `sys.stdout' points
1553 to a terminal device. Please note that `ui.formatted' should be
1553 to a terminal device. Please note that `ui.formatted' should be
1554 considered an implementation detail; it is not intended for use outside
1554 considered an implementation detail; it is not intended for use outside
1555 Mercurial or its extensions.
1555 Mercurial or its extensions.
1556
1556
1557 This function refers to output only; for input, see `ui.interactive()'.
1557 This function refers to output only; for input, see `ui.interactive()'.
1558 This function always returns false when in plain mode, see `ui.plain()'.
1558 This function always returns false when in plain mode, see `ui.plain()'.
1559 '''
1559 '''
1560 if self.plain():
1560 if self.plain():
1561 return False
1561 return False
1562
1562
1563 i = self.configbool(b"ui", b"formatted")
1563 i = self.configbool(b"ui", b"formatted")
1564 if i is None:
1564 if i is None:
1565 # some environments replace stdout without implementing isatty
1565 # some environments replace stdout without implementing isatty
1566 # usually those are non-interactive
1566 # usually those are non-interactive
1567 return self._isatty(self._fout)
1567 return self._isatty(self._fout)
1568
1568
1569 return i
1569 return i
1570
1570
1571 def _readline(self, prompt=b' ', promptopts=None):
1571 def _readline(self, prompt=b' ', promptopts=None):
1572 # Replacing stdin/stdout temporarily is a hard problem on Python 3
1572 # Replacing stdin/stdout temporarily is a hard problem on Python 3
1573 # because they have to be text streams with *no buffering*. Instead,
1573 # because they have to be text streams with *no buffering*. Instead,
1574 # we use rawinput() only if call_readline() will be invoked by
1574 # we use rawinput() only if call_readline() will be invoked by
1575 # PyOS_Readline(), so no I/O will be made at Python layer.
1575 # PyOS_Readline(), so no I/O will be made at Python layer.
1576 usereadline = (
1576 usereadline = (
1577 self._isatty(self._fin)
1577 self._isatty(self._fin)
1578 and self._isatty(self._fout)
1578 and self._isatty(self._fout)
1579 and procutil.isstdin(self._fin)
1579 and procutil.isstdin(self._fin)
1580 and procutil.isstdout(self._fout)
1580 and procutil.isstdout(self._fout)
1581 )
1581 )
1582 if usereadline:
1582 if usereadline:
1583 try:
1583 try:
1584 # magically add command line editing support, where
1584 # magically add command line editing support, where
1585 # available
1585 # available
1586 import readline
1586 import readline
1587
1587
1588 # force demandimport to really load the module
1588 # force demandimport to really load the module
1589 readline.read_history_file
1589 readline.read_history_file
1590 # windows sometimes raises something other than ImportError
1590 # windows sometimes raises something other than ImportError
1591 except Exception:
1591 except Exception:
1592 usereadline = False
1592 usereadline = False
1593
1593
1594 if self._colormode == b'win32' or not usereadline:
1594 if self._colormode == b'win32' or not usereadline:
1595 if not promptopts:
1595 if not promptopts:
1596 promptopts = {}
1596 promptopts = {}
1597 self._writemsgnobuf(
1597 self._writemsgnobuf(
1598 self._fmsgout, prompt, type=b'prompt', **promptopts
1598 self._fmsgout, prompt, type=b'prompt', **promptopts
1599 )
1599 )
1600 self.flush()
1600 self.flush()
1601 prompt = b' '
1601 prompt = b' '
1602 else:
1602 else:
1603 prompt = self.label(prompt, b'ui.prompt') + b' '
1603 prompt = self.label(prompt, b'ui.prompt') + b' '
1604
1604
1605 # prompt ' ' must exist; otherwise readline may delete entire line
1605 # prompt ' ' must exist; otherwise readline may delete entire line
1606 # - http://bugs.python.org/issue12833
1606 # - http://bugs.python.org/issue12833
1607 with self.timeblockedsection(b'stdio'):
1607 with self.timeblockedsection(b'stdio'):
1608 if usereadline:
1608 if usereadline:
1609 self.flush()
1609 self.flush()
1610 prompt = encoding.strfromlocal(prompt)
1610 prompt = encoding.strfromlocal(prompt)
1611 line = encoding.strtolocal(pycompat.rawinput(prompt))
1611 line = encoding.strtolocal(pycompat.rawinput(prompt))
1612 # When stdin is in binary mode on Windows, it can cause
1612 # When stdin is in binary mode on Windows, it can cause
1613 # raw_input() to emit an extra trailing carriage return
1613 # raw_input() to emit an extra trailing carriage return
1614 if pycompat.oslinesep == b'\r\n' and line.endswith(b'\r'):
1614 if pycompat.oslinesep == b'\r\n' and line.endswith(b'\r'):
1615 line = line[:-1]
1615 line = line[:-1]
1616 else:
1616 else:
1617 self._fout.write(pycompat.bytestr(prompt))
1617 self._fout.write(pycompat.bytestr(prompt))
1618 self._fout.flush()
1618 self._fout.flush()
1619 line = self._fin.readline()
1619 line = self._fin.readline()
1620 if not line:
1620 if not line:
1621 raise EOFError
1621 raise EOFError
1622 line = line.rstrip(pycompat.oslinesep)
1622 line = line.rstrip(pycompat.oslinesep)
1623
1623
1624 return line
1624 return line
1625
1625
1626 def prompt(self, msg, default=b"y"):
1626 def prompt(self, msg, default=b"y"):
1627 """Prompt user with msg, read response.
1627 """Prompt user with msg, read response.
1628 If ui is not interactive, the default is returned.
1628 If ui is not interactive, the default is returned.
1629 """
1629 """
1630 return self._prompt(msg, default=default)
1630 return self._prompt(msg, default=default)
1631
1631
1632 def _prompt(self, msg, **opts):
1632 def _prompt(self, msg, **opts):
1633 default = opts['default']
1633 default = opts['default']
1634 if not self.interactive():
1634 if not self.interactive():
1635 self._writemsg(self._fmsgout, msg, b' ', type=b'prompt', **opts)
1635 self._writemsg(self._fmsgout, msg, b' ', type=b'prompt', **opts)
1636 self._writemsg(
1636 self._writemsg(
1637 self._fmsgout, default or b'', b"\n", type=b'promptecho'
1637 self._fmsgout, default or b'', b"\n", type=b'promptecho'
1638 )
1638 )
1639 return default
1639 return default
1640 try:
1640 try:
1641 r = self._readline(prompt=msg, promptopts=opts)
1641 r = self._readline(prompt=msg, promptopts=opts)
1642 if not r:
1642 if not r:
1643 r = default
1643 r = default
1644 if self.configbool(b'ui', b'promptecho'):
1644 if self.configbool(b'ui', b'promptecho'):
1645 self._writemsg(self._fmsgout, r, b"\n", type=b'promptecho')
1645 self._writemsg(self._fmsgout, r, b"\n", type=b'promptecho')
1646 return r
1646 return r
1647 except EOFError:
1647 except EOFError:
1648 raise error.ResponseExpected()
1648 raise error.ResponseExpected()
1649
1649
1650 @staticmethod
1650 @staticmethod
1651 def extractchoices(prompt):
1651 def extractchoices(prompt):
1652 """Extract prompt message and list of choices from specified prompt.
1652 """Extract prompt message and list of choices from specified prompt.
1653
1653
1654 This returns tuple "(message, choices)", and "choices" is the
1654 This returns tuple "(message, choices)", and "choices" is the
1655 list of tuple "(response character, text without &)".
1655 list of tuple "(response character, text without &)".
1656
1656
1657 >>> ui.extractchoices(b"awake? $$ &Yes $$ &No")
1657 >>> ui.extractchoices(b"awake? $$ &Yes $$ &No")
1658 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1658 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1659 >>> ui.extractchoices(b"line\\nbreak? $$ &Yes $$ &No")
1659 >>> ui.extractchoices(b"line\\nbreak? $$ &Yes $$ &No")
1660 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1660 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1661 >>> ui.extractchoices(b"want lots of $$money$$?$$Ye&s$$N&o")
1661 >>> ui.extractchoices(b"want lots of $$money$$?$$Ye&s$$N&o")
1662 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1662 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1663 """
1663 """
1664
1664
1665 # Sadly, the prompt string may have been built with a filename
1665 # Sadly, the prompt string may have been built with a filename
1666 # containing "$$" so let's try to find the first valid-looking
1666 # containing "$$" so let's try to find the first valid-looking
1667 # prompt to start parsing. Sadly, we also can't rely on
1667 # prompt to start parsing. Sadly, we also can't rely on
1668 # choices containing spaces, ASCII, or basically anything
1668 # choices containing spaces, ASCII, or basically anything
1669 # except an ampersand followed by a character.
1669 # except an ampersand followed by a character.
1670 m = re.match(br'(?s)(.+?)\$\$([^$]*&[^ $].*)', prompt)
1670 m = re.match(br'(?s)(.+?)\$\$([^$]*&[^ $].*)', prompt)
1671 msg = m.group(1)
1671 msg = m.group(1)
1672 choices = [p.strip(b' ') for p in m.group(2).split(b'$$')]
1672 choices = [p.strip(b' ') for p in m.group(2).split(b'$$')]
1673
1673
1674 def choicetuple(s):
1674 def choicetuple(s):
1675 ampidx = s.index(b'&')
1675 ampidx = s.index(b'&')
1676 return s[ampidx + 1 : ampidx + 2].lower(), s.replace(b'&', b'', 1)
1676 return s[ampidx + 1 : ampidx + 2].lower(), s.replace(b'&', b'', 1)
1677
1677
1678 return (msg, [choicetuple(s) for s in choices])
1678 return (msg, [choicetuple(s) for s in choices])
1679
1679
1680 def promptchoice(self, prompt, default=0):
1680 def promptchoice(self, prompt, default=0):
1681 """Prompt user with a message, read response, and ensure it matches
1681 """Prompt user with a message, read response, and ensure it matches
1682 one of the provided choices. The prompt is formatted as follows:
1682 one of the provided choices. The prompt is formatted as follows:
1683
1683
1684 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1684 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1685
1685
1686 The index of the choice is returned. Responses are case
1686 The index of the choice is returned. Responses are case
1687 insensitive. If ui is not interactive, the default is
1687 insensitive. If ui is not interactive, the default is
1688 returned.
1688 returned.
1689 """
1689 """
1690
1690
1691 msg, choices = self.extractchoices(prompt)
1691 msg, choices = self.extractchoices(prompt)
1692 resps = [r for r, t in choices]
1692 resps = [r for r, t in choices]
1693 while True:
1693 while True:
1694 r = self._prompt(msg, default=resps[default], choices=choices)
1694 r = self._prompt(msg, default=resps[default], choices=choices)
1695 if r.lower() in resps:
1695 if r.lower() in resps:
1696 return resps.index(r.lower())
1696 return resps.index(r.lower())
1697 # TODO: shouldn't it be a warning?
1697 # TODO: shouldn't it be a warning?
1698 self._writemsg(self._fmsgout, _(b"unrecognized response\n"))
1698 self._writemsg(self._fmsgout, _(b"unrecognized response\n"))
1699
1699
1700 def getpass(self, prompt=None, default=None):
1700 def getpass(self, prompt=None, default=None):
1701 if not self.interactive():
1701 if not self.interactive():
1702 return default
1702 return default
1703 try:
1703 try:
1704 self._writemsg(
1704 self._writemsg(
1705 self._fmsgerr,
1705 self._fmsgerr,
1706 prompt or _(b'password: '),
1706 prompt or _(b'password: '),
1707 type=b'prompt',
1707 type=b'prompt',
1708 password=True,
1708 password=True,
1709 )
1709 )
1710 # disable getpass() only if explicitly specified. it's still valid
1710 # disable getpass() only if explicitly specified. it's still valid
1711 # to interact with tty even if fin is not a tty.
1711 # to interact with tty even if fin is not a tty.
1712 with self.timeblockedsection(b'stdio'):
1712 with self.timeblockedsection(b'stdio'):
1713 if self.configbool(b'ui', b'nontty'):
1713 if self.configbool(b'ui', b'nontty'):
1714 l = self._fin.readline()
1714 l = self._fin.readline()
1715 if not l:
1715 if not l:
1716 raise EOFError
1716 raise EOFError
1717 return l.rstrip(b'\n')
1717 return l.rstrip(b'\n')
1718 else:
1718 else:
1719 return getpass.getpass('')
1719 return getpass.getpass('')
1720 except EOFError:
1720 except EOFError:
1721 raise error.ResponseExpected()
1721 raise error.ResponseExpected()
1722
1722
1723 def status(self, *msg, **opts):
1723 def status(self, *msg, **opts):
1724 '''write status message to output (if ui.quiet is False)
1724 '''write status message to output (if ui.quiet is False)
1725
1725
1726 This adds an output label of "ui.status".
1726 This adds an output label of "ui.status".
1727 '''
1727 '''
1728 if not self.quiet:
1728 if not self.quiet:
1729 self._writemsg(self._fmsgout, type=b'status', *msg, **opts)
1729 self._writemsg(self._fmsgout, type=b'status', *msg, **opts)
1730
1730
1731 def warn(self, *msg, **opts):
1731 def warn(self, *msg, **opts):
1732 '''write warning message to output (stderr)
1732 '''write warning message to output (stderr)
1733
1733
1734 This adds an output label of "ui.warning".
1734 This adds an output label of "ui.warning".
1735 '''
1735 '''
1736 self._writemsg(self._fmsgerr, type=b'warning', *msg, **opts)
1736 self._writemsg(self._fmsgerr, type=b'warning', *msg, **opts)
1737
1737
1738 def error(self, *msg, **opts):
1738 def error(self, *msg, **opts):
1739 '''write error message to output (stderr)
1739 '''write error message to output (stderr)
1740
1740
1741 This adds an output label of "ui.error".
1741 This adds an output label of "ui.error".
1742 '''
1742 '''
1743 self._writemsg(self._fmsgerr, type=b'error', *msg, **opts)
1743 self._writemsg(self._fmsgerr, type=b'error', *msg, **opts)
1744
1744
1745 def note(self, *msg, **opts):
1745 def note(self, *msg, **opts):
1746 '''write note to output (if ui.verbose is True)
1746 '''write note to output (if ui.verbose is True)
1747
1747
1748 This adds an output label of "ui.note".
1748 This adds an output label of "ui.note".
1749 '''
1749 '''
1750 if self.verbose:
1750 if self.verbose:
1751 self._writemsg(self._fmsgout, type=b'note', *msg, **opts)
1751 self._writemsg(self._fmsgout, type=b'note', *msg, **opts)
1752
1752
1753 def debug(self, *msg, **opts):
1753 def debug(self, *msg, **opts):
1754 '''write debug message to output (if ui.debugflag is True)
1754 '''write debug message to output (if ui.debugflag is True)
1755
1755
1756 This adds an output label of "ui.debug".
1756 This adds an output label of "ui.debug".
1757 '''
1757 '''
1758 if self.debugflag:
1758 if self.debugflag:
1759 self._writemsg(self._fmsgout, type=b'debug', *msg, **opts)
1759 self._writemsg(self._fmsgout, type=b'debug', *msg, **opts)
1760 self.log(b'debug', b'%s', b''.join(msg))
1760 self.log(b'debug', b'%s', b''.join(msg))
1761
1761
1762 # Aliases to defeat check-code.
1762 # Aliases to defeat check-code.
1763 statusnoi18n = status
1763 statusnoi18n = status
1764 notenoi18n = note
1764 notenoi18n = note
1765 warnnoi18n = warn
1765 warnnoi18n = warn
1766 writenoi18n = write
1766 writenoi18n = write
1767
1767
1768 def edit(
1768 def edit(
1769 self,
1769 self,
1770 text,
1770 text,
1771 user,
1771 user,
1772 extra=None,
1772 extra=None,
1773 editform=None,
1773 editform=None,
1774 pending=None,
1774 pending=None,
1775 repopath=None,
1775 repopath=None,
1776 action=None,
1776 action=None,
1777 ):
1777 ):
1778 if action is None:
1778 if action is None:
1779 self.develwarn(
1779 self.develwarn(
1780 b'action is None but will soon be a required '
1780 b'action is None but will soon be a required '
1781 b'parameter to ui.edit()'
1781 b'parameter to ui.edit()'
1782 )
1782 )
1783 extra_defaults = {
1783 extra_defaults = {
1784 b'prefix': b'editor',
1784 b'prefix': b'editor',
1785 b'suffix': b'.txt',
1785 b'suffix': b'.txt',
1786 }
1786 }
1787 if extra is not None:
1787 if extra is not None:
1788 if extra.get(b'suffix') is not None:
1788 if extra.get(b'suffix') is not None:
1789 self.develwarn(
1789 self.develwarn(
1790 b'extra.suffix is not None but will soon be '
1790 b'extra.suffix is not None but will soon be '
1791 b'ignored by ui.edit()'
1791 b'ignored by ui.edit()'
1792 )
1792 )
1793 extra_defaults.update(extra)
1793 extra_defaults.update(extra)
1794 extra = extra_defaults
1794 extra = extra_defaults
1795
1795
1796 if action == b'diff':
1796 if action == b'diff':
1797 suffix = b'.diff'
1797 suffix = b'.diff'
1798 elif action:
1798 elif action:
1799 suffix = b'.%s.hg.txt' % action
1799 suffix = b'.%s.hg.txt' % action
1800 else:
1800 else:
1801 suffix = extra[b'suffix']
1801 suffix = extra[b'suffix']
1802
1802
1803 rdir = None
1803 rdir = None
1804 if self.configbool(b'experimental', b'editortmpinhg'):
1804 if self.configbool(b'experimental', b'editortmpinhg'):
1805 rdir = repopath
1805 rdir = repopath
1806 (fd, name) = pycompat.mkstemp(
1806 (fd, name) = pycompat.mkstemp(
1807 prefix=b'hg-' + extra[b'prefix'] + b'-', suffix=suffix, dir=rdir
1807 prefix=b'hg-' + extra[b'prefix'] + b'-', suffix=suffix, dir=rdir
1808 )
1808 )
1809 try:
1809 try:
1810 with os.fdopen(fd, 'wb') as f:
1810 with os.fdopen(fd, 'wb') as f:
1811 f.write(util.tonativeeol(text))
1811 f.write(util.tonativeeol(text))
1812
1812
1813 environ = {b'HGUSER': user}
1813 environ = {b'HGUSER': user}
1814 if b'transplant_source' in extra:
1814 if b'transplant_source' in extra:
1815 environ.update(
1815 environ.update(
1816 {b'HGREVISION': hex(extra[b'transplant_source'])}
1816 {b'HGREVISION': hex(extra[b'transplant_source'])}
1817 )
1817 )
1818 for label in (b'intermediate-source', b'source', b'rebase_source'):
1818 for label in (b'intermediate-source', b'source', b'rebase_source'):
1819 if label in extra:
1819 if label in extra:
1820 environ.update({b'HGREVISION': extra[label]})
1820 environ.update({b'HGREVISION': extra[label]})
1821 break
1821 break
1822 if editform:
1822 if editform:
1823 environ.update({b'HGEDITFORM': editform})
1823 environ.update({b'HGEDITFORM': editform})
1824 if pending:
1824 if pending:
1825 environ.update({b'HG_PENDING': pending})
1825 environ.update({b'HG_PENDING': pending})
1826
1826
1827 editor = self.geteditor()
1827 editor = self.geteditor()
1828
1828
1829 self.system(
1829 self.system(
1830 b"%s \"%s\"" % (editor, name),
1830 b"%s \"%s\"" % (editor, name),
1831 environ=environ,
1831 environ=environ,
1832 onerr=error.Abort,
1832 onerr=error.Abort,
1833 errprefix=_(b"edit failed"),
1833 errprefix=_(b"edit failed"),
1834 blockedtag=b'editor',
1834 blockedtag=b'editor',
1835 )
1835 )
1836
1836
1837 with open(name, 'rb') as f:
1837 with open(name, 'rb') as f:
1838 t = util.fromnativeeol(f.read())
1838 t = util.fromnativeeol(f.read())
1839 finally:
1839 finally:
1840 os.unlink(name)
1840 os.unlink(name)
1841
1841
1842 return t
1842 return t
1843
1843
1844 def system(
1844 def system(
1845 self,
1845 self,
1846 cmd,
1846 cmd,
1847 environ=None,
1847 environ=None,
1848 cwd=None,
1848 cwd=None,
1849 onerr=None,
1849 onerr=None,
1850 errprefix=None,
1850 errprefix=None,
1851 blockedtag=None,
1851 blockedtag=None,
1852 ):
1852 ):
1853 '''execute shell command with appropriate output stream. command
1853 '''execute shell command with appropriate output stream. command
1854 output will be redirected if fout is not stdout.
1854 output will be redirected if fout is not stdout.
1855
1855
1856 if command fails and onerr is None, return status, else raise onerr
1856 if command fails and onerr is None, return status, else raise onerr
1857 object as exception.
1857 object as exception.
1858 '''
1858 '''
1859 if blockedtag is None:
1859 if blockedtag is None:
1860 # Long cmds tend to be because of an absolute path on cmd. Keep
1860 # Long cmds tend to be because of an absolute path on cmd. Keep
1861 # the tail end instead
1861 # the tail end instead
1862 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1862 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1863 blockedtag = b'unknown_system_' + cmdsuffix
1863 blockedtag = b'unknown_system_' + cmdsuffix
1864 out = self._fout
1864 out = self._fout
1865 if any(s[1] for s in self._bufferstates):
1865 if any(s[1] for s in self._bufferstates):
1866 out = self
1866 out = self
1867 with self.timeblockedsection(blockedtag):
1867 with self.timeblockedsection(blockedtag):
1868 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1868 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1869 if rc and onerr:
1869 if rc and onerr:
1870 errmsg = b'%s %s' % (
1870 errmsg = b'%s %s' % (
1871 procutil.shellsplit(cmd)[0],
1871 procutil.shellsplit(cmd)[0],
1872 procutil.explainexit(rc),
1872 procutil.explainexit(rc),
1873 )
1873 )
1874 if errprefix:
1874 if errprefix:
1875 errmsg = b'%s: %s' % (errprefix, errmsg)
1875 errmsg = b'%s: %s' % (errprefix, errmsg)
1876 raise onerr(errmsg)
1876 raise onerr(errmsg)
1877 return rc
1877 return rc
1878
1878
1879 def _runsystem(self, cmd, environ, cwd, out):
1879 def _runsystem(self, cmd, environ, cwd, out):
1880 """actually execute the given shell command (can be overridden by
1880 """actually execute the given shell command (can be overridden by
1881 extensions like chg)"""
1881 extensions like chg)"""
1882 return procutil.system(cmd, environ=environ, cwd=cwd, out=out)
1882 return procutil.system(cmd, environ=environ, cwd=cwd, out=out)
1883
1883
1884 def traceback(self, exc=None, force=False):
1884 def traceback(self, exc=None, force=False):
1885 '''print exception traceback if traceback printing enabled or forced.
1885 '''print exception traceback if traceback printing enabled or forced.
1886 only to call in exception handler. returns true if traceback
1886 only to call in exception handler. returns true if traceback
1887 printed.'''
1887 printed.'''
1888 if self.tracebackflag or force:
1888 if self.tracebackflag or force:
1889 if exc is None:
1889 if exc is None:
1890 exc = sys.exc_info()
1890 exc = sys.exc_info()
1891 cause = getattr(exc[1], 'cause', None)
1891 cause = getattr(exc[1], 'cause', None)
1892
1892
1893 if cause is not None:
1893 if cause is not None:
1894 causetb = traceback.format_tb(cause[2])
1894 causetb = traceback.format_tb(cause[2])
1895 exctb = traceback.format_tb(exc[2])
1895 exctb = traceback.format_tb(exc[2])
1896 exconly = traceback.format_exception_only(cause[0], cause[1])
1896 exconly = traceback.format_exception_only(cause[0], cause[1])
1897
1897
1898 # exclude frame where 'exc' was chained and rethrown from exctb
1898 # exclude frame where 'exc' was chained and rethrown from exctb
1899 self.write_err(
1899 self.write_err(
1900 b'Traceback (most recent call last):\n',
1900 b'Traceback (most recent call last):\n',
1901 encoding.strtolocal(''.join(exctb[:-1])),
1901 encoding.strtolocal(''.join(exctb[:-1])),
1902 encoding.strtolocal(''.join(causetb)),
1902 encoding.strtolocal(''.join(causetb)),
1903 encoding.strtolocal(''.join(exconly)),
1903 encoding.strtolocal(''.join(exconly)),
1904 )
1904 )
1905 else:
1905 else:
1906 output = traceback.format_exception(exc[0], exc[1], exc[2])
1906 output = traceback.format_exception(exc[0], exc[1], exc[2])
1907 self.write_err(encoding.strtolocal(''.join(output)))
1907 self.write_err(encoding.strtolocal(''.join(output)))
1908 return self.tracebackflag or force
1908 return self.tracebackflag or force
1909
1909
1910 def geteditor(self):
1910 def geteditor(self):
1911 '''return editor to use'''
1911 '''return editor to use'''
1912 if pycompat.sysplatform == b'plan9':
1912 if pycompat.sysplatform == b'plan9':
1913 # vi is the MIPS instruction simulator on Plan 9. We
1913 # vi is the MIPS instruction simulator on Plan 9. We
1914 # instead default to E to plumb commit messages to
1914 # instead default to E to plumb commit messages to
1915 # avoid confusion.
1915 # avoid confusion.
1916 editor = b'E'
1916 editor = b'E'
1917 elif pycompat.isdarwin:
1918 # vi on darwin is POSIX compatible to a fault, and that includes
1919 # exiting non-zero if you make any mistake when running an ex
1920 # command. Proof: `vi -c ':unknown' -c ':qa'; echo $?` produces 1,
1921 # while s/vi/vim/ doesn't.
1922 editor = b'vim'
1917 else:
1923 else:
1918 editor = b'vi'
1924 editor = b'vi'
1919 return encoding.environ.get(b"HGEDITOR") or self.config(
1925 return encoding.environ.get(b"HGEDITOR") or self.config(
1920 b"ui", b"editor", editor
1926 b"ui", b"editor", editor
1921 )
1927 )
1922
1928
1923 @util.propertycache
1929 @util.propertycache
1924 def _progbar(self):
1930 def _progbar(self):
1925 """setup the progbar singleton to the ui object"""
1931 """setup the progbar singleton to the ui object"""
1926 if (
1932 if (
1927 self.quiet
1933 self.quiet
1928 or self.debugflag
1934 or self.debugflag
1929 or self.configbool(b'progress', b'disable')
1935 or self.configbool(b'progress', b'disable')
1930 or not progress.shouldprint(self)
1936 or not progress.shouldprint(self)
1931 ):
1937 ):
1932 return None
1938 return None
1933 return getprogbar(self)
1939 return getprogbar(self)
1934
1940
1935 def _progclear(self):
1941 def _progclear(self):
1936 """clear progress bar output if any. use it before any output"""
1942 """clear progress bar output if any. use it before any output"""
1937 if not haveprogbar(): # nothing loaded yet
1943 if not haveprogbar(): # nothing loaded yet
1938 return
1944 return
1939 if self._progbar is not None and self._progbar.printed:
1945 if self._progbar is not None and self._progbar.printed:
1940 self._progbar.clear()
1946 self._progbar.clear()
1941
1947
1942 def makeprogress(self, topic, unit=b"", total=None):
1948 def makeprogress(self, topic, unit=b"", total=None):
1943 """Create a progress helper for the specified topic"""
1949 """Create a progress helper for the specified topic"""
1944 if getattr(self._fmsgerr, 'structured', False):
1950 if getattr(self._fmsgerr, 'structured', False):
1945 # channel for machine-readable output with metadata, just send
1951 # channel for machine-readable output with metadata, just send
1946 # raw information
1952 # raw information
1947 # TODO: consider porting some useful information (e.g. estimated
1953 # TODO: consider porting some useful information (e.g. estimated
1948 # time) from progbar. we might want to support update delay to
1954 # time) from progbar. we might want to support update delay to
1949 # reduce the cost of transferring progress messages.
1955 # reduce the cost of transferring progress messages.
1950 def updatebar(topic, pos, item, unit, total):
1956 def updatebar(topic, pos, item, unit, total):
1951 self._fmsgerr.write(
1957 self._fmsgerr.write(
1952 None,
1958 None,
1953 type=b'progress',
1959 type=b'progress',
1954 topic=topic,
1960 topic=topic,
1955 pos=pos,
1961 pos=pos,
1956 item=item,
1962 item=item,
1957 unit=unit,
1963 unit=unit,
1958 total=total,
1964 total=total,
1959 )
1965 )
1960
1966
1961 elif self._progbar is not None:
1967 elif self._progbar is not None:
1962 updatebar = self._progbar.progress
1968 updatebar = self._progbar.progress
1963 else:
1969 else:
1964
1970
1965 def updatebar(topic, pos, item, unit, total):
1971 def updatebar(topic, pos, item, unit, total):
1966 pass
1972 pass
1967
1973
1968 return scmutil.progress(self, updatebar, topic, unit, total)
1974 return scmutil.progress(self, updatebar, topic, unit, total)
1969
1975
1970 def getlogger(self, name):
1976 def getlogger(self, name):
1971 """Returns a logger of the given name; or None if not registered"""
1977 """Returns a logger of the given name; or None if not registered"""
1972 return self._loggers.get(name)
1978 return self._loggers.get(name)
1973
1979
1974 def setlogger(self, name, logger):
1980 def setlogger(self, name, logger):
1975 """Install logger which can be identified later by the given name
1981 """Install logger which can be identified later by the given name
1976
1982
1977 More than one loggers can be registered. Use extension or module
1983 More than one loggers can be registered. Use extension or module
1978 name to uniquely identify the logger instance.
1984 name to uniquely identify the logger instance.
1979 """
1985 """
1980 self._loggers[name] = logger
1986 self._loggers[name] = logger
1981
1987
1982 def log(self, event, msgfmt, *msgargs, **opts):
1988 def log(self, event, msgfmt, *msgargs, **opts):
1983 '''hook for logging facility extensions
1989 '''hook for logging facility extensions
1984
1990
1985 event should be a readily-identifiable subsystem, which will
1991 event should be a readily-identifiable subsystem, which will
1986 allow filtering.
1992 allow filtering.
1987
1993
1988 msgfmt should be a newline-terminated format string to log, and
1994 msgfmt should be a newline-terminated format string to log, and
1989 *msgargs are %-formatted into it.
1995 *msgargs are %-formatted into it.
1990
1996
1991 **opts currently has no defined meanings.
1997 **opts currently has no defined meanings.
1992 '''
1998 '''
1993 if not self._loggers:
1999 if not self._loggers:
1994 return
2000 return
1995 activeloggers = [
2001 activeloggers = [
1996 l for l in pycompat.itervalues(self._loggers) if l.tracked(event)
2002 l for l in pycompat.itervalues(self._loggers) if l.tracked(event)
1997 ]
2003 ]
1998 if not activeloggers:
2004 if not activeloggers:
1999 return
2005 return
2000 msg = msgfmt % msgargs
2006 msg = msgfmt % msgargs
2001 opts = pycompat.byteskwargs(opts)
2007 opts = pycompat.byteskwargs(opts)
2002 # guard against recursion from e.g. ui.debug()
2008 # guard against recursion from e.g. ui.debug()
2003 registeredloggers = self._loggers
2009 registeredloggers = self._loggers
2004 self._loggers = {}
2010 self._loggers = {}
2005 try:
2011 try:
2006 for logger in activeloggers:
2012 for logger in activeloggers:
2007 logger.log(self, event, msg, opts)
2013 logger.log(self, event, msg, opts)
2008 finally:
2014 finally:
2009 self._loggers = registeredloggers
2015 self._loggers = registeredloggers
2010
2016
2011 def label(self, msg, label):
2017 def label(self, msg, label):
2012 '''style msg based on supplied label
2018 '''style msg based on supplied label
2013
2019
2014 If some color mode is enabled, this will add the necessary control
2020 If some color mode is enabled, this will add the necessary control
2015 characters to apply such color. In addition, 'debug' color mode adds
2021 characters to apply such color. In addition, 'debug' color mode adds
2016 markup showing which label affects a piece of text.
2022 markup showing which label affects a piece of text.
2017
2023
2018 ui.write(s, 'label') is equivalent to
2024 ui.write(s, 'label') is equivalent to
2019 ui.write(ui.label(s, 'label')).
2025 ui.write(ui.label(s, 'label')).
2020 '''
2026 '''
2021 if self._colormode is not None:
2027 if self._colormode is not None:
2022 return color.colorlabel(self, msg, label)
2028 return color.colorlabel(self, msg, label)
2023 return msg
2029 return msg
2024
2030
2025 def develwarn(self, msg, stacklevel=1, config=None):
2031 def develwarn(self, msg, stacklevel=1, config=None):
2026 """issue a developer warning message
2032 """issue a developer warning message
2027
2033
2028 Use 'stacklevel' to report the offender some layers further up in the
2034 Use 'stacklevel' to report the offender some layers further up in the
2029 stack.
2035 stack.
2030 """
2036 """
2031 if not self.configbool(b'devel', b'all-warnings'):
2037 if not self.configbool(b'devel', b'all-warnings'):
2032 if config is None or not self.configbool(b'devel', config):
2038 if config is None or not self.configbool(b'devel', config):
2033 return
2039 return
2034 msg = b'devel-warn: ' + msg
2040 msg = b'devel-warn: ' + msg
2035 stacklevel += 1 # get in develwarn
2041 stacklevel += 1 # get in develwarn
2036 if self.tracebackflag:
2042 if self.tracebackflag:
2037 util.debugstacktrace(msg, stacklevel, self._ferr, self._fout)
2043 util.debugstacktrace(msg, stacklevel, self._ferr, self._fout)
2038 self.log(
2044 self.log(
2039 b'develwarn',
2045 b'develwarn',
2040 b'%s at:\n%s'
2046 b'%s at:\n%s'
2041 % (msg, b''.join(util.getstackframes(stacklevel))),
2047 % (msg, b''.join(util.getstackframes(stacklevel))),
2042 )
2048 )
2043 else:
2049 else:
2044 curframe = inspect.currentframe()
2050 curframe = inspect.currentframe()
2045 calframe = inspect.getouterframes(curframe, 2)
2051 calframe = inspect.getouterframes(curframe, 2)
2046 fname, lineno, fmsg = calframe[stacklevel][1:4]
2052 fname, lineno, fmsg = calframe[stacklevel][1:4]
2047 fname, fmsg = pycompat.sysbytes(fname), pycompat.sysbytes(fmsg)
2053 fname, fmsg = pycompat.sysbytes(fname), pycompat.sysbytes(fmsg)
2048 self.write_err(b'%s at: %s:%d (%s)\n' % (msg, fname, lineno, fmsg))
2054 self.write_err(b'%s at: %s:%d (%s)\n' % (msg, fname, lineno, fmsg))
2049 self.log(
2055 self.log(
2050 b'develwarn', b'%s at: %s:%d (%s)\n', msg, fname, lineno, fmsg
2056 b'develwarn', b'%s at: %s:%d (%s)\n', msg, fname, lineno, fmsg
2051 )
2057 )
2052
2058
2053 # avoid cycles
2059 # avoid cycles
2054 del curframe
2060 del curframe
2055 del calframe
2061 del calframe
2056
2062
2057 def deprecwarn(self, msg, version, stacklevel=2):
2063 def deprecwarn(self, msg, version, stacklevel=2):
2058 """issue a deprecation warning
2064 """issue a deprecation warning
2059
2065
2060 - msg: message explaining what is deprecated and how to upgrade,
2066 - msg: message explaining what is deprecated and how to upgrade,
2061 - version: last version where the API will be supported,
2067 - version: last version where the API will be supported,
2062 """
2068 """
2063 if not (
2069 if not (
2064 self.configbool(b'devel', b'all-warnings')
2070 self.configbool(b'devel', b'all-warnings')
2065 or self.configbool(b'devel', b'deprec-warn')
2071 or self.configbool(b'devel', b'deprec-warn')
2066 ):
2072 ):
2067 return
2073 return
2068 msg += (
2074 msg += (
2069 b"\n(compatibility will be dropped after Mercurial-%s,"
2075 b"\n(compatibility will be dropped after Mercurial-%s,"
2070 b" update your code.)"
2076 b" update your code.)"
2071 ) % version
2077 ) % version
2072 self.develwarn(msg, stacklevel=stacklevel, config=b'deprec-warn')
2078 self.develwarn(msg, stacklevel=stacklevel, config=b'deprec-warn')
2073
2079
2074 def exportableenviron(self):
2080 def exportableenviron(self):
2075 """The environment variables that are safe to export, e.g. through
2081 """The environment variables that are safe to export, e.g. through
2076 hgweb.
2082 hgweb.
2077 """
2083 """
2078 return self._exportableenviron
2084 return self._exportableenviron
2079
2085
2080 @contextlib.contextmanager
2086 @contextlib.contextmanager
2081 def configoverride(self, overrides, source=b""):
2087 def configoverride(self, overrides, source=b""):
2082 """Context manager for temporary config overrides
2088 """Context manager for temporary config overrides
2083 `overrides` must be a dict of the following structure:
2089 `overrides` must be a dict of the following structure:
2084 {(section, name) : value}"""
2090 {(section, name) : value}"""
2085 backups = {}
2091 backups = {}
2086 try:
2092 try:
2087 for (section, name), value in overrides.items():
2093 for (section, name), value in overrides.items():
2088 backups[(section, name)] = self.backupconfig(section, name)
2094 backups[(section, name)] = self.backupconfig(section, name)
2089 self.setconfig(section, name, value, source)
2095 self.setconfig(section, name, value, source)
2090 yield
2096 yield
2091 finally:
2097 finally:
2092 for __, backup in backups.items():
2098 for __, backup in backups.items():
2093 self.restoreconfig(backup)
2099 self.restoreconfig(backup)
2094 # just restoring ui.quiet config to the previous value is not enough
2100 # just restoring ui.quiet config to the previous value is not enough
2095 # as it does not update ui.quiet class member
2101 # as it does not update ui.quiet class member
2096 if (b'ui', b'quiet') in overrides:
2102 if (b'ui', b'quiet') in overrides:
2097 self.fixconfig(section=b'ui')
2103 self.fixconfig(section=b'ui')
2098
2104
2099
2105
2100 class paths(dict):
2106 class paths(dict):
2101 """Represents a collection of paths and their configs.
2107 """Represents a collection of paths and their configs.
2102
2108
2103 Data is initially derived from ui instances and the config files they have
2109 Data is initially derived from ui instances and the config files they have
2104 loaded.
2110 loaded.
2105 """
2111 """
2106
2112
2107 def __init__(self, ui):
2113 def __init__(self, ui):
2108 dict.__init__(self)
2114 dict.__init__(self)
2109
2115
2110 for name, loc in ui.configitems(b'paths', ignoresub=True):
2116 for name, loc in ui.configitems(b'paths', ignoresub=True):
2111 # No location is the same as not existing.
2117 # No location is the same as not existing.
2112 if not loc:
2118 if not loc:
2113 continue
2119 continue
2114 loc, sub = ui.configsuboptions(b'paths', name)
2120 loc, sub = ui.configsuboptions(b'paths', name)
2115 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
2121 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
2116
2122
2117 def getpath(self, name, default=None):
2123 def getpath(self, name, default=None):
2118 """Return a ``path`` from a string, falling back to default.
2124 """Return a ``path`` from a string, falling back to default.
2119
2125
2120 ``name`` can be a named path or locations. Locations are filesystem
2126 ``name`` can be a named path or locations. Locations are filesystem
2121 paths or URIs.
2127 paths or URIs.
2122
2128
2123 Returns None if ``name`` is not a registered path, a URI, or a local
2129 Returns None if ``name`` is not a registered path, a URI, or a local
2124 path to a repo.
2130 path to a repo.
2125 """
2131 """
2126 # Only fall back to default if no path was requested.
2132 # Only fall back to default if no path was requested.
2127 if name is None:
2133 if name is None:
2128 if not default:
2134 if not default:
2129 default = ()
2135 default = ()
2130 elif not isinstance(default, (tuple, list)):
2136 elif not isinstance(default, (tuple, list)):
2131 default = (default,)
2137 default = (default,)
2132 for k in default:
2138 for k in default:
2133 try:
2139 try:
2134 return self[k]
2140 return self[k]
2135 except KeyError:
2141 except KeyError:
2136 continue
2142 continue
2137 return None
2143 return None
2138
2144
2139 # Most likely empty string.
2145 # Most likely empty string.
2140 # This may need to raise in the future.
2146 # This may need to raise in the future.
2141 if not name:
2147 if not name:
2142 return None
2148 return None
2143
2149
2144 try:
2150 try:
2145 return self[name]
2151 return self[name]
2146 except KeyError:
2152 except KeyError:
2147 # Try to resolve as a local path or URI.
2153 # Try to resolve as a local path or URI.
2148 try:
2154 try:
2149 # We don't pass sub-options in, so no need to pass ui instance.
2155 # We don't pass sub-options in, so no need to pass ui instance.
2150 return path(None, None, rawloc=name)
2156 return path(None, None, rawloc=name)
2151 except ValueError:
2157 except ValueError:
2152 raise error.RepoError(_(b'repository %s does not exist') % name)
2158 raise error.RepoError(_(b'repository %s does not exist') % name)
2153
2159
2154
2160
2155 _pathsuboptions = {}
2161 _pathsuboptions = {}
2156
2162
2157
2163
2158 def pathsuboption(option, attr):
2164 def pathsuboption(option, attr):
2159 """Decorator used to declare a path sub-option.
2165 """Decorator used to declare a path sub-option.
2160
2166
2161 Arguments are the sub-option name and the attribute it should set on
2167 Arguments are the sub-option name and the attribute it should set on
2162 ``path`` instances.
2168 ``path`` instances.
2163
2169
2164 The decorated function will receive as arguments a ``ui`` instance,
2170 The decorated function will receive as arguments a ``ui`` instance,
2165 ``path`` instance, and the string value of this option from the config.
2171 ``path`` instance, and the string value of this option from the config.
2166 The function should return the value that will be set on the ``path``
2172 The function should return the value that will be set on the ``path``
2167 instance.
2173 instance.
2168
2174
2169 This decorator can be used to perform additional verification of
2175 This decorator can be used to perform additional verification of
2170 sub-options and to change the type of sub-options.
2176 sub-options and to change the type of sub-options.
2171 """
2177 """
2172
2178
2173 def register(func):
2179 def register(func):
2174 _pathsuboptions[option] = (attr, func)
2180 _pathsuboptions[option] = (attr, func)
2175 return func
2181 return func
2176
2182
2177 return register
2183 return register
2178
2184
2179
2185
2180 @pathsuboption(b'pushurl', b'pushloc')
2186 @pathsuboption(b'pushurl', b'pushloc')
2181 def pushurlpathoption(ui, path, value):
2187 def pushurlpathoption(ui, path, value):
2182 u = util.url(value)
2188 u = util.url(value)
2183 # Actually require a URL.
2189 # Actually require a URL.
2184 if not u.scheme:
2190 if not u.scheme:
2185 ui.warn(_(b'(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
2191 ui.warn(_(b'(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
2186 return None
2192 return None
2187
2193
2188 # Don't support the #foo syntax in the push URL to declare branch to
2194 # Don't support the #foo syntax in the push URL to declare branch to
2189 # push.
2195 # push.
2190 if u.fragment:
2196 if u.fragment:
2191 ui.warn(
2197 ui.warn(
2192 _(
2198 _(
2193 b'("#fragment" in paths.%s:pushurl not supported; '
2199 b'("#fragment" in paths.%s:pushurl not supported; '
2194 b'ignoring)\n'
2200 b'ignoring)\n'
2195 )
2201 )
2196 % path.name
2202 % path.name
2197 )
2203 )
2198 u.fragment = None
2204 u.fragment = None
2199
2205
2200 return bytes(u)
2206 return bytes(u)
2201
2207
2202
2208
2203 @pathsuboption(b'pushrev', b'pushrev')
2209 @pathsuboption(b'pushrev', b'pushrev')
2204 def pushrevpathoption(ui, path, value):
2210 def pushrevpathoption(ui, path, value):
2205 return value
2211 return value
2206
2212
2207
2213
2208 class path(object):
2214 class path(object):
2209 """Represents an individual path and its configuration."""
2215 """Represents an individual path and its configuration."""
2210
2216
2211 def __init__(self, ui, name, rawloc=None, suboptions=None):
2217 def __init__(self, ui, name, rawloc=None, suboptions=None):
2212 """Construct a path from its config options.
2218 """Construct a path from its config options.
2213
2219
2214 ``ui`` is the ``ui`` instance the path is coming from.
2220 ``ui`` is the ``ui`` instance the path is coming from.
2215 ``name`` is the symbolic name of the path.
2221 ``name`` is the symbolic name of the path.
2216 ``rawloc`` is the raw location, as defined in the config.
2222 ``rawloc`` is the raw location, as defined in the config.
2217 ``pushloc`` is the raw locations pushes should be made to.
2223 ``pushloc`` is the raw locations pushes should be made to.
2218
2224
2219 If ``name`` is not defined, we require that the location be a) a local
2225 If ``name`` is not defined, we require that the location be a) a local
2220 filesystem path with a .hg directory or b) a URL. If not,
2226 filesystem path with a .hg directory or b) a URL. If not,
2221 ``ValueError`` is raised.
2227 ``ValueError`` is raised.
2222 """
2228 """
2223 if not rawloc:
2229 if not rawloc:
2224 raise ValueError(b'rawloc must be defined')
2230 raise ValueError(b'rawloc must be defined')
2225
2231
2226 # Locations may define branches via syntax <base>#<branch>.
2232 # Locations may define branches via syntax <base>#<branch>.
2227 u = util.url(rawloc)
2233 u = util.url(rawloc)
2228 branch = None
2234 branch = None
2229 if u.fragment:
2235 if u.fragment:
2230 branch = u.fragment
2236 branch = u.fragment
2231 u.fragment = None
2237 u.fragment = None
2232
2238
2233 self.url = u
2239 self.url = u
2234 self.branch = branch
2240 self.branch = branch
2235
2241
2236 self.name = name
2242 self.name = name
2237 self.rawloc = rawloc
2243 self.rawloc = rawloc
2238 self.loc = b'%s' % u
2244 self.loc = b'%s' % u
2239
2245
2240 # When given a raw location but not a symbolic name, validate the
2246 # When given a raw location but not a symbolic name, validate the
2241 # location is valid.
2247 # location is valid.
2242 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
2248 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
2243 raise ValueError(
2249 raise ValueError(
2244 b'location is not a URL or path to a local '
2250 b'location is not a URL or path to a local '
2245 b'repo: %s' % rawloc
2251 b'repo: %s' % rawloc
2246 )
2252 )
2247
2253
2248 suboptions = suboptions or {}
2254 suboptions = suboptions or {}
2249
2255
2250 # Now process the sub-options. If a sub-option is registered, its
2256 # Now process the sub-options. If a sub-option is registered, its
2251 # attribute will always be present. The value will be None if there
2257 # attribute will always be present. The value will be None if there
2252 # was no valid sub-option.
2258 # was no valid sub-option.
2253 for suboption, (attr, func) in pycompat.iteritems(_pathsuboptions):
2259 for suboption, (attr, func) in pycompat.iteritems(_pathsuboptions):
2254 if suboption not in suboptions:
2260 if suboption not in suboptions:
2255 setattr(self, attr, None)
2261 setattr(self, attr, None)
2256 continue
2262 continue
2257
2263
2258 value = func(ui, self, suboptions[suboption])
2264 value = func(ui, self, suboptions[suboption])
2259 setattr(self, attr, value)
2265 setattr(self, attr, value)
2260
2266
2261 def _isvalidlocalpath(self, path):
2267 def _isvalidlocalpath(self, path):
2262 """Returns True if the given path is a potentially valid repository.
2268 """Returns True if the given path is a potentially valid repository.
2263 This is its own function so that extensions can change the definition of
2269 This is its own function so that extensions can change the definition of
2264 'valid' in this case (like when pulling from a git repo into a hg
2270 'valid' in this case (like when pulling from a git repo into a hg
2265 one)."""
2271 one)."""
2266 try:
2272 try:
2267 return os.path.isdir(os.path.join(path, b'.hg'))
2273 return os.path.isdir(os.path.join(path, b'.hg'))
2268 # Python 2 may return TypeError. Python 3, ValueError.
2274 # Python 2 may return TypeError. Python 3, ValueError.
2269 except (TypeError, ValueError):
2275 except (TypeError, ValueError):
2270 return False
2276 return False
2271
2277
2272 @property
2278 @property
2273 def suboptions(self):
2279 def suboptions(self):
2274 """Return sub-options and their values for this path.
2280 """Return sub-options and their values for this path.
2275
2281
2276 This is intended to be used for presentation purposes.
2282 This is intended to be used for presentation purposes.
2277 """
2283 """
2278 d = {}
2284 d = {}
2279 for subopt, (attr, _func) in pycompat.iteritems(_pathsuboptions):
2285 for subopt, (attr, _func) in pycompat.iteritems(_pathsuboptions):
2280 value = getattr(self, attr)
2286 value = getattr(self, attr)
2281 if value is not None:
2287 if value is not None:
2282 d[subopt] = value
2288 d[subopt] = value
2283 return d
2289 return d
2284
2290
2285
2291
2286 # we instantiate one globally shared progress bar to avoid
2292 # we instantiate one globally shared progress bar to avoid
2287 # competing progress bars when multiple UI objects get created
2293 # competing progress bars when multiple UI objects get created
2288 _progresssingleton = None
2294 _progresssingleton = None
2289
2295
2290
2296
2291 def getprogbar(ui):
2297 def getprogbar(ui):
2292 global _progresssingleton
2298 global _progresssingleton
2293 if _progresssingleton is None:
2299 if _progresssingleton is None:
2294 # passing 'ui' object to the singleton is fishy,
2300 # passing 'ui' object to the singleton is fishy,
2295 # this is how the extension used to work but feel free to rework it.
2301 # this is how the extension used to work but feel free to rework it.
2296 _progresssingleton = progress.progbar(ui)
2302 _progresssingleton = progress.progbar(ui)
2297 return _progresssingleton
2303 return _progresssingleton
2298
2304
2299
2305
2300 def haveprogbar():
2306 def haveprogbar():
2301 return _progresssingleton is not None
2307 return _progresssingleton is not None
2302
2308
2303
2309
2304 def _selectmsgdests(ui):
2310 def _selectmsgdests(ui):
2305 name = ui.config(b'ui', b'message-output')
2311 name = ui.config(b'ui', b'message-output')
2306 if name == b'channel':
2312 if name == b'channel':
2307 if ui.fmsg:
2313 if ui.fmsg:
2308 return ui.fmsg, ui.fmsg
2314 return ui.fmsg, ui.fmsg
2309 else:
2315 else:
2310 # fall back to ferr if channel isn't ready so that status/error
2316 # fall back to ferr if channel isn't ready so that status/error
2311 # messages can be printed
2317 # messages can be printed
2312 return ui.ferr, ui.ferr
2318 return ui.ferr, ui.ferr
2313 if name == b'stdio':
2319 if name == b'stdio':
2314 return ui.fout, ui.ferr
2320 return ui.fout, ui.ferr
2315 if name == b'stderr':
2321 if name == b'stderr':
2316 return ui.ferr, ui.ferr
2322 return ui.ferr, ui.ferr
2317 raise error.Abort(b'invalid ui.message-output destination: %s' % name)
2323 raise error.Abort(b'invalid ui.message-output destination: %s' % name)
2318
2324
2319
2325
2320 def _writemsgwith(write, dest, *args, **opts):
2326 def _writemsgwith(write, dest, *args, **opts):
2321 """Write ui message with the given ui._write*() function
2327 """Write ui message with the given ui._write*() function
2322
2328
2323 The specified message type is translated to 'ui.<type>' label if the dest
2329 The specified message type is translated to 'ui.<type>' label if the dest
2324 isn't a structured channel, so that the message will be colorized.
2330 isn't a structured channel, so that the message will be colorized.
2325 """
2331 """
2326 # TODO: maybe change 'type' to a mandatory option
2332 # TODO: maybe change 'type' to a mandatory option
2327 if 'type' in opts and not getattr(dest, 'structured', False):
2333 if 'type' in opts and not getattr(dest, 'structured', False):
2328 opts['label'] = opts.get('label', b'') + b' ui.%s' % opts.pop('type')
2334 opts['label'] = opts.get('label', b'') + b' ui.%s' % opts.pop('type')
2329 write(dest, *args, **opts)
2335 write(dest, *args, **opts)
@@ -1,1753 +1,1753 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 will never work on Python 3 before 3.5 due to a lack
8 # Mercurial will never work on Python 3 before 3.5 due to a lack
9 # of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1
9 # of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1
10 # due to a bug in % formatting in bytestrings.
10 # due to a bug in % formatting in bytestrings.
11 # We cannot support Python 3.5.0, 3.5.1, 3.5.2 because of bug in
11 # We cannot support Python 3.5.0, 3.5.1, 3.5.2 because of bug in
12 # codecs.escape_encode() where it raises SystemError on empty bytestring
12 # codecs.escape_encode() where it raises SystemError on empty bytestring
13 # bug link: https://bugs.python.org/issue25270
13 # bug link: https://bugs.python.org/issue25270
14 supportedpy = ','.join(
14 supportedpy = ','.join(
15 [
15 [
16 '>=2.7',
16 '>=2.7',
17 '!=3.0.*',
17 '!=3.0.*',
18 '!=3.1.*',
18 '!=3.1.*',
19 '!=3.2.*',
19 '!=3.2.*',
20 '!=3.3.*',
20 '!=3.3.*',
21 '!=3.4.*',
21 '!=3.4.*',
22 '!=3.5.0',
22 '!=3.5.0',
23 '!=3.5.1',
23 '!=3.5.1',
24 '!=3.5.2',
24 '!=3.5.2',
25 '!=3.6.0',
25 '!=3.6.0',
26 '!=3.6.1',
26 '!=3.6.1',
27 ]
27 ]
28 )
28 )
29
29
30 import sys, platform
30 import sys, platform
31 import sysconfig
31 import sysconfig
32
32
33 if sys.version_info[0] >= 3:
33 if sys.version_info[0] >= 3:
34 printf = eval('print')
34 printf = eval('print')
35 libdir_escape = 'unicode_escape'
35 libdir_escape = 'unicode_escape'
36
36
37 def sysstr(s):
37 def sysstr(s):
38 return s.decode('latin-1')
38 return s.decode('latin-1')
39
39
40
40
41 else:
41 else:
42 libdir_escape = 'string_escape'
42 libdir_escape = 'string_escape'
43
43
44 def printf(*args, **kwargs):
44 def printf(*args, **kwargs):
45 f = kwargs.get('file', sys.stdout)
45 f = kwargs.get('file', sys.stdout)
46 end = kwargs.get('end', '\n')
46 end = kwargs.get('end', '\n')
47 f.write(b' '.join(args) + end)
47 f.write(b' '.join(args) + end)
48
48
49 def sysstr(s):
49 def sysstr(s):
50 return s
50 return s
51
51
52
52
53 # Attempt to guide users to a modern pip - this means that 2.6 users
53 # Attempt to guide users to a modern pip - this means that 2.6 users
54 # should have a chance of getting a 4.2 release, and when we ratchet
54 # should have a chance of getting a 4.2 release, and when we ratchet
55 # the version requirement forward again hopefully everyone will get
55 # the version requirement forward again hopefully everyone will get
56 # something that works for them.
56 # something that works for them.
57 if sys.version_info < (2, 7, 0, 'final'):
57 if sys.version_info < (2, 7, 0, 'final'):
58 pip_message = (
58 pip_message = (
59 'This may be due to an out of date pip. '
59 'This may be due to an out of date pip. '
60 'Make sure you have pip >= 9.0.1.'
60 'Make sure you have pip >= 9.0.1.'
61 )
61 )
62 try:
62 try:
63 import pip
63 import pip
64
64
65 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]])
65 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]])
66 if pip_version < (9, 0, 1):
66 if pip_version < (9, 0, 1):
67 pip_message = (
67 pip_message = (
68 'Your pip version is out of date, please install '
68 'Your pip version is out of date, please install '
69 'pip >= 9.0.1. pip {} detected.'.format(pip.__version__)
69 'pip >= 9.0.1. pip {} detected.'.format(pip.__version__)
70 )
70 )
71 else:
71 else:
72 # pip is new enough - it must be something else
72 # pip is new enough - it must be something else
73 pip_message = ''
73 pip_message = ''
74 except Exception:
74 except Exception:
75 pass
75 pass
76 error = """
76 error = """
77 Mercurial does not support Python older than 2.7.
77 Mercurial does not support Python older than 2.7.
78 Python {py} detected.
78 Python {py} detected.
79 {pip}
79 {pip}
80 """.format(
80 """.format(
81 py=sys.version_info, pip=pip_message
81 py=sys.version_info, pip=pip_message
82 )
82 )
83 printf(error, file=sys.stderr)
83 printf(error, file=sys.stderr)
84 sys.exit(1)
84 sys.exit(1)
85
85
86 if sys.version_info[0] >= 3:
86 if sys.version_info[0] >= 3:
87 DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX']
87 DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX']
88 else:
88 else:
89 # deprecated in Python 3
89 # deprecated in Python 3
90 DYLIB_SUFFIX = sysconfig.get_config_vars()['SO']
90 DYLIB_SUFFIX = sysconfig.get_config_vars()['SO']
91
91
92 # Solaris Python packaging brain damage
92 # Solaris Python packaging brain damage
93 try:
93 try:
94 import hashlib
94 import hashlib
95
95
96 sha = hashlib.sha1()
96 sha = hashlib.sha1()
97 except ImportError:
97 except ImportError:
98 try:
98 try:
99 import sha
99 import sha
100
100
101 sha.sha # silence unused import warning
101 sha.sha # silence unused import warning
102 except ImportError:
102 except ImportError:
103 raise SystemExit(
103 raise SystemExit(
104 "Couldn't import standard hashlib (incomplete Python install)."
104 "Couldn't import standard hashlib (incomplete Python install)."
105 )
105 )
106
106
107 try:
107 try:
108 import zlib
108 import zlib
109
109
110 zlib.compressobj # silence unused import warning
110 zlib.compressobj # silence unused import warning
111 except ImportError:
111 except ImportError:
112 raise SystemExit(
112 raise SystemExit(
113 "Couldn't import standard zlib (incomplete Python install)."
113 "Couldn't import standard zlib (incomplete Python install)."
114 )
114 )
115
115
116 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
116 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
117 isironpython = False
117 isironpython = False
118 try:
118 try:
119 isironpython = (
119 isironpython = (
120 platform.python_implementation().lower().find("ironpython") != -1
120 platform.python_implementation().lower().find("ironpython") != -1
121 )
121 )
122 except AttributeError:
122 except AttributeError:
123 pass
123 pass
124
124
125 if isironpython:
125 if isironpython:
126 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
126 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
127 else:
127 else:
128 try:
128 try:
129 import bz2
129 import bz2
130
130
131 bz2.BZ2Compressor # silence unused import warning
131 bz2.BZ2Compressor # silence unused import warning
132 except ImportError:
132 except ImportError:
133 raise SystemExit(
133 raise SystemExit(
134 "Couldn't import standard bz2 (incomplete Python install)."
134 "Couldn't import standard bz2 (incomplete Python install)."
135 )
135 )
136
136
137 ispypy = "PyPy" in sys.version
137 ispypy = "PyPy" in sys.version
138
138
139 import ctypes
139 import ctypes
140 import errno
140 import errno
141 import stat, subprocess, time
141 import stat, subprocess, time
142 import re
142 import re
143 import shutil
143 import shutil
144 import tempfile
144 import tempfile
145 from distutils import log
145 from distutils import log
146
146
147 # We have issues with setuptools on some platforms and builders. Until
147 # We have issues with setuptools on some platforms and builders. Until
148 # those are resolved, setuptools is opt-in except for platforms where
148 # those are resolved, setuptools is opt-in except for platforms where
149 # we don't have issues.
149 # we don't have issues.
150 issetuptools = os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ
150 issetuptools = os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ
151 if issetuptools:
151 if issetuptools:
152 from setuptools import setup
152 from setuptools import setup
153 else:
153 else:
154 from distutils.core import setup
154 from distutils.core import setup
155 from distutils.ccompiler import new_compiler
155 from distutils.ccompiler import new_compiler
156 from distutils.core import Command, Extension
156 from distutils.core import Command, Extension
157 from distutils.dist import Distribution
157 from distutils.dist import Distribution
158 from distutils.command.build import build
158 from distutils.command.build import build
159 from distutils.command.build_ext import build_ext
159 from distutils.command.build_ext import build_ext
160 from distutils.command.build_py import build_py
160 from distutils.command.build_py import build_py
161 from distutils.command.build_scripts import build_scripts
161 from distutils.command.build_scripts import build_scripts
162 from distutils.command.install import install
162 from distutils.command.install import install
163 from distutils.command.install_lib import install_lib
163 from distutils.command.install_lib import install_lib
164 from distutils.command.install_scripts import install_scripts
164 from distutils.command.install_scripts import install_scripts
165 from distutils.spawn import spawn, find_executable
165 from distutils.spawn import spawn, find_executable
166 from distutils import file_util
166 from distutils import file_util
167 from distutils.errors import (
167 from distutils.errors import (
168 CCompilerError,
168 CCompilerError,
169 DistutilsError,
169 DistutilsError,
170 DistutilsExecError,
170 DistutilsExecError,
171 )
171 )
172 from distutils.sysconfig import get_python_inc, get_config_var
172 from distutils.sysconfig import get_python_inc, get_config_var
173 from distutils.version import StrictVersion
173 from distutils.version import StrictVersion
174
174
175 # Explain to distutils.StrictVersion how our release candidates are versionned
175 # Explain to distutils.StrictVersion how our release candidates are versionned
176 StrictVersion.version_re = re.compile(r'^(\d+)\.(\d+)(\.(\d+))?-?(rc(\d+))?$')
176 StrictVersion.version_re = re.compile(r'^(\d+)\.(\d+)(\.(\d+))?-?(rc(\d+))?$')
177
177
178
178
179 def write_if_changed(path, content):
179 def write_if_changed(path, content):
180 """Write content to a file iff the content hasn't changed."""
180 """Write content to a file iff the content hasn't changed."""
181 if os.path.exists(path):
181 if os.path.exists(path):
182 with open(path, 'rb') as fh:
182 with open(path, 'rb') as fh:
183 current = fh.read()
183 current = fh.read()
184 else:
184 else:
185 current = b''
185 current = b''
186
186
187 if current != content:
187 if current != content:
188 with open(path, 'wb') as fh:
188 with open(path, 'wb') as fh:
189 fh.write(content)
189 fh.write(content)
190
190
191
191
192 scripts = ['hg']
192 scripts = ['hg']
193 if os.name == 'nt':
193 if os.name == 'nt':
194 # We remove hg.bat if we are able to build hg.exe.
194 # We remove hg.bat if we are able to build hg.exe.
195 scripts.append('contrib/win32/hg.bat')
195 scripts.append('contrib/win32/hg.bat')
196
196
197
197
198 def cancompile(cc, code):
198 def cancompile(cc, code):
199 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
199 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
200 devnull = oldstderr = None
200 devnull = oldstderr = None
201 try:
201 try:
202 fname = os.path.join(tmpdir, 'testcomp.c')
202 fname = os.path.join(tmpdir, 'testcomp.c')
203 f = open(fname, 'w')
203 f = open(fname, 'w')
204 f.write(code)
204 f.write(code)
205 f.close()
205 f.close()
206 # Redirect stderr to /dev/null to hide any error messages
206 # Redirect stderr to /dev/null to hide any error messages
207 # from the compiler.
207 # from the compiler.
208 # This will have to be changed if we ever have to check
208 # This will have to be changed if we ever have to check
209 # for a function on Windows.
209 # for a function on Windows.
210 devnull = open('/dev/null', 'w')
210 devnull = open('/dev/null', 'w')
211 oldstderr = os.dup(sys.stderr.fileno())
211 oldstderr = os.dup(sys.stderr.fileno())
212 os.dup2(devnull.fileno(), sys.stderr.fileno())
212 os.dup2(devnull.fileno(), sys.stderr.fileno())
213 objects = cc.compile([fname], output_dir=tmpdir)
213 objects = cc.compile([fname], output_dir=tmpdir)
214 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
214 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
215 return True
215 return True
216 except Exception:
216 except Exception:
217 return False
217 return False
218 finally:
218 finally:
219 if oldstderr is not None:
219 if oldstderr is not None:
220 os.dup2(oldstderr, sys.stderr.fileno())
220 os.dup2(oldstderr, sys.stderr.fileno())
221 if devnull is not None:
221 if devnull is not None:
222 devnull.close()
222 devnull.close()
223 shutil.rmtree(tmpdir)
223 shutil.rmtree(tmpdir)
224
224
225
225
226 # simplified version of distutils.ccompiler.CCompiler.has_function
226 # simplified version of distutils.ccompiler.CCompiler.has_function
227 # that actually removes its temporary files.
227 # that actually removes its temporary files.
228 def hasfunction(cc, funcname):
228 def hasfunction(cc, funcname):
229 code = 'int main(void) { %s(); }\n' % funcname
229 code = 'int main(void) { %s(); }\n' % funcname
230 return cancompile(cc, code)
230 return cancompile(cc, code)
231
231
232
232
233 def hasheader(cc, headername):
233 def hasheader(cc, headername):
234 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
234 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
235 return cancompile(cc, code)
235 return cancompile(cc, code)
236
236
237
237
238 # py2exe needs to be installed to work
238 # py2exe needs to be installed to work
239 try:
239 try:
240 import py2exe
240 import py2exe
241
241
242 py2exe.Distribution # silence unused import warning
242 py2exe.Distribution # silence unused import warning
243 py2exeloaded = True
243 py2exeloaded = True
244 # import py2exe's patched Distribution class
244 # import py2exe's patched Distribution class
245 from distutils.core import Distribution
245 from distutils.core import Distribution
246 except ImportError:
246 except ImportError:
247 py2exeloaded = False
247 py2exeloaded = False
248
248
249
249
250 def runcmd(cmd, env, cwd=None):
250 def runcmd(cmd, env, cwd=None):
251 p = subprocess.Popen(
251 p = subprocess.Popen(
252 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, cwd=cwd
252 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, cwd=cwd
253 )
253 )
254 out, err = p.communicate()
254 out, err = p.communicate()
255 return p.returncode, out, err
255 return p.returncode, out, err
256
256
257
257
258 class hgcommand(object):
258 class hgcommand(object):
259 def __init__(self, cmd, env):
259 def __init__(self, cmd, env):
260 self.cmd = cmd
260 self.cmd = cmd
261 self.env = env
261 self.env = env
262
262
263 def run(self, args):
263 def run(self, args):
264 cmd = self.cmd + args
264 cmd = self.cmd + args
265 returncode, out, err = runcmd(cmd, self.env)
265 returncode, out, err = runcmd(cmd, self.env)
266 err = filterhgerr(err)
266 err = filterhgerr(err)
267 if err or returncode != 0:
267 if err or returncode != 0:
268 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
268 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
269 printf(err, file=sys.stderr)
269 printf(err, file=sys.stderr)
270 return ''
270 return b''
271 return out
271 return out
272
272
273
273
274 def filterhgerr(err):
274 def filterhgerr(err):
275 # If root is executing setup.py, but the repository is owned by
275 # If root is executing setup.py, but the repository is owned by
276 # another user (as in "sudo python setup.py install") we will get
276 # another user (as in "sudo python setup.py install") we will get
277 # trust warnings since the .hg/hgrc file is untrusted. That is
277 # trust warnings since the .hg/hgrc file is untrusted. That is
278 # fine, we don't want to load it anyway. Python may warn about
278 # fine, we don't want to load it anyway. Python may warn about
279 # a missing __init__.py in mercurial/locale, we also ignore that.
279 # a missing __init__.py in mercurial/locale, we also ignore that.
280 err = [
280 err = [
281 e
281 e
282 for e in err.splitlines()
282 for e in err.splitlines()
283 if (
283 if (
284 not e.startswith(b'not trusting file')
284 not e.startswith(b'not trusting file')
285 and not e.startswith(b'warning: Not importing')
285 and not e.startswith(b'warning: Not importing')
286 and not e.startswith(b'obsolete feature not enabled')
286 and not e.startswith(b'obsolete feature not enabled')
287 and not e.startswith(b'*** failed to import extension')
287 and not e.startswith(b'*** failed to import extension')
288 and not e.startswith(b'devel-warn:')
288 and not e.startswith(b'devel-warn:')
289 and not (
289 and not (
290 e.startswith(b'(third party extension')
290 e.startswith(b'(third party extension')
291 and e.endswith(b'or newer of Mercurial; disabling)')
291 and e.endswith(b'or newer of Mercurial; disabling)')
292 )
292 )
293 )
293 )
294 ]
294 ]
295 return b'\n'.join(b' ' + e for e in err)
295 return b'\n'.join(b' ' + e for e in err)
296
296
297
297
298 def findhg():
298 def findhg():
299 """Try to figure out how we should invoke hg for examining the local
299 """Try to figure out how we should invoke hg for examining the local
300 repository contents.
300 repository contents.
301
301
302 Returns an hgcommand object."""
302 Returns an hgcommand object."""
303 # By default, prefer the "hg" command in the user's path. This was
303 # By default, prefer the "hg" command in the user's path. This was
304 # presumably the hg command that the user used to create this repository.
304 # presumably the hg command that the user used to create this repository.
305 #
305 #
306 # This repository may require extensions or other settings that would not
306 # This repository may require extensions or other settings that would not
307 # be enabled by running the hg script directly from this local repository.
307 # be enabled by running the hg script directly from this local repository.
308 hgenv = os.environ.copy()
308 hgenv = os.environ.copy()
309 # Use HGPLAIN to disable hgrc settings that would change output formatting,
309 # Use HGPLAIN to disable hgrc settings that would change output formatting,
310 # and disable localization for the same reasons.
310 # and disable localization for the same reasons.
311 hgenv['HGPLAIN'] = '1'
311 hgenv['HGPLAIN'] = '1'
312 hgenv['LANGUAGE'] = 'C'
312 hgenv['LANGUAGE'] = 'C'
313 hgcmd = ['hg']
313 hgcmd = ['hg']
314 # Run a simple "hg log" command just to see if using hg from the user's
314 # Run a simple "hg log" command just to see if using hg from the user's
315 # path works and can successfully interact with this repository. Windows
315 # path works and can successfully interact with this repository. Windows
316 # gives precedence to hg.exe in the current directory, so fall back to the
316 # gives precedence to hg.exe in the current directory, so fall back to the
317 # python invocation of local hg, where pythonXY.dll can always be found.
317 # python invocation of local hg, where pythonXY.dll can always be found.
318 check_cmd = ['log', '-r.', '-Ttest']
318 check_cmd = ['log', '-r.', '-Ttest']
319 if os.name != 'nt' or not os.path.exists("hg.exe"):
319 if os.name != 'nt' or not os.path.exists("hg.exe"):
320 try:
320 try:
321 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
321 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
322 except EnvironmentError:
322 except EnvironmentError:
323 retcode = -1
323 retcode = -1
324 if retcode == 0 and not filterhgerr(err):
324 if retcode == 0 and not filterhgerr(err):
325 return hgcommand(hgcmd, hgenv)
325 return hgcommand(hgcmd, hgenv)
326
326
327 # Fall back to trying the local hg installation.
327 # Fall back to trying the local hg installation.
328 hgenv = localhgenv()
328 hgenv = localhgenv()
329 hgcmd = [sys.executable, 'hg']
329 hgcmd = [sys.executable, 'hg']
330 try:
330 try:
331 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
331 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
332 except EnvironmentError:
332 except EnvironmentError:
333 retcode = -1
333 retcode = -1
334 if retcode == 0 and not filterhgerr(err):
334 if retcode == 0 and not filterhgerr(err):
335 return hgcommand(hgcmd, hgenv)
335 return hgcommand(hgcmd, hgenv)
336
336
337 raise SystemExit(
337 raise SystemExit(
338 'Unable to find a working hg binary to extract the '
338 'Unable to find a working hg binary to extract the '
339 'version from the repository tags'
339 'version from the repository tags'
340 )
340 )
341
341
342
342
343 def localhgenv():
343 def localhgenv():
344 """Get an environment dictionary to use for invoking or importing
344 """Get an environment dictionary to use for invoking or importing
345 mercurial from the local repository."""
345 mercurial from the local repository."""
346 # Execute hg out of this directory with a custom environment which takes
346 # Execute hg out of this directory with a custom environment which takes
347 # care to not use any hgrc files and do no localization.
347 # care to not use any hgrc files and do no localization.
348 env = {
348 env = {
349 'HGMODULEPOLICY': 'py',
349 'HGMODULEPOLICY': 'py',
350 'HGRCPATH': '',
350 'HGRCPATH': '',
351 'LANGUAGE': 'C',
351 'LANGUAGE': 'C',
352 'PATH': '',
352 'PATH': '',
353 } # make pypi modules that use os.environ['PATH'] happy
353 } # make pypi modules that use os.environ['PATH'] happy
354 if 'LD_LIBRARY_PATH' in os.environ:
354 if 'LD_LIBRARY_PATH' in os.environ:
355 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
355 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
356 if 'SystemRoot' in os.environ:
356 if 'SystemRoot' in os.environ:
357 # SystemRoot is required by Windows to load various DLLs. See:
357 # SystemRoot is required by Windows to load various DLLs. See:
358 # https://bugs.python.org/issue13524#msg148850
358 # https://bugs.python.org/issue13524#msg148850
359 env['SystemRoot'] = os.environ['SystemRoot']
359 env['SystemRoot'] = os.environ['SystemRoot']
360 return env
360 return env
361
361
362
362
363 version = ''
363 version = ''
364
364
365 if os.path.isdir('.hg'):
365 if os.path.isdir('.hg'):
366 hg = findhg()
366 hg = findhg()
367 cmd = ['log', '-r', '.', '--template', '{tags}\n']
367 cmd = ['log', '-r', '.', '--template', '{tags}\n']
368 numerictags = [t for t in sysstr(hg.run(cmd)).split() if t[0:1].isdigit()]
368 numerictags = [t for t in sysstr(hg.run(cmd)).split() if t[0:1].isdigit()]
369 hgid = sysstr(hg.run(['id', '-i'])).strip()
369 hgid = sysstr(hg.run(['id', '-i'])).strip()
370 if not hgid:
370 if not hgid:
371 # Bail out if hg is having problems interacting with this repository,
371 # Bail out if hg is having problems interacting with this repository,
372 # rather than falling through and producing a bogus version number.
372 # rather than falling through and producing a bogus version number.
373 # Continuing with an invalid version number will break extensions
373 # Continuing with an invalid version number will break extensions
374 # that define minimumhgversion.
374 # that define minimumhgversion.
375 raise SystemExit('Unable to determine hg version from local repository')
375 raise SystemExit('Unable to determine hg version from local repository')
376 if numerictags: # tag(s) found
376 if numerictags: # tag(s) found
377 version = numerictags[-1]
377 version = numerictags[-1]
378 if hgid.endswith('+'): # propagate the dirty status to the tag
378 if hgid.endswith('+'): # propagate the dirty status to the tag
379 version += '+'
379 version += '+'
380 else: # no tag found
380 else: # no tag found
381 ltagcmd = ['parents', '--template', '{latesttag}']
381 ltagcmd = ['parents', '--template', '{latesttag}']
382 ltag = sysstr(hg.run(ltagcmd))
382 ltag = sysstr(hg.run(ltagcmd))
383 changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
383 changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
384 changessince = len(hg.run(changessincecmd).splitlines())
384 changessince = len(hg.run(changessincecmd).splitlines())
385 version = '%s+%s-%s' % (ltag, changessince, hgid)
385 version = '%s+%s-%s' % (ltag, changessince, hgid)
386 if version.endswith('+'):
386 if version.endswith('+'):
387 version += time.strftime('%Y%m%d')
387 version += time.strftime('%Y%m%d')
388 elif os.path.exists('.hg_archival.txt'):
388 elif os.path.exists('.hg_archival.txt'):
389 kw = dict(
389 kw = dict(
390 [[t.strip() for t in l.split(':', 1)] for l in open('.hg_archival.txt')]
390 [[t.strip() for t in l.split(':', 1)] for l in open('.hg_archival.txt')]
391 )
391 )
392 if 'tag' in kw:
392 if 'tag' in kw:
393 version = kw['tag']
393 version = kw['tag']
394 elif 'latesttag' in kw:
394 elif 'latesttag' in kw:
395 if 'changessincelatesttag' in kw:
395 if 'changessincelatesttag' in kw:
396 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
396 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
397 else:
397 else:
398 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
398 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
399 else:
399 else:
400 version = kw.get('node', '')[:12]
400 version = kw.get('node', '')[:12]
401
401
402 if version:
402 if version:
403 versionb = version
403 versionb = version
404 if not isinstance(versionb, bytes):
404 if not isinstance(versionb, bytes):
405 versionb = versionb.encode('ascii')
405 versionb = versionb.encode('ascii')
406
406
407 write_if_changed(
407 write_if_changed(
408 'mercurial/__version__.py',
408 'mercurial/__version__.py',
409 b''.join(
409 b''.join(
410 [
410 [
411 b'# this file is autogenerated by setup.py\n'
411 b'# this file is autogenerated by setup.py\n'
412 b'version = b"%s"\n' % versionb,
412 b'version = b"%s"\n' % versionb,
413 ]
413 ]
414 ),
414 ),
415 )
415 )
416
416
417 try:
417 try:
418 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
418 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
419 os.environ['HGMODULEPOLICY'] = 'py'
419 os.environ['HGMODULEPOLICY'] = 'py'
420 from mercurial import __version__
420 from mercurial import __version__
421
421
422 version = __version__.version
422 version = __version__.version
423 except ImportError:
423 except ImportError:
424 version = b'unknown'
424 version = b'unknown'
425 finally:
425 finally:
426 if oldpolicy is None:
426 if oldpolicy is None:
427 del os.environ['HGMODULEPOLICY']
427 del os.environ['HGMODULEPOLICY']
428 else:
428 else:
429 os.environ['HGMODULEPOLICY'] = oldpolicy
429 os.environ['HGMODULEPOLICY'] = oldpolicy
430
430
431
431
432 class hgbuild(build):
432 class hgbuild(build):
433 # Insert hgbuildmo first so that files in mercurial/locale/ are found
433 # Insert hgbuildmo first so that files in mercurial/locale/ are found
434 # when build_py is run next.
434 # when build_py is run next.
435 sub_commands = [('build_mo', None)] + build.sub_commands
435 sub_commands = [('build_mo', None)] + build.sub_commands
436
436
437
437
438 class hgbuildmo(build):
438 class hgbuildmo(build):
439
439
440 description = "build translations (.mo files)"
440 description = "build translations (.mo files)"
441
441
442 def run(self):
442 def run(self):
443 if not find_executable('msgfmt'):
443 if not find_executable('msgfmt'):
444 self.warn(
444 self.warn(
445 "could not find msgfmt executable, no translations "
445 "could not find msgfmt executable, no translations "
446 "will be built"
446 "will be built"
447 )
447 )
448 return
448 return
449
449
450 podir = 'i18n'
450 podir = 'i18n'
451 if not os.path.isdir(podir):
451 if not os.path.isdir(podir):
452 self.warn("could not find %s/ directory" % podir)
452 self.warn("could not find %s/ directory" % podir)
453 return
453 return
454
454
455 join = os.path.join
455 join = os.path.join
456 for po in os.listdir(podir):
456 for po in os.listdir(podir):
457 if not po.endswith('.po'):
457 if not po.endswith('.po'):
458 continue
458 continue
459 pofile = join(podir, po)
459 pofile = join(podir, po)
460 modir = join('locale', po[:-3], 'LC_MESSAGES')
460 modir = join('locale', po[:-3], 'LC_MESSAGES')
461 mofile = join(modir, 'hg.mo')
461 mofile = join(modir, 'hg.mo')
462 mobuildfile = join('mercurial', mofile)
462 mobuildfile = join('mercurial', mofile)
463 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
463 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
464 if sys.platform != 'sunos5':
464 if sys.platform != 'sunos5':
465 # msgfmt on Solaris does not know about -c
465 # msgfmt on Solaris does not know about -c
466 cmd.append('-c')
466 cmd.append('-c')
467 self.mkpath(join('mercurial', modir))
467 self.mkpath(join('mercurial', modir))
468 self.make_file([pofile], mobuildfile, spawn, (cmd,))
468 self.make_file([pofile], mobuildfile, spawn, (cmd,))
469
469
470
470
471 class hgdist(Distribution):
471 class hgdist(Distribution):
472 pure = False
472 pure = False
473 rust = False
473 rust = False
474 no_rust = False
474 no_rust = False
475 cffi = ispypy
475 cffi = ispypy
476
476
477 global_options = Distribution.global_options + [
477 global_options = Distribution.global_options + [
478 ('pure', None, "use pure (slow) Python code instead of C extensions"),
478 ('pure', None, "use pure (slow) Python code instead of C extensions"),
479 ('rust', None, "use Rust extensions additionally to C extensions"),
479 ('rust', None, "use Rust extensions additionally to C extensions"),
480 (
480 (
481 'no-rust',
481 'no-rust',
482 None,
482 None,
483 "do not use Rust extensions additionally to C extensions",
483 "do not use Rust extensions additionally to C extensions",
484 ),
484 ),
485 ]
485 ]
486
486
487 negative_opt = Distribution.negative_opt.copy()
487 negative_opt = Distribution.negative_opt.copy()
488 boolean_options = ['pure', 'rust', 'no-rust']
488 boolean_options = ['pure', 'rust', 'no-rust']
489 negative_opt['no-rust'] = 'rust'
489 negative_opt['no-rust'] = 'rust'
490
490
491 def _set_command_options(self, command_obj, option_dict=None):
491 def _set_command_options(self, command_obj, option_dict=None):
492 # Not all distutils versions in the wild have boolean_options.
492 # Not all distutils versions in the wild have boolean_options.
493 # This should be cleaned up when we're Python 3 only.
493 # This should be cleaned up when we're Python 3 only.
494 command_obj.boolean_options = (
494 command_obj.boolean_options = (
495 getattr(command_obj, 'boolean_options', []) + self.boolean_options
495 getattr(command_obj, 'boolean_options', []) + self.boolean_options
496 )
496 )
497 return Distribution._set_command_options(
497 return Distribution._set_command_options(
498 self, command_obj, option_dict=option_dict
498 self, command_obj, option_dict=option_dict
499 )
499 )
500
500
501 def parse_command_line(self):
501 def parse_command_line(self):
502 ret = Distribution.parse_command_line(self)
502 ret = Distribution.parse_command_line(self)
503 if not (self.rust or self.no_rust):
503 if not (self.rust or self.no_rust):
504 hgrustext = os.environ.get('HGWITHRUSTEXT')
504 hgrustext = os.environ.get('HGWITHRUSTEXT')
505 # TODO record it for proper rebuild upon changes
505 # TODO record it for proper rebuild upon changes
506 # (see mercurial/__modulepolicy__.py)
506 # (see mercurial/__modulepolicy__.py)
507 if hgrustext != 'cpython' and hgrustext is not None:
507 if hgrustext != 'cpython' and hgrustext is not None:
508 if hgrustext:
508 if hgrustext:
509 msg = 'unkown HGWITHRUSTEXT value: %s' % hgrustext
509 msg = 'unkown HGWITHRUSTEXT value: %s' % hgrustext
510 printf(msg, file=sys.stderr)
510 printf(msg, file=sys.stderr)
511 hgrustext = None
511 hgrustext = None
512 self.rust = hgrustext is not None
512 self.rust = hgrustext is not None
513 self.no_rust = not self.rust
513 self.no_rust = not self.rust
514 return ret
514 return ret
515
515
516 def has_ext_modules(self):
516 def has_ext_modules(self):
517 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
517 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
518 # too late for some cases
518 # too late for some cases
519 return not self.pure and Distribution.has_ext_modules(self)
519 return not self.pure and Distribution.has_ext_modules(self)
520
520
521
521
522 # This is ugly as a one-liner. So use a variable.
522 # This is ugly as a one-liner. So use a variable.
523 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
523 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
524 buildextnegops['no-zstd'] = 'zstd'
524 buildextnegops['no-zstd'] = 'zstd'
525 buildextnegops['no-rust'] = 'rust'
525 buildextnegops['no-rust'] = 'rust'
526
526
527
527
528 class hgbuildext(build_ext):
528 class hgbuildext(build_ext):
529 user_options = build_ext.user_options + [
529 user_options = build_ext.user_options + [
530 ('zstd', None, 'compile zstd bindings [default]'),
530 ('zstd', None, 'compile zstd bindings [default]'),
531 ('no-zstd', None, 'do not compile zstd bindings'),
531 ('no-zstd', None, 'do not compile zstd bindings'),
532 (
532 (
533 'rust',
533 'rust',
534 None,
534 None,
535 'compile Rust extensions if they are in use '
535 'compile Rust extensions if they are in use '
536 '(requires Cargo) [default]',
536 '(requires Cargo) [default]',
537 ),
537 ),
538 ('no-rust', None, 'do not compile Rust extensions'),
538 ('no-rust', None, 'do not compile Rust extensions'),
539 ]
539 ]
540
540
541 boolean_options = build_ext.boolean_options + ['zstd', 'rust']
541 boolean_options = build_ext.boolean_options + ['zstd', 'rust']
542 negative_opt = buildextnegops
542 negative_opt = buildextnegops
543
543
544 def initialize_options(self):
544 def initialize_options(self):
545 self.zstd = True
545 self.zstd = True
546 self.rust = True
546 self.rust = True
547
547
548 return build_ext.initialize_options(self)
548 return build_ext.initialize_options(self)
549
549
550 def finalize_options(self):
550 def finalize_options(self):
551 # Unless overridden by the end user, build extensions in parallel.
551 # Unless overridden by the end user, build extensions in parallel.
552 # Only influences behavior on Python 3.5+.
552 # Only influences behavior on Python 3.5+.
553 if getattr(self, 'parallel', None) is None:
553 if getattr(self, 'parallel', None) is None:
554 self.parallel = True
554 self.parallel = True
555
555
556 return build_ext.finalize_options(self)
556 return build_ext.finalize_options(self)
557
557
558 def build_extensions(self):
558 def build_extensions(self):
559 ruststandalones = [
559 ruststandalones = [
560 e for e in self.extensions if isinstance(e, RustStandaloneExtension)
560 e for e in self.extensions if isinstance(e, RustStandaloneExtension)
561 ]
561 ]
562 self.extensions = [
562 self.extensions = [
563 e for e in self.extensions if e not in ruststandalones
563 e for e in self.extensions if e not in ruststandalones
564 ]
564 ]
565 # Filter out zstd if disabled via argument.
565 # Filter out zstd if disabled via argument.
566 if not self.zstd:
566 if not self.zstd:
567 self.extensions = [
567 self.extensions = [
568 e for e in self.extensions if e.name != 'mercurial.zstd'
568 e for e in self.extensions if e.name != 'mercurial.zstd'
569 ]
569 ]
570
570
571 # Build Rust standalon extensions if it'll be used
571 # Build Rust standalon extensions if it'll be used
572 # and its build is not explictely disabled (for external build
572 # and its build is not explictely disabled (for external build
573 # as Linux distributions would do)
573 # as Linux distributions would do)
574 if self.distribution.rust and self.rust:
574 if self.distribution.rust and self.rust:
575 for rustext in ruststandalones:
575 for rustext in ruststandalones:
576 rustext.build('' if self.inplace else self.build_lib)
576 rustext.build('' if self.inplace else self.build_lib)
577
577
578 return build_ext.build_extensions(self)
578 return build_ext.build_extensions(self)
579
579
580 def build_extension(self, ext):
580 def build_extension(self, ext):
581 if (
581 if (
582 self.distribution.rust
582 self.distribution.rust
583 and self.rust
583 and self.rust
584 and isinstance(ext, RustExtension)
584 and isinstance(ext, RustExtension)
585 ):
585 ):
586 ext.rustbuild()
586 ext.rustbuild()
587 try:
587 try:
588 build_ext.build_extension(self, ext)
588 build_ext.build_extension(self, ext)
589 except CCompilerError:
589 except CCompilerError:
590 if not getattr(ext, 'optional', False):
590 if not getattr(ext, 'optional', False):
591 raise
591 raise
592 log.warn(
592 log.warn(
593 "Failed to build optional extension '%s' (skipping)", ext.name
593 "Failed to build optional extension '%s' (skipping)", ext.name
594 )
594 )
595
595
596
596
597 class hgbuildscripts(build_scripts):
597 class hgbuildscripts(build_scripts):
598 def run(self):
598 def run(self):
599 if os.name != 'nt' or self.distribution.pure:
599 if os.name != 'nt' or self.distribution.pure:
600 return build_scripts.run(self)
600 return build_scripts.run(self)
601
601
602 exebuilt = False
602 exebuilt = False
603 try:
603 try:
604 self.run_command('build_hgexe')
604 self.run_command('build_hgexe')
605 exebuilt = True
605 exebuilt = True
606 except (DistutilsError, CCompilerError):
606 except (DistutilsError, CCompilerError):
607 log.warn('failed to build optional hg.exe')
607 log.warn('failed to build optional hg.exe')
608
608
609 if exebuilt:
609 if exebuilt:
610 # Copying hg.exe to the scripts build directory ensures it is
610 # Copying hg.exe to the scripts build directory ensures it is
611 # installed by the install_scripts command.
611 # installed by the install_scripts command.
612 hgexecommand = self.get_finalized_command('build_hgexe')
612 hgexecommand = self.get_finalized_command('build_hgexe')
613 dest = os.path.join(self.build_dir, 'hg.exe')
613 dest = os.path.join(self.build_dir, 'hg.exe')
614 self.mkpath(self.build_dir)
614 self.mkpath(self.build_dir)
615 self.copy_file(hgexecommand.hgexepath, dest)
615 self.copy_file(hgexecommand.hgexepath, dest)
616
616
617 # Remove hg.bat because it is redundant with hg.exe.
617 # Remove hg.bat because it is redundant with hg.exe.
618 self.scripts.remove('contrib/win32/hg.bat')
618 self.scripts.remove('contrib/win32/hg.bat')
619
619
620 return build_scripts.run(self)
620 return build_scripts.run(self)
621
621
622
622
623 class hgbuildpy(build_py):
623 class hgbuildpy(build_py):
624 def finalize_options(self):
624 def finalize_options(self):
625 build_py.finalize_options(self)
625 build_py.finalize_options(self)
626
626
627 if self.distribution.pure:
627 if self.distribution.pure:
628 self.distribution.ext_modules = []
628 self.distribution.ext_modules = []
629 elif self.distribution.cffi:
629 elif self.distribution.cffi:
630 from mercurial.cffi import (
630 from mercurial.cffi import (
631 bdiffbuild,
631 bdiffbuild,
632 mpatchbuild,
632 mpatchbuild,
633 )
633 )
634
634
635 exts = [
635 exts = [
636 mpatchbuild.ffi.distutils_extension(),
636 mpatchbuild.ffi.distutils_extension(),
637 bdiffbuild.ffi.distutils_extension(),
637 bdiffbuild.ffi.distutils_extension(),
638 ]
638 ]
639 # cffi modules go here
639 # cffi modules go here
640 if sys.platform == 'darwin':
640 if sys.platform == 'darwin':
641 from mercurial.cffi import osutilbuild
641 from mercurial.cffi import osutilbuild
642
642
643 exts.append(osutilbuild.ffi.distutils_extension())
643 exts.append(osutilbuild.ffi.distutils_extension())
644 self.distribution.ext_modules = exts
644 self.distribution.ext_modules = exts
645 else:
645 else:
646 h = os.path.join(get_python_inc(), 'Python.h')
646 h = os.path.join(get_python_inc(), 'Python.h')
647 if not os.path.exists(h):
647 if not os.path.exists(h):
648 raise SystemExit(
648 raise SystemExit(
649 'Python headers are required to build '
649 'Python headers are required to build '
650 'Mercurial but weren\'t found in %s' % h
650 'Mercurial but weren\'t found in %s' % h
651 )
651 )
652
652
653 def run(self):
653 def run(self):
654 basepath = os.path.join(self.build_lib, 'mercurial')
654 basepath = os.path.join(self.build_lib, 'mercurial')
655 self.mkpath(basepath)
655 self.mkpath(basepath)
656
656
657 rust = self.distribution.rust
657 rust = self.distribution.rust
658 if self.distribution.pure:
658 if self.distribution.pure:
659 modulepolicy = 'py'
659 modulepolicy = 'py'
660 elif self.build_lib == '.':
660 elif self.build_lib == '.':
661 # in-place build should run without rebuilding and Rust extensions
661 # in-place build should run without rebuilding and Rust extensions
662 modulepolicy = 'rust+c-allow' if rust else 'allow'
662 modulepolicy = 'rust+c-allow' if rust else 'allow'
663 else:
663 else:
664 modulepolicy = 'rust+c' if rust else 'c'
664 modulepolicy = 'rust+c' if rust else 'c'
665
665
666 content = b''.join(
666 content = b''.join(
667 [
667 [
668 b'# this file is autogenerated by setup.py\n',
668 b'# this file is autogenerated by setup.py\n',
669 b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
669 b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
670 ]
670 ]
671 )
671 )
672 write_if_changed(os.path.join(basepath, '__modulepolicy__.py'), content)
672 write_if_changed(os.path.join(basepath, '__modulepolicy__.py'), content)
673
673
674 build_py.run(self)
674 build_py.run(self)
675
675
676
676
677 class buildhgextindex(Command):
677 class buildhgextindex(Command):
678 description = 'generate prebuilt index of hgext (for frozen package)'
678 description = 'generate prebuilt index of hgext (for frozen package)'
679 user_options = []
679 user_options = []
680 _indexfilename = 'hgext/__index__.py'
680 _indexfilename = 'hgext/__index__.py'
681
681
682 def initialize_options(self):
682 def initialize_options(self):
683 pass
683 pass
684
684
685 def finalize_options(self):
685 def finalize_options(self):
686 pass
686 pass
687
687
688 def run(self):
688 def run(self):
689 if os.path.exists(self._indexfilename):
689 if os.path.exists(self._indexfilename):
690 with open(self._indexfilename, 'w') as f:
690 with open(self._indexfilename, 'w') as f:
691 f.write('# empty\n')
691 f.write('# empty\n')
692
692
693 # here no extension enabled, disabled() lists up everything
693 # here no extension enabled, disabled() lists up everything
694 code = (
694 code = (
695 'import pprint; from mercurial import extensions; '
695 'import pprint; from mercurial import extensions; '
696 'ext = extensions.disabled();'
696 'ext = extensions.disabled();'
697 'ext.pop("__index__", None);'
697 'ext.pop("__index__", None);'
698 'pprint.pprint(ext)'
698 'pprint.pprint(ext)'
699 )
699 )
700 returncode, out, err = runcmd(
700 returncode, out, err = runcmd(
701 [sys.executable, '-c', code], localhgenv()
701 [sys.executable, '-c', code], localhgenv()
702 )
702 )
703 if err or returncode != 0:
703 if err or returncode != 0:
704 raise DistutilsExecError(err)
704 raise DistutilsExecError(err)
705
705
706 with open(self._indexfilename, 'wb') as f:
706 with open(self._indexfilename, 'wb') as f:
707 f.write(b'# this file is autogenerated by setup.py\n')
707 f.write(b'# this file is autogenerated by setup.py\n')
708 f.write(b'docs = ')
708 f.write(b'docs = ')
709 f.write(out)
709 f.write(out)
710
710
711
711
712 class buildhgexe(build_ext):
712 class buildhgexe(build_ext):
713 description = 'compile hg.exe from mercurial/exewrapper.c'
713 description = 'compile hg.exe from mercurial/exewrapper.c'
714 user_options = build_ext.user_options + [
714 user_options = build_ext.user_options + [
715 (
715 (
716 'long-paths-support',
716 'long-paths-support',
717 None,
717 None,
718 'enable support for long paths on '
718 'enable support for long paths on '
719 'Windows (off by default and '
719 'Windows (off by default and '
720 'experimental)',
720 'experimental)',
721 ),
721 ),
722 ]
722 ]
723
723
724 LONG_PATHS_MANIFEST = """
724 LONG_PATHS_MANIFEST = """
725 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
725 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
726 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
726 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
727 <application>
727 <application>
728 <windowsSettings
728 <windowsSettings
729 xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
729 xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
730 <ws2:longPathAware>true</ws2:longPathAware>
730 <ws2:longPathAware>true</ws2:longPathAware>
731 </windowsSettings>
731 </windowsSettings>
732 </application>
732 </application>
733 </assembly>"""
733 </assembly>"""
734
734
735 def initialize_options(self):
735 def initialize_options(self):
736 build_ext.initialize_options(self)
736 build_ext.initialize_options(self)
737 self.long_paths_support = False
737 self.long_paths_support = False
738
738
739 def build_extensions(self):
739 def build_extensions(self):
740 if os.name != 'nt':
740 if os.name != 'nt':
741 return
741 return
742 if isinstance(self.compiler, HackedMingw32CCompiler):
742 if isinstance(self.compiler, HackedMingw32CCompiler):
743 self.compiler.compiler_so = self.compiler.compiler # no -mdll
743 self.compiler.compiler_so = self.compiler.compiler # no -mdll
744 self.compiler.dll_libraries = [] # no -lmsrvc90
744 self.compiler.dll_libraries = [] # no -lmsrvc90
745
745
746 pythonlib = None
746 pythonlib = None
747
747
748 if getattr(sys, 'dllhandle', None):
748 if getattr(sys, 'dllhandle', None):
749 # Different Python installs can have different Python library
749 # Different Python installs can have different Python library
750 # names. e.g. the official CPython distribution uses pythonXY.dll
750 # names. e.g. the official CPython distribution uses pythonXY.dll
751 # and MinGW uses libpythonX.Y.dll.
751 # and MinGW uses libpythonX.Y.dll.
752 _kernel32 = ctypes.windll.kernel32
752 _kernel32 = ctypes.windll.kernel32
753 _kernel32.GetModuleFileNameA.argtypes = [
753 _kernel32.GetModuleFileNameA.argtypes = [
754 ctypes.c_void_p,
754 ctypes.c_void_p,
755 ctypes.c_void_p,
755 ctypes.c_void_p,
756 ctypes.c_ulong,
756 ctypes.c_ulong,
757 ]
757 ]
758 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
758 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
759 size = 1000
759 size = 1000
760 buf = ctypes.create_string_buffer(size + 1)
760 buf = ctypes.create_string_buffer(size + 1)
761 filelen = _kernel32.GetModuleFileNameA(
761 filelen = _kernel32.GetModuleFileNameA(
762 sys.dllhandle, ctypes.byref(buf), size
762 sys.dllhandle, ctypes.byref(buf), size
763 )
763 )
764
764
765 if filelen > 0 and filelen != size:
765 if filelen > 0 and filelen != size:
766 dllbasename = os.path.basename(buf.value)
766 dllbasename = os.path.basename(buf.value)
767 if not dllbasename.lower().endswith(b'.dll'):
767 if not dllbasename.lower().endswith(b'.dll'):
768 raise SystemExit(
768 raise SystemExit(
769 'Python DLL does not end with .dll: %s' % dllbasename
769 'Python DLL does not end with .dll: %s' % dllbasename
770 )
770 )
771 pythonlib = dllbasename[:-4]
771 pythonlib = dllbasename[:-4]
772
772
773 if not pythonlib:
773 if not pythonlib:
774 log.warn(
774 log.warn(
775 'could not determine Python DLL filename; assuming pythonXY'
775 'could not determine Python DLL filename; assuming pythonXY'
776 )
776 )
777
777
778 hv = sys.hexversion
778 hv = sys.hexversion
779 pythonlib = b'python%d%d' % (hv >> 24, (hv >> 16) & 0xFF)
779 pythonlib = b'python%d%d' % (hv >> 24, (hv >> 16) & 0xFF)
780
780
781 log.info('using %s as Python library name' % pythonlib)
781 log.info('using %s as Python library name' % pythonlib)
782 with open('mercurial/hgpythonlib.h', 'wb') as f:
782 with open('mercurial/hgpythonlib.h', 'wb') as f:
783 f.write(b'/* this file is autogenerated by setup.py */\n')
783 f.write(b'/* this file is autogenerated by setup.py */\n')
784 f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib)
784 f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib)
785
785
786 macros = None
786 macros = None
787 if sys.version_info[0] >= 3:
787 if sys.version_info[0] >= 3:
788 macros = [('_UNICODE', None), ('UNICODE', None)]
788 macros = [('_UNICODE', None), ('UNICODE', None)]
789
789
790 objects = self.compiler.compile(
790 objects = self.compiler.compile(
791 ['mercurial/exewrapper.c'],
791 ['mercurial/exewrapper.c'],
792 output_dir=self.build_temp,
792 output_dir=self.build_temp,
793 macros=macros,
793 macros=macros,
794 )
794 )
795 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
795 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
796 self.hgtarget = os.path.join(dir, 'hg')
796 self.hgtarget = os.path.join(dir, 'hg')
797 self.compiler.link_executable(
797 self.compiler.link_executable(
798 objects, self.hgtarget, libraries=[], output_dir=self.build_temp
798 objects, self.hgtarget, libraries=[], output_dir=self.build_temp
799 )
799 )
800 if self.long_paths_support:
800 if self.long_paths_support:
801 self.addlongpathsmanifest()
801 self.addlongpathsmanifest()
802
802
803 def addlongpathsmanifest(self):
803 def addlongpathsmanifest(self):
804 r"""Add manifest pieces so that hg.exe understands long paths
804 r"""Add manifest pieces so that hg.exe understands long paths
805
805
806 This is an EXPERIMENTAL feature, use with care.
806 This is an EXPERIMENTAL feature, use with care.
807 To enable long paths support, one needs to do two things:
807 To enable long paths support, one needs to do two things:
808 - build Mercurial with --long-paths-support option
808 - build Mercurial with --long-paths-support option
809 - change HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\
809 - change HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\
810 LongPathsEnabled to have value 1.
810 LongPathsEnabled to have value 1.
811
811
812 Please ignore 'warning 81010002: Unrecognized Element "longPathAware"';
812 Please ignore 'warning 81010002: Unrecognized Element "longPathAware"';
813 it happens because Mercurial uses mt.exe circa 2008, which is not
813 it happens because Mercurial uses mt.exe circa 2008, which is not
814 yet aware of long paths support in the manifest (I think so at least).
814 yet aware of long paths support in the manifest (I think so at least).
815 This does not stop mt.exe from embedding/merging the XML properly.
815 This does not stop mt.exe from embedding/merging the XML properly.
816
816
817 Why resource #1 should be used for .exe manifests? I don't know and
817 Why resource #1 should be used for .exe manifests? I don't know and
818 wasn't able to find an explanation for mortals. But it seems to work.
818 wasn't able to find an explanation for mortals. But it seems to work.
819 """
819 """
820 exefname = self.compiler.executable_filename(self.hgtarget)
820 exefname = self.compiler.executable_filename(self.hgtarget)
821 fdauto, manfname = tempfile.mkstemp(suffix='.hg.exe.manifest')
821 fdauto, manfname = tempfile.mkstemp(suffix='.hg.exe.manifest')
822 os.close(fdauto)
822 os.close(fdauto)
823 with open(manfname, 'w') as f:
823 with open(manfname, 'w') as f:
824 f.write(self.LONG_PATHS_MANIFEST)
824 f.write(self.LONG_PATHS_MANIFEST)
825 log.info("long paths manifest is written to '%s'" % manfname)
825 log.info("long paths manifest is written to '%s'" % manfname)
826 inputresource = '-inputresource:%s;#1' % exefname
826 inputresource = '-inputresource:%s;#1' % exefname
827 outputresource = '-outputresource:%s;#1' % exefname
827 outputresource = '-outputresource:%s;#1' % exefname
828 log.info("running mt.exe to update hg.exe's manifest in-place")
828 log.info("running mt.exe to update hg.exe's manifest in-place")
829 # supplying both -manifest and -inputresource to mt.exe makes
829 # supplying both -manifest and -inputresource to mt.exe makes
830 # it merge the embedded and supplied manifests in the -outputresource
830 # it merge the embedded and supplied manifests in the -outputresource
831 self.spawn(
831 self.spawn(
832 [
832 [
833 'mt.exe',
833 'mt.exe',
834 '-nologo',
834 '-nologo',
835 '-manifest',
835 '-manifest',
836 manfname,
836 manfname,
837 inputresource,
837 inputresource,
838 outputresource,
838 outputresource,
839 ]
839 ]
840 )
840 )
841 log.info("done updating hg.exe's manifest")
841 log.info("done updating hg.exe's manifest")
842 os.remove(manfname)
842 os.remove(manfname)
843
843
844 @property
844 @property
845 def hgexepath(self):
845 def hgexepath(self):
846 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
846 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
847 return os.path.join(self.build_temp, dir, 'hg.exe')
847 return os.path.join(self.build_temp, dir, 'hg.exe')
848
848
849
849
850 class hgbuilddoc(Command):
850 class hgbuilddoc(Command):
851 description = 'build documentation'
851 description = 'build documentation'
852 user_options = [
852 user_options = [
853 ('man', None, 'generate man pages'),
853 ('man', None, 'generate man pages'),
854 ('html', None, 'generate html pages'),
854 ('html', None, 'generate html pages'),
855 ]
855 ]
856
856
857 def initialize_options(self):
857 def initialize_options(self):
858 self.man = None
858 self.man = None
859 self.html = None
859 self.html = None
860
860
861 def finalize_options(self):
861 def finalize_options(self):
862 # If --man or --html are set, only generate what we're told to.
862 # If --man or --html are set, only generate what we're told to.
863 # Otherwise generate everything.
863 # Otherwise generate everything.
864 have_subset = self.man is not None or self.html is not None
864 have_subset = self.man is not None or self.html is not None
865
865
866 if have_subset:
866 if have_subset:
867 self.man = True if self.man else False
867 self.man = True if self.man else False
868 self.html = True if self.html else False
868 self.html = True if self.html else False
869 else:
869 else:
870 self.man = True
870 self.man = True
871 self.html = True
871 self.html = True
872
872
873 def run(self):
873 def run(self):
874 def normalizecrlf(p):
874 def normalizecrlf(p):
875 with open(p, 'rb') as fh:
875 with open(p, 'rb') as fh:
876 orig = fh.read()
876 orig = fh.read()
877
877
878 if b'\r\n' not in orig:
878 if b'\r\n' not in orig:
879 return
879 return
880
880
881 log.info('normalizing %s to LF line endings' % p)
881 log.info('normalizing %s to LF line endings' % p)
882 with open(p, 'wb') as fh:
882 with open(p, 'wb') as fh:
883 fh.write(orig.replace(b'\r\n', b'\n'))
883 fh.write(orig.replace(b'\r\n', b'\n'))
884
884
885 def gentxt(root):
885 def gentxt(root):
886 txt = 'doc/%s.txt' % root
886 txt = 'doc/%s.txt' % root
887 log.info('generating %s' % txt)
887 log.info('generating %s' % txt)
888 res, out, err = runcmd(
888 res, out, err = runcmd(
889 [sys.executable, 'gendoc.py', root], os.environ, cwd='doc'
889 [sys.executable, 'gendoc.py', root], os.environ, cwd='doc'
890 )
890 )
891 if res:
891 if res:
892 raise SystemExit(
892 raise SystemExit(
893 'error running gendoc.py: %s' % '\n'.join([out, err])
893 'error running gendoc.py: %s' % '\n'.join([out, err])
894 )
894 )
895
895
896 with open(txt, 'wb') as fh:
896 with open(txt, 'wb') as fh:
897 fh.write(out)
897 fh.write(out)
898
898
899 def gengendoc(root):
899 def gengendoc(root):
900 gendoc = 'doc/%s.gendoc.txt' % root
900 gendoc = 'doc/%s.gendoc.txt' % root
901
901
902 log.info('generating %s' % gendoc)
902 log.info('generating %s' % gendoc)
903 res, out, err = runcmd(
903 res, out, err = runcmd(
904 [sys.executable, 'gendoc.py', '%s.gendoc' % root],
904 [sys.executable, 'gendoc.py', '%s.gendoc' % root],
905 os.environ,
905 os.environ,
906 cwd='doc',
906 cwd='doc',
907 )
907 )
908 if res:
908 if res:
909 raise SystemExit(
909 raise SystemExit(
910 'error running gendoc: %s' % '\n'.join([out, err])
910 'error running gendoc: %s' % '\n'.join([out, err])
911 )
911 )
912
912
913 with open(gendoc, 'wb') as fh:
913 with open(gendoc, 'wb') as fh:
914 fh.write(out)
914 fh.write(out)
915
915
916 def genman(root):
916 def genman(root):
917 log.info('generating doc/%s' % root)
917 log.info('generating doc/%s' % root)
918 res, out, err = runcmd(
918 res, out, err = runcmd(
919 [
919 [
920 sys.executable,
920 sys.executable,
921 'runrst',
921 'runrst',
922 'hgmanpage',
922 'hgmanpage',
923 '--halt',
923 '--halt',
924 'warning',
924 'warning',
925 '--strip-elements-with-class',
925 '--strip-elements-with-class',
926 'htmlonly',
926 'htmlonly',
927 '%s.txt' % root,
927 '%s.txt' % root,
928 root,
928 root,
929 ],
929 ],
930 os.environ,
930 os.environ,
931 cwd='doc',
931 cwd='doc',
932 )
932 )
933 if res:
933 if res:
934 raise SystemExit(
934 raise SystemExit(
935 'error running runrst: %s' % '\n'.join([out, err])
935 'error running runrst: %s' % '\n'.join([out, err])
936 )
936 )
937
937
938 normalizecrlf('doc/%s' % root)
938 normalizecrlf('doc/%s' % root)
939
939
940 def genhtml(root):
940 def genhtml(root):
941 log.info('generating doc/%s.html' % root)
941 log.info('generating doc/%s.html' % root)
942 res, out, err = runcmd(
942 res, out, err = runcmd(
943 [
943 [
944 sys.executable,
944 sys.executable,
945 'runrst',
945 'runrst',
946 'html',
946 'html',
947 '--halt',
947 '--halt',
948 'warning',
948 'warning',
949 '--link-stylesheet',
949 '--link-stylesheet',
950 '--stylesheet-path',
950 '--stylesheet-path',
951 'style.css',
951 'style.css',
952 '%s.txt' % root,
952 '%s.txt' % root,
953 '%s.html' % root,
953 '%s.html' % root,
954 ],
954 ],
955 os.environ,
955 os.environ,
956 cwd='doc',
956 cwd='doc',
957 )
957 )
958 if res:
958 if res:
959 raise SystemExit(
959 raise SystemExit(
960 'error running runrst: %s' % '\n'.join([out, err])
960 'error running runrst: %s' % '\n'.join([out, err])
961 )
961 )
962
962
963 normalizecrlf('doc/%s.html' % root)
963 normalizecrlf('doc/%s.html' % root)
964
964
965 # This logic is duplicated in doc/Makefile.
965 # This logic is duplicated in doc/Makefile.
966 sources = {
966 sources = {
967 f
967 f
968 for f in os.listdir('mercurial/helptext')
968 for f in os.listdir('mercurial/helptext')
969 if re.search(r'[0-9]\.txt$', f)
969 if re.search(r'[0-9]\.txt$', f)
970 }
970 }
971
971
972 # common.txt is a one-off.
972 # common.txt is a one-off.
973 gentxt('common')
973 gentxt('common')
974
974
975 for source in sorted(sources):
975 for source in sorted(sources):
976 assert source[-4:] == '.txt'
976 assert source[-4:] == '.txt'
977 root = source[:-4]
977 root = source[:-4]
978
978
979 gentxt(root)
979 gentxt(root)
980 gengendoc(root)
980 gengendoc(root)
981
981
982 if self.man:
982 if self.man:
983 genman(root)
983 genman(root)
984 if self.html:
984 if self.html:
985 genhtml(root)
985 genhtml(root)
986
986
987
987
988 class hginstall(install):
988 class hginstall(install):
989
989
990 user_options = install.user_options + [
990 user_options = install.user_options + [
991 (
991 (
992 'old-and-unmanageable',
992 'old-and-unmanageable',
993 None,
993 None,
994 'noop, present for eggless setuptools compat',
994 'noop, present for eggless setuptools compat',
995 ),
995 ),
996 (
996 (
997 'single-version-externally-managed',
997 'single-version-externally-managed',
998 None,
998 None,
999 'noop, present for eggless setuptools compat',
999 'noop, present for eggless setuptools compat',
1000 ),
1000 ),
1001 ]
1001 ]
1002
1002
1003 # Also helps setuptools not be sad while we refuse to create eggs.
1003 # Also helps setuptools not be sad while we refuse to create eggs.
1004 single_version_externally_managed = True
1004 single_version_externally_managed = True
1005
1005
1006 def get_sub_commands(self):
1006 def get_sub_commands(self):
1007 # Screen out egg related commands to prevent egg generation. But allow
1007 # Screen out egg related commands to prevent egg generation. But allow
1008 # mercurial.egg-info generation, since that is part of modern
1008 # mercurial.egg-info generation, since that is part of modern
1009 # packaging.
1009 # packaging.
1010 excl = {'bdist_egg'}
1010 excl = {'bdist_egg'}
1011 return filter(lambda x: x not in excl, install.get_sub_commands(self))
1011 return filter(lambda x: x not in excl, install.get_sub_commands(self))
1012
1012
1013
1013
1014 class hginstalllib(install_lib):
1014 class hginstalllib(install_lib):
1015 '''
1015 '''
1016 This is a specialization of install_lib that replaces the copy_file used
1016 This is a specialization of install_lib that replaces the copy_file used
1017 there so that it supports setting the mode of files after copying them,
1017 there so that it supports setting the mode of files after copying them,
1018 instead of just preserving the mode that the files originally had. If your
1018 instead of just preserving the mode that the files originally had. If your
1019 system has a umask of something like 027, preserving the permissions when
1019 system has a umask of something like 027, preserving the permissions when
1020 copying will lead to a broken install.
1020 copying will lead to a broken install.
1021
1021
1022 Note that just passing keep_permissions=False to copy_file would be
1022 Note that just passing keep_permissions=False to copy_file would be
1023 insufficient, as it might still be applying a umask.
1023 insufficient, as it might still be applying a umask.
1024 '''
1024 '''
1025
1025
1026 def run(self):
1026 def run(self):
1027 realcopyfile = file_util.copy_file
1027 realcopyfile = file_util.copy_file
1028
1028
1029 def copyfileandsetmode(*args, **kwargs):
1029 def copyfileandsetmode(*args, **kwargs):
1030 src, dst = args[0], args[1]
1030 src, dst = args[0], args[1]
1031 dst, copied = realcopyfile(*args, **kwargs)
1031 dst, copied = realcopyfile(*args, **kwargs)
1032 if copied:
1032 if copied:
1033 st = os.stat(src)
1033 st = os.stat(src)
1034 # Persist executable bit (apply it to group and other if user
1034 # Persist executable bit (apply it to group and other if user
1035 # has it)
1035 # has it)
1036 if st[stat.ST_MODE] & stat.S_IXUSR:
1036 if st[stat.ST_MODE] & stat.S_IXUSR:
1037 setmode = int('0755', 8)
1037 setmode = int('0755', 8)
1038 else:
1038 else:
1039 setmode = int('0644', 8)
1039 setmode = int('0644', 8)
1040 m = stat.S_IMODE(st[stat.ST_MODE])
1040 m = stat.S_IMODE(st[stat.ST_MODE])
1041 m = (m & ~int('0777', 8)) | setmode
1041 m = (m & ~int('0777', 8)) | setmode
1042 os.chmod(dst, m)
1042 os.chmod(dst, m)
1043
1043
1044 file_util.copy_file = copyfileandsetmode
1044 file_util.copy_file = copyfileandsetmode
1045 try:
1045 try:
1046 install_lib.run(self)
1046 install_lib.run(self)
1047 finally:
1047 finally:
1048 file_util.copy_file = realcopyfile
1048 file_util.copy_file = realcopyfile
1049
1049
1050
1050
1051 class hginstallscripts(install_scripts):
1051 class hginstallscripts(install_scripts):
1052 '''
1052 '''
1053 This is a specialization of install_scripts that replaces the @LIBDIR@ with
1053 This is a specialization of install_scripts that replaces the @LIBDIR@ with
1054 the configured directory for modules. If possible, the path is made relative
1054 the configured directory for modules. If possible, the path is made relative
1055 to the directory for scripts.
1055 to the directory for scripts.
1056 '''
1056 '''
1057
1057
1058 def initialize_options(self):
1058 def initialize_options(self):
1059 install_scripts.initialize_options(self)
1059 install_scripts.initialize_options(self)
1060
1060
1061 self.install_lib = None
1061 self.install_lib = None
1062
1062
1063 def finalize_options(self):
1063 def finalize_options(self):
1064 install_scripts.finalize_options(self)
1064 install_scripts.finalize_options(self)
1065 self.set_undefined_options('install', ('install_lib', 'install_lib'))
1065 self.set_undefined_options('install', ('install_lib', 'install_lib'))
1066
1066
1067 def run(self):
1067 def run(self):
1068 install_scripts.run(self)
1068 install_scripts.run(self)
1069
1069
1070 # It only makes sense to replace @LIBDIR@ with the install path if
1070 # It only makes sense to replace @LIBDIR@ with the install path if
1071 # the install path is known. For wheels, the logic below calculates
1071 # the install path is known. For wheels, the logic below calculates
1072 # the libdir to be "../..". This is because the internal layout of a
1072 # the libdir to be "../..". This is because the internal layout of a
1073 # wheel archive looks like:
1073 # wheel archive looks like:
1074 #
1074 #
1075 # mercurial-3.6.1.data/scripts/hg
1075 # mercurial-3.6.1.data/scripts/hg
1076 # mercurial/__init__.py
1076 # mercurial/__init__.py
1077 #
1077 #
1078 # When installing wheels, the subdirectories of the "<pkg>.data"
1078 # When installing wheels, the subdirectories of the "<pkg>.data"
1079 # directory are translated to system local paths and files therein
1079 # directory are translated to system local paths and files therein
1080 # are copied in place. The mercurial/* files are installed into the
1080 # are copied in place. The mercurial/* files are installed into the
1081 # site-packages directory. However, the site-packages directory
1081 # site-packages directory. However, the site-packages directory
1082 # isn't known until wheel install time. This means we have no clue
1082 # isn't known until wheel install time. This means we have no clue
1083 # at wheel generation time what the installed site-packages directory
1083 # at wheel generation time what the installed site-packages directory
1084 # will be. And, wheels don't appear to provide the ability to register
1084 # will be. And, wheels don't appear to provide the ability to register
1085 # custom code to run during wheel installation. This all means that
1085 # custom code to run during wheel installation. This all means that
1086 # we can't reliably set the libdir in wheels: the default behavior
1086 # we can't reliably set the libdir in wheels: the default behavior
1087 # of looking in sys.path must do.
1087 # of looking in sys.path must do.
1088
1088
1089 if (
1089 if (
1090 os.path.splitdrive(self.install_dir)[0]
1090 os.path.splitdrive(self.install_dir)[0]
1091 != os.path.splitdrive(self.install_lib)[0]
1091 != os.path.splitdrive(self.install_lib)[0]
1092 ):
1092 ):
1093 # can't make relative paths from one drive to another, so use an
1093 # can't make relative paths from one drive to another, so use an
1094 # absolute path instead
1094 # absolute path instead
1095 libdir = self.install_lib
1095 libdir = self.install_lib
1096 else:
1096 else:
1097 libdir = os.path.relpath(self.install_lib, self.install_dir)
1097 libdir = os.path.relpath(self.install_lib, self.install_dir)
1098
1098
1099 for outfile in self.outfiles:
1099 for outfile in self.outfiles:
1100 with open(outfile, 'rb') as fp:
1100 with open(outfile, 'rb') as fp:
1101 data = fp.read()
1101 data = fp.read()
1102
1102
1103 # skip binary files
1103 # skip binary files
1104 if b'\0' in data:
1104 if b'\0' in data:
1105 continue
1105 continue
1106
1106
1107 # During local installs, the shebang will be rewritten to the final
1107 # During local installs, the shebang will be rewritten to the final
1108 # install path. During wheel packaging, the shebang has a special
1108 # install path. During wheel packaging, the shebang has a special
1109 # value.
1109 # value.
1110 if data.startswith(b'#!python'):
1110 if data.startswith(b'#!python'):
1111 log.info(
1111 log.info(
1112 'not rewriting @LIBDIR@ in %s because install path '
1112 'not rewriting @LIBDIR@ in %s because install path '
1113 'not known' % outfile
1113 'not known' % outfile
1114 )
1114 )
1115 continue
1115 continue
1116
1116
1117 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
1117 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
1118 with open(outfile, 'wb') as fp:
1118 with open(outfile, 'wb') as fp:
1119 fp.write(data)
1119 fp.write(data)
1120
1120
1121
1121
1122 # virtualenv installs custom distutils/__init__.py and
1122 # virtualenv installs custom distutils/__init__.py and
1123 # distutils/distutils.cfg files which essentially proxy back to the
1123 # distutils/distutils.cfg files which essentially proxy back to the
1124 # "real" distutils in the main Python install. The presence of this
1124 # "real" distutils in the main Python install. The presence of this
1125 # directory causes py2exe to pick up the "hacked" distutils package
1125 # directory causes py2exe to pick up the "hacked" distutils package
1126 # from the virtualenv and "import distutils" will fail from the py2exe
1126 # from the virtualenv and "import distutils" will fail from the py2exe
1127 # build because the "real" distutils files can't be located.
1127 # build because the "real" distutils files can't be located.
1128 #
1128 #
1129 # We work around this by monkeypatching the py2exe code finding Python
1129 # We work around this by monkeypatching the py2exe code finding Python
1130 # modules to replace the found virtualenv distutils modules with the
1130 # modules to replace the found virtualenv distutils modules with the
1131 # original versions via filesystem scanning. This is a bit hacky. But
1131 # original versions via filesystem scanning. This is a bit hacky. But
1132 # it allows us to use virtualenvs for py2exe packaging, which is more
1132 # it allows us to use virtualenvs for py2exe packaging, which is more
1133 # deterministic and reproducible.
1133 # deterministic and reproducible.
1134 #
1134 #
1135 # It's worth noting that the common StackOverflow suggestions for this
1135 # It's worth noting that the common StackOverflow suggestions for this
1136 # problem involve copying the original distutils files into the
1136 # problem involve copying the original distutils files into the
1137 # virtualenv or into the staging directory after setup() is invoked.
1137 # virtualenv or into the staging directory after setup() is invoked.
1138 # The former is very brittle and can easily break setup(). Our hacking
1138 # The former is very brittle and can easily break setup(). Our hacking
1139 # of the found modules routine has a similar result as copying the files
1139 # of the found modules routine has a similar result as copying the files
1140 # manually. But it makes fewer assumptions about how py2exe works and
1140 # manually. But it makes fewer assumptions about how py2exe works and
1141 # is less brittle.
1141 # is less brittle.
1142
1142
1143 # This only catches virtualenvs made with virtualenv (as opposed to
1143 # This only catches virtualenvs made with virtualenv (as opposed to
1144 # venv, which is likely what Python 3 uses).
1144 # venv, which is likely what Python 3 uses).
1145 py2exehacked = py2exeloaded and getattr(sys, 'real_prefix', None) is not None
1145 py2exehacked = py2exeloaded and getattr(sys, 'real_prefix', None) is not None
1146
1146
1147 if py2exehacked:
1147 if py2exehacked:
1148 from distutils.command.py2exe import py2exe as buildpy2exe
1148 from distutils.command.py2exe import py2exe as buildpy2exe
1149 from py2exe.mf import Module as py2exemodule
1149 from py2exe.mf import Module as py2exemodule
1150
1150
1151 class hgbuildpy2exe(buildpy2exe):
1151 class hgbuildpy2exe(buildpy2exe):
1152 def find_needed_modules(self, mf, files, modules):
1152 def find_needed_modules(self, mf, files, modules):
1153 res = buildpy2exe.find_needed_modules(self, mf, files, modules)
1153 res = buildpy2exe.find_needed_modules(self, mf, files, modules)
1154
1154
1155 # Replace virtualenv's distutils modules with the real ones.
1155 # Replace virtualenv's distutils modules with the real ones.
1156 modules = {}
1156 modules = {}
1157 for k, v in res.modules.items():
1157 for k, v in res.modules.items():
1158 if k != 'distutils' and not k.startswith('distutils.'):
1158 if k != 'distutils' and not k.startswith('distutils.'):
1159 modules[k] = v
1159 modules[k] = v
1160
1160
1161 res.modules = modules
1161 res.modules = modules
1162
1162
1163 import opcode
1163 import opcode
1164
1164
1165 distutilsreal = os.path.join(
1165 distutilsreal = os.path.join(
1166 os.path.dirname(opcode.__file__), 'distutils'
1166 os.path.dirname(opcode.__file__), 'distutils'
1167 )
1167 )
1168
1168
1169 for root, dirs, files in os.walk(distutilsreal):
1169 for root, dirs, files in os.walk(distutilsreal):
1170 for f in sorted(files):
1170 for f in sorted(files):
1171 if not f.endswith('.py'):
1171 if not f.endswith('.py'):
1172 continue
1172 continue
1173
1173
1174 full = os.path.join(root, f)
1174 full = os.path.join(root, f)
1175
1175
1176 parents = ['distutils']
1176 parents = ['distutils']
1177
1177
1178 if root != distutilsreal:
1178 if root != distutilsreal:
1179 rel = os.path.relpath(root, distutilsreal)
1179 rel = os.path.relpath(root, distutilsreal)
1180 parents.extend(p for p in rel.split(os.sep))
1180 parents.extend(p for p in rel.split(os.sep))
1181
1181
1182 modname = '%s.%s' % ('.'.join(parents), f[:-3])
1182 modname = '%s.%s' % ('.'.join(parents), f[:-3])
1183
1183
1184 if modname.startswith('distutils.tests.'):
1184 if modname.startswith('distutils.tests.'):
1185 continue
1185 continue
1186
1186
1187 if modname.endswith('.__init__'):
1187 if modname.endswith('.__init__'):
1188 modname = modname[: -len('.__init__')]
1188 modname = modname[: -len('.__init__')]
1189 path = os.path.dirname(full)
1189 path = os.path.dirname(full)
1190 else:
1190 else:
1191 path = None
1191 path = None
1192
1192
1193 res.modules[modname] = py2exemodule(
1193 res.modules[modname] = py2exemodule(
1194 modname, full, path=path
1194 modname, full, path=path
1195 )
1195 )
1196
1196
1197 if 'distutils' not in res.modules:
1197 if 'distutils' not in res.modules:
1198 raise SystemExit('could not find distutils modules')
1198 raise SystemExit('could not find distutils modules')
1199
1199
1200 return res
1200 return res
1201
1201
1202
1202
1203 cmdclass = {
1203 cmdclass = {
1204 'build': hgbuild,
1204 'build': hgbuild,
1205 'build_doc': hgbuilddoc,
1205 'build_doc': hgbuilddoc,
1206 'build_mo': hgbuildmo,
1206 'build_mo': hgbuildmo,
1207 'build_ext': hgbuildext,
1207 'build_ext': hgbuildext,
1208 'build_py': hgbuildpy,
1208 'build_py': hgbuildpy,
1209 'build_scripts': hgbuildscripts,
1209 'build_scripts': hgbuildscripts,
1210 'build_hgextindex': buildhgextindex,
1210 'build_hgextindex': buildhgextindex,
1211 'install': hginstall,
1211 'install': hginstall,
1212 'install_lib': hginstalllib,
1212 'install_lib': hginstalllib,
1213 'install_scripts': hginstallscripts,
1213 'install_scripts': hginstallscripts,
1214 'build_hgexe': buildhgexe,
1214 'build_hgexe': buildhgexe,
1215 }
1215 }
1216
1216
1217 if py2exehacked:
1217 if py2exehacked:
1218 cmdclass['py2exe'] = hgbuildpy2exe
1218 cmdclass['py2exe'] = hgbuildpy2exe
1219
1219
1220 packages = [
1220 packages = [
1221 'mercurial',
1221 'mercurial',
1222 'mercurial.cext',
1222 'mercurial.cext',
1223 'mercurial.cffi',
1223 'mercurial.cffi',
1224 'mercurial.defaultrc',
1224 'mercurial.defaultrc',
1225 'mercurial.helptext',
1225 'mercurial.helptext',
1226 'mercurial.helptext.internals',
1226 'mercurial.helptext.internals',
1227 'mercurial.hgweb',
1227 'mercurial.hgweb',
1228 'mercurial.interfaces',
1228 'mercurial.interfaces',
1229 'mercurial.pure',
1229 'mercurial.pure',
1230 'mercurial.thirdparty',
1230 'mercurial.thirdparty',
1231 'mercurial.thirdparty.attr',
1231 'mercurial.thirdparty.attr',
1232 'mercurial.thirdparty.zope',
1232 'mercurial.thirdparty.zope',
1233 'mercurial.thirdparty.zope.interface',
1233 'mercurial.thirdparty.zope.interface',
1234 'mercurial.utils',
1234 'mercurial.utils',
1235 'mercurial.revlogutils',
1235 'mercurial.revlogutils',
1236 'mercurial.testing',
1236 'mercurial.testing',
1237 'hgext',
1237 'hgext',
1238 'hgext.convert',
1238 'hgext.convert',
1239 'hgext.fsmonitor',
1239 'hgext.fsmonitor',
1240 'hgext.fastannotate',
1240 'hgext.fastannotate',
1241 'hgext.fsmonitor.pywatchman',
1241 'hgext.fsmonitor.pywatchman',
1242 'hgext.git',
1242 'hgext.git',
1243 'hgext.highlight',
1243 'hgext.highlight',
1244 'hgext.hooklib',
1244 'hgext.hooklib',
1245 'hgext.infinitepush',
1245 'hgext.infinitepush',
1246 'hgext.largefiles',
1246 'hgext.largefiles',
1247 'hgext.lfs',
1247 'hgext.lfs',
1248 'hgext.narrow',
1248 'hgext.narrow',
1249 'hgext.remotefilelog',
1249 'hgext.remotefilelog',
1250 'hgext.zeroconf',
1250 'hgext.zeroconf',
1251 'hgext3rd',
1251 'hgext3rd',
1252 'hgdemandimport',
1252 'hgdemandimport',
1253 ]
1253 ]
1254 if sys.version_info[0] == 2:
1254 if sys.version_info[0] == 2:
1255 packages.extend(
1255 packages.extend(
1256 [
1256 [
1257 'mercurial.thirdparty.concurrent',
1257 'mercurial.thirdparty.concurrent',
1258 'mercurial.thirdparty.concurrent.futures',
1258 'mercurial.thirdparty.concurrent.futures',
1259 ]
1259 ]
1260 )
1260 )
1261
1261
1262 if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ:
1262 if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ:
1263 # py2exe can't cope with namespace packages very well, so we have to
1263 # py2exe can't cope with namespace packages very well, so we have to
1264 # install any hgext3rd.* extensions that we want in the final py2exe
1264 # install any hgext3rd.* extensions that we want in the final py2exe
1265 # image here. This is gross, but you gotta do what you gotta do.
1265 # image here. This is gross, but you gotta do what you gotta do.
1266 packages.extend(os.environ['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'].split(' '))
1266 packages.extend(os.environ['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'].split(' '))
1267
1267
1268 common_depends = [
1268 common_depends = [
1269 'mercurial/bitmanipulation.h',
1269 'mercurial/bitmanipulation.h',
1270 'mercurial/compat.h',
1270 'mercurial/compat.h',
1271 'mercurial/cext/util.h',
1271 'mercurial/cext/util.h',
1272 ]
1272 ]
1273 common_include_dirs = ['mercurial']
1273 common_include_dirs = ['mercurial']
1274
1274
1275 common_cflags = []
1275 common_cflags = []
1276
1276
1277 # MSVC 2008 still needs declarations at the top of the scope, but Python 3.9
1277 # MSVC 2008 still needs declarations at the top of the scope, but Python 3.9
1278 # makes declarations not at the top of a scope in the headers.
1278 # makes declarations not at the top of a scope in the headers.
1279 if os.name != 'nt' and sys.version_info[1] < 9:
1279 if os.name != 'nt' and sys.version_info[1] < 9:
1280 common_cflags = ['-Werror=declaration-after-statement']
1280 common_cflags = ['-Werror=declaration-after-statement']
1281
1281
1282 osutil_cflags = []
1282 osutil_cflags = []
1283 osutil_ldflags = []
1283 osutil_ldflags = []
1284
1284
1285 # platform specific macros
1285 # platform specific macros
1286 for plat, func in [('bsd', 'setproctitle')]:
1286 for plat, func in [('bsd', 'setproctitle')]:
1287 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
1287 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
1288 osutil_cflags.append('-DHAVE_%s' % func.upper())
1288 osutil_cflags.append('-DHAVE_%s' % func.upper())
1289
1289
1290 for plat, macro, code in [
1290 for plat, macro, code in [
1291 (
1291 (
1292 'bsd|darwin',
1292 'bsd|darwin',
1293 'BSD_STATFS',
1293 'BSD_STATFS',
1294 '''
1294 '''
1295 #include <sys/param.h>
1295 #include <sys/param.h>
1296 #include <sys/mount.h>
1296 #include <sys/mount.h>
1297 int main() { struct statfs s; return sizeof(s.f_fstypename); }
1297 int main() { struct statfs s; return sizeof(s.f_fstypename); }
1298 ''',
1298 ''',
1299 ),
1299 ),
1300 (
1300 (
1301 'linux',
1301 'linux',
1302 'LINUX_STATFS',
1302 'LINUX_STATFS',
1303 '''
1303 '''
1304 #include <linux/magic.h>
1304 #include <linux/magic.h>
1305 #include <sys/vfs.h>
1305 #include <sys/vfs.h>
1306 int main() { struct statfs s; return sizeof(s.f_type); }
1306 int main() { struct statfs s; return sizeof(s.f_type); }
1307 ''',
1307 ''',
1308 ),
1308 ),
1309 ]:
1309 ]:
1310 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
1310 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
1311 osutil_cflags.append('-DHAVE_%s' % macro)
1311 osutil_cflags.append('-DHAVE_%s' % macro)
1312
1312
1313 if sys.platform == 'darwin':
1313 if sys.platform == 'darwin':
1314 osutil_ldflags += ['-framework', 'ApplicationServices']
1314 osutil_ldflags += ['-framework', 'ApplicationServices']
1315
1315
1316 xdiff_srcs = [
1316 xdiff_srcs = [
1317 'mercurial/thirdparty/xdiff/xdiffi.c',
1317 'mercurial/thirdparty/xdiff/xdiffi.c',
1318 'mercurial/thirdparty/xdiff/xprepare.c',
1318 'mercurial/thirdparty/xdiff/xprepare.c',
1319 'mercurial/thirdparty/xdiff/xutils.c',
1319 'mercurial/thirdparty/xdiff/xutils.c',
1320 ]
1320 ]
1321
1321
1322 xdiff_headers = [
1322 xdiff_headers = [
1323 'mercurial/thirdparty/xdiff/xdiff.h',
1323 'mercurial/thirdparty/xdiff/xdiff.h',
1324 'mercurial/thirdparty/xdiff/xdiffi.h',
1324 'mercurial/thirdparty/xdiff/xdiffi.h',
1325 'mercurial/thirdparty/xdiff/xinclude.h',
1325 'mercurial/thirdparty/xdiff/xinclude.h',
1326 'mercurial/thirdparty/xdiff/xmacros.h',
1326 'mercurial/thirdparty/xdiff/xmacros.h',
1327 'mercurial/thirdparty/xdiff/xprepare.h',
1327 'mercurial/thirdparty/xdiff/xprepare.h',
1328 'mercurial/thirdparty/xdiff/xtypes.h',
1328 'mercurial/thirdparty/xdiff/xtypes.h',
1329 'mercurial/thirdparty/xdiff/xutils.h',
1329 'mercurial/thirdparty/xdiff/xutils.h',
1330 ]
1330 ]
1331
1331
1332
1332
1333 class RustCompilationError(CCompilerError):
1333 class RustCompilationError(CCompilerError):
1334 """Exception class for Rust compilation errors."""
1334 """Exception class for Rust compilation errors."""
1335
1335
1336
1336
1337 class RustExtension(Extension):
1337 class RustExtension(Extension):
1338 """Base classes for concrete Rust Extension classes.
1338 """Base classes for concrete Rust Extension classes.
1339 """
1339 """
1340
1340
1341 rusttargetdir = os.path.join('rust', 'target', 'release')
1341 rusttargetdir = os.path.join('rust', 'target', 'release')
1342
1342
1343 def __init__(
1343 def __init__(
1344 self, mpath, sources, rustlibname, subcrate, py3_features=None, **kw
1344 self, mpath, sources, rustlibname, subcrate, py3_features=None, **kw
1345 ):
1345 ):
1346 Extension.__init__(self, mpath, sources, **kw)
1346 Extension.__init__(self, mpath, sources, **kw)
1347 srcdir = self.rustsrcdir = os.path.join('rust', subcrate)
1347 srcdir = self.rustsrcdir = os.path.join('rust', subcrate)
1348 self.py3_features = py3_features
1348 self.py3_features = py3_features
1349
1349
1350 # adding Rust source and control files to depends so that the extension
1350 # adding Rust source and control files to depends so that the extension
1351 # gets rebuilt if they've changed
1351 # gets rebuilt if they've changed
1352 self.depends.append(os.path.join(srcdir, 'Cargo.toml'))
1352 self.depends.append(os.path.join(srcdir, 'Cargo.toml'))
1353 cargo_lock = os.path.join(srcdir, 'Cargo.lock')
1353 cargo_lock = os.path.join(srcdir, 'Cargo.lock')
1354 if os.path.exists(cargo_lock):
1354 if os.path.exists(cargo_lock):
1355 self.depends.append(cargo_lock)
1355 self.depends.append(cargo_lock)
1356 for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')):
1356 for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')):
1357 self.depends.extend(
1357 self.depends.extend(
1358 os.path.join(dirpath, fname)
1358 os.path.join(dirpath, fname)
1359 for fname in fnames
1359 for fname in fnames
1360 if os.path.splitext(fname)[1] == '.rs'
1360 if os.path.splitext(fname)[1] == '.rs'
1361 )
1361 )
1362
1362
1363 @staticmethod
1363 @staticmethod
1364 def rustdylibsuffix():
1364 def rustdylibsuffix():
1365 """Return the suffix for shared libraries produced by rustc.
1365 """Return the suffix for shared libraries produced by rustc.
1366
1366
1367 See also: https://doc.rust-lang.org/reference/linkage.html
1367 See also: https://doc.rust-lang.org/reference/linkage.html
1368 """
1368 """
1369 if sys.platform == 'darwin':
1369 if sys.platform == 'darwin':
1370 return '.dylib'
1370 return '.dylib'
1371 elif os.name == 'nt':
1371 elif os.name == 'nt':
1372 return '.dll'
1372 return '.dll'
1373 else:
1373 else:
1374 return '.so'
1374 return '.so'
1375
1375
1376 def rustbuild(self):
1376 def rustbuild(self):
1377 env = os.environ.copy()
1377 env = os.environ.copy()
1378 if 'HGTEST_RESTOREENV' in env:
1378 if 'HGTEST_RESTOREENV' in env:
1379 # Mercurial tests change HOME to a temporary directory,
1379 # Mercurial tests change HOME to a temporary directory,
1380 # but, if installed with rustup, the Rust toolchain needs
1380 # but, if installed with rustup, the Rust toolchain needs
1381 # HOME to be correct (otherwise the 'no default toolchain'
1381 # HOME to be correct (otherwise the 'no default toolchain'
1382 # error message is issued and the build fails).
1382 # error message is issued and the build fails).
1383 # This happens currently with test-hghave.t, which does
1383 # This happens currently with test-hghave.t, which does
1384 # invoke this build.
1384 # invoke this build.
1385
1385
1386 # Unix only fix (os.path.expanduser not really reliable if
1386 # Unix only fix (os.path.expanduser not really reliable if
1387 # HOME is shadowed like this)
1387 # HOME is shadowed like this)
1388 import pwd
1388 import pwd
1389
1389
1390 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir
1390 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir
1391
1391
1392 cargocmd = ['cargo', 'rustc', '-vv', '--release']
1392 cargocmd = ['cargo', 'rustc', '-vv', '--release']
1393
1393
1394 feature_flags = []
1394 feature_flags = []
1395
1395
1396 if sys.version_info[0] == 3 and self.py3_features is not None:
1396 if sys.version_info[0] == 3 and self.py3_features is not None:
1397 feature_flags.append(self.py3_features)
1397 feature_flags.append(self.py3_features)
1398 cargocmd.append('--no-default-features')
1398 cargocmd.append('--no-default-features')
1399
1399
1400 rust_features = env.get("HG_RUST_FEATURES")
1400 rust_features = env.get("HG_RUST_FEATURES")
1401 if rust_features:
1401 if rust_features:
1402 feature_flags.append(rust_features)
1402 feature_flags.append(rust_features)
1403
1403
1404 cargocmd.extend(('--features', " ".join(feature_flags)))
1404 cargocmd.extend(('--features', " ".join(feature_flags)))
1405
1405
1406 cargocmd.append('--')
1406 cargocmd.append('--')
1407 if sys.platform == 'darwin':
1407 if sys.platform == 'darwin':
1408 cargocmd.extend(
1408 cargocmd.extend(
1409 ("-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup")
1409 ("-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup")
1410 )
1410 )
1411 try:
1411 try:
1412 subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir)
1412 subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir)
1413 except OSError as exc:
1413 except OSError as exc:
1414 if exc.errno == errno.ENOENT:
1414 if exc.errno == errno.ENOENT:
1415 raise RustCompilationError("Cargo not found")
1415 raise RustCompilationError("Cargo not found")
1416 elif exc.errno == errno.EACCES:
1416 elif exc.errno == errno.EACCES:
1417 raise RustCompilationError(
1417 raise RustCompilationError(
1418 "Cargo found, but permisssion to execute it is denied"
1418 "Cargo found, but permisssion to execute it is denied"
1419 )
1419 )
1420 else:
1420 else:
1421 raise
1421 raise
1422 except subprocess.CalledProcessError:
1422 except subprocess.CalledProcessError:
1423 raise RustCompilationError(
1423 raise RustCompilationError(
1424 "Cargo failed. Working directory: %r, "
1424 "Cargo failed. Working directory: %r, "
1425 "command: %r, environment: %r"
1425 "command: %r, environment: %r"
1426 % (self.rustsrcdir, cargocmd, env)
1426 % (self.rustsrcdir, cargocmd, env)
1427 )
1427 )
1428
1428
1429
1429
1430 class RustStandaloneExtension(RustExtension):
1430 class RustStandaloneExtension(RustExtension):
1431 def __init__(self, pydottedname, rustcrate, dylibname, **kw):
1431 def __init__(self, pydottedname, rustcrate, dylibname, **kw):
1432 RustExtension.__init__(
1432 RustExtension.__init__(
1433 self, pydottedname, [], dylibname, rustcrate, **kw
1433 self, pydottedname, [], dylibname, rustcrate, **kw
1434 )
1434 )
1435 self.dylibname = dylibname
1435 self.dylibname = dylibname
1436
1436
1437 def build(self, target_dir):
1437 def build(self, target_dir):
1438 self.rustbuild()
1438 self.rustbuild()
1439 target = [target_dir]
1439 target = [target_dir]
1440 target.extend(self.name.split('.'))
1440 target.extend(self.name.split('.'))
1441 target[-1] += DYLIB_SUFFIX
1441 target[-1] += DYLIB_SUFFIX
1442 shutil.copy2(
1442 shutil.copy2(
1443 os.path.join(
1443 os.path.join(
1444 self.rusttargetdir, self.dylibname + self.rustdylibsuffix()
1444 self.rusttargetdir, self.dylibname + self.rustdylibsuffix()
1445 ),
1445 ),
1446 os.path.join(*target),
1446 os.path.join(*target),
1447 )
1447 )
1448
1448
1449
1449
1450 extmodules = [
1450 extmodules = [
1451 Extension(
1451 Extension(
1452 'mercurial.cext.base85',
1452 'mercurial.cext.base85',
1453 ['mercurial/cext/base85.c'],
1453 ['mercurial/cext/base85.c'],
1454 include_dirs=common_include_dirs,
1454 include_dirs=common_include_dirs,
1455 extra_compile_args=common_cflags,
1455 extra_compile_args=common_cflags,
1456 depends=common_depends,
1456 depends=common_depends,
1457 ),
1457 ),
1458 Extension(
1458 Extension(
1459 'mercurial.cext.bdiff',
1459 'mercurial.cext.bdiff',
1460 ['mercurial/bdiff.c', 'mercurial/cext/bdiff.c'] + xdiff_srcs,
1460 ['mercurial/bdiff.c', 'mercurial/cext/bdiff.c'] + xdiff_srcs,
1461 include_dirs=common_include_dirs,
1461 include_dirs=common_include_dirs,
1462 extra_compile_args=common_cflags,
1462 extra_compile_args=common_cflags,
1463 depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers,
1463 depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers,
1464 ),
1464 ),
1465 Extension(
1465 Extension(
1466 'mercurial.cext.mpatch',
1466 'mercurial.cext.mpatch',
1467 ['mercurial/mpatch.c', 'mercurial/cext/mpatch.c'],
1467 ['mercurial/mpatch.c', 'mercurial/cext/mpatch.c'],
1468 include_dirs=common_include_dirs,
1468 include_dirs=common_include_dirs,
1469 extra_compile_args=common_cflags,
1469 extra_compile_args=common_cflags,
1470 depends=common_depends,
1470 depends=common_depends,
1471 ),
1471 ),
1472 Extension(
1472 Extension(
1473 'mercurial.cext.parsers',
1473 'mercurial.cext.parsers',
1474 [
1474 [
1475 'mercurial/cext/charencode.c',
1475 'mercurial/cext/charencode.c',
1476 'mercurial/cext/dirs.c',
1476 'mercurial/cext/dirs.c',
1477 'mercurial/cext/manifest.c',
1477 'mercurial/cext/manifest.c',
1478 'mercurial/cext/parsers.c',
1478 'mercurial/cext/parsers.c',
1479 'mercurial/cext/pathencode.c',
1479 'mercurial/cext/pathencode.c',
1480 'mercurial/cext/revlog.c',
1480 'mercurial/cext/revlog.c',
1481 ],
1481 ],
1482 include_dirs=common_include_dirs,
1482 include_dirs=common_include_dirs,
1483 extra_compile_args=common_cflags,
1483 extra_compile_args=common_cflags,
1484 depends=common_depends
1484 depends=common_depends
1485 + ['mercurial/cext/charencode.h', 'mercurial/cext/revlog.h',],
1485 + ['mercurial/cext/charencode.h', 'mercurial/cext/revlog.h',],
1486 ),
1486 ),
1487 Extension(
1487 Extension(
1488 'mercurial.cext.osutil',
1488 'mercurial.cext.osutil',
1489 ['mercurial/cext/osutil.c'],
1489 ['mercurial/cext/osutil.c'],
1490 include_dirs=common_include_dirs,
1490 include_dirs=common_include_dirs,
1491 extra_compile_args=common_cflags + osutil_cflags,
1491 extra_compile_args=common_cflags + osutil_cflags,
1492 extra_link_args=osutil_ldflags,
1492 extra_link_args=osutil_ldflags,
1493 depends=common_depends,
1493 depends=common_depends,
1494 ),
1494 ),
1495 Extension(
1495 Extension(
1496 'mercurial.thirdparty.zope.interface._zope_interface_coptimizations',
1496 'mercurial.thirdparty.zope.interface._zope_interface_coptimizations',
1497 [
1497 [
1498 'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c',
1498 'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c',
1499 ],
1499 ],
1500 extra_compile_args=common_cflags,
1500 extra_compile_args=common_cflags,
1501 ),
1501 ),
1502 Extension(
1502 Extension(
1503 'mercurial.thirdparty.sha1dc',
1503 'mercurial.thirdparty.sha1dc',
1504 [
1504 [
1505 'mercurial/thirdparty/sha1dc/cext.c',
1505 'mercurial/thirdparty/sha1dc/cext.c',
1506 'mercurial/thirdparty/sha1dc/lib/sha1.c',
1506 'mercurial/thirdparty/sha1dc/lib/sha1.c',
1507 'mercurial/thirdparty/sha1dc/lib/ubc_check.c',
1507 'mercurial/thirdparty/sha1dc/lib/ubc_check.c',
1508 ],
1508 ],
1509 extra_compile_args=common_cflags,
1509 extra_compile_args=common_cflags,
1510 ),
1510 ),
1511 Extension(
1511 Extension(
1512 'hgext.fsmonitor.pywatchman.bser',
1512 'hgext.fsmonitor.pywatchman.bser',
1513 ['hgext/fsmonitor/pywatchman/bser.c'],
1513 ['hgext/fsmonitor/pywatchman/bser.c'],
1514 extra_compile_args=common_cflags,
1514 extra_compile_args=common_cflags,
1515 ),
1515 ),
1516 RustStandaloneExtension(
1516 RustStandaloneExtension(
1517 'mercurial.rustext', 'hg-cpython', 'librusthg', py3_features='python3'
1517 'mercurial.rustext', 'hg-cpython', 'librusthg', py3_features='python3'
1518 ),
1518 ),
1519 ]
1519 ]
1520
1520
1521
1521
1522 sys.path.insert(0, 'contrib/python-zstandard')
1522 sys.path.insert(0, 'contrib/python-zstandard')
1523 import setup_zstd
1523 import setup_zstd
1524
1524
1525 zstd = setup_zstd.get_c_extension(
1525 zstd = setup_zstd.get_c_extension(
1526 name='mercurial.zstd', root=os.path.abspath(os.path.dirname(__file__))
1526 name='mercurial.zstd', root=os.path.abspath(os.path.dirname(__file__))
1527 )
1527 )
1528 zstd.extra_compile_args += common_cflags
1528 zstd.extra_compile_args += common_cflags
1529 extmodules.append(zstd)
1529 extmodules.append(zstd)
1530
1530
1531 try:
1531 try:
1532 from distutils import cygwinccompiler
1532 from distutils import cygwinccompiler
1533
1533
1534 # the -mno-cygwin option has been deprecated for years
1534 # the -mno-cygwin option has been deprecated for years
1535 mingw32compilerclass = cygwinccompiler.Mingw32CCompiler
1535 mingw32compilerclass = cygwinccompiler.Mingw32CCompiler
1536
1536
1537 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
1537 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
1538 def __init__(self, *args, **kwargs):
1538 def __init__(self, *args, **kwargs):
1539 mingw32compilerclass.__init__(self, *args, **kwargs)
1539 mingw32compilerclass.__init__(self, *args, **kwargs)
1540 for i in 'compiler compiler_so linker_exe linker_so'.split():
1540 for i in 'compiler compiler_so linker_exe linker_so'.split():
1541 try:
1541 try:
1542 getattr(self, i).remove('-mno-cygwin')
1542 getattr(self, i).remove('-mno-cygwin')
1543 except ValueError:
1543 except ValueError:
1544 pass
1544 pass
1545
1545
1546 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
1546 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
1547 except ImportError:
1547 except ImportError:
1548 # the cygwinccompiler package is not available on some Python
1548 # the cygwinccompiler package is not available on some Python
1549 # distributions like the ones from the optware project for Synology
1549 # distributions like the ones from the optware project for Synology
1550 # DiskStation boxes
1550 # DiskStation boxes
1551 class HackedMingw32CCompiler(object):
1551 class HackedMingw32CCompiler(object):
1552 pass
1552 pass
1553
1553
1554
1554
1555 if os.name == 'nt':
1555 if os.name == 'nt':
1556 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
1556 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
1557 # extra_link_args to distutils.extensions.Extension() doesn't have any
1557 # extra_link_args to distutils.extensions.Extension() doesn't have any
1558 # effect.
1558 # effect.
1559 from distutils import msvccompiler
1559 from distutils import msvccompiler
1560
1560
1561 msvccompilerclass = msvccompiler.MSVCCompiler
1561 msvccompilerclass = msvccompiler.MSVCCompiler
1562
1562
1563 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
1563 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
1564 def initialize(self):
1564 def initialize(self):
1565 msvccompilerclass.initialize(self)
1565 msvccompilerclass.initialize(self)
1566 # "warning LNK4197: export 'func' specified multiple times"
1566 # "warning LNK4197: export 'func' specified multiple times"
1567 self.ldflags_shared.append('/ignore:4197')
1567 self.ldflags_shared.append('/ignore:4197')
1568 self.ldflags_shared_debug.append('/ignore:4197')
1568 self.ldflags_shared_debug.append('/ignore:4197')
1569
1569
1570 msvccompiler.MSVCCompiler = HackedMSVCCompiler
1570 msvccompiler.MSVCCompiler = HackedMSVCCompiler
1571
1571
1572 packagedata = {
1572 packagedata = {
1573 'mercurial': [
1573 'mercurial': [
1574 'locale/*/LC_MESSAGES/hg.mo',
1574 'locale/*/LC_MESSAGES/hg.mo',
1575 'defaultrc/*.rc',
1575 'defaultrc/*.rc',
1576 'dummycert.pem',
1576 'dummycert.pem',
1577 ],
1577 ],
1578 'mercurial.helptext': ['*.txt',],
1578 'mercurial.helptext': ['*.txt',],
1579 'mercurial.helptext.internals': ['*.txt',],
1579 'mercurial.helptext.internals': ['*.txt',],
1580 }
1580 }
1581
1581
1582
1582
1583 def ordinarypath(p):
1583 def ordinarypath(p):
1584 return p and p[0] != '.' and p[-1] != '~'
1584 return p and p[0] != '.' and p[-1] != '~'
1585
1585
1586
1586
1587 for root in ('templates',):
1587 for root in ('templates',):
1588 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
1588 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
1589 curdir = curdir.split(os.sep, 1)[1]
1589 curdir = curdir.split(os.sep, 1)[1]
1590 dirs[:] = filter(ordinarypath, dirs)
1590 dirs[:] = filter(ordinarypath, dirs)
1591 for f in filter(ordinarypath, files):
1591 for f in filter(ordinarypath, files):
1592 f = os.path.join(curdir, f)
1592 f = os.path.join(curdir, f)
1593 packagedata['mercurial'].append(f)
1593 packagedata['mercurial'].append(f)
1594
1594
1595 datafiles = []
1595 datafiles = []
1596
1596
1597 # distutils expects version to be str/unicode. Converting it to
1597 # distutils expects version to be str/unicode. Converting it to
1598 # unicode on Python 2 still works because it won't contain any
1598 # unicode on Python 2 still works because it won't contain any
1599 # non-ascii bytes and will be implicitly converted back to bytes
1599 # non-ascii bytes and will be implicitly converted back to bytes
1600 # when operated on.
1600 # when operated on.
1601 assert isinstance(version, bytes)
1601 assert isinstance(version, bytes)
1602 setupversion = version.decode('ascii')
1602 setupversion = version.decode('ascii')
1603
1603
1604 extra = {}
1604 extra = {}
1605
1605
1606 py2exepackages = [
1606 py2exepackages = [
1607 'hgdemandimport',
1607 'hgdemandimport',
1608 'hgext3rd',
1608 'hgext3rd',
1609 'hgext',
1609 'hgext',
1610 'email',
1610 'email',
1611 # implicitly imported per module policy
1611 # implicitly imported per module policy
1612 # (cffi wouldn't be used as a frozen exe)
1612 # (cffi wouldn't be used as a frozen exe)
1613 'mercurial.cext',
1613 'mercurial.cext',
1614 #'mercurial.cffi',
1614 #'mercurial.cffi',
1615 'mercurial.pure',
1615 'mercurial.pure',
1616 ]
1616 ]
1617
1617
1618 py2exeexcludes = []
1618 py2exeexcludes = []
1619 py2exedllexcludes = ['crypt32.dll']
1619 py2exedllexcludes = ['crypt32.dll']
1620
1620
1621 if issetuptools:
1621 if issetuptools:
1622 extra['python_requires'] = supportedpy
1622 extra['python_requires'] = supportedpy
1623
1623
1624 if py2exeloaded:
1624 if py2exeloaded:
1625 extra['console'] = [
1625 extra['console'] = [
1626 {
1626 {
1627 'script': 'hg',
1627 'script': 'hg',
1628 'copyright': 'Copyright (C) 2005-2020 Matt Mackall and others',
1628 'copyright': 'Copyright (C) 2005-2020 Matt Mackall and others',
1629 'product_version': version,
1629 'product_version': version,
1630 }
1630 }
1631 ]
1631 ]
1632 # Sub command of 'build' because 'py2exe' does not handle sub_commands.
1632 # Sub command of 'build' because 'py2exe' does not handle sub_commands.
1633 # Need to override hgbuild because it has a private copy of
1633 # Need to override hgbuild because it has a private copy of
1634 # build.sub_commands.
1634 # build.sub_commands.
1635 hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
1635 hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
1636 # put dlls in sub directory so that they won't pollute PATH
1636 # put dlls in sub directory so that they won't pollute PATH
1637 extra['zipfile'] = 'lib/library.zip'
1637 extra['zipfile'] = 'lib/library.zip'
1638
1638
1639 # We allow some configuration to be supplemented via environment
1639 # We allow some configuration to be supplemented via environment
1640 # variables. This is better than setup.cfg files because it allows
1640 # variables. This is better than setup.cfg files because it allows
1641 # supplementing configs instead of replacing them.
1641 # supplementing configs instead of replacing them.
1642 extrapackages = os.environ.get('HG_PY2EXE_EXTRA_PACKAGES')
1642 extrapackages = os.environ.get('HG_PY2EXE_EXTRA_PACKAGES')
1643 if extrapackages:
1643 if extrapackages:
1644 py2exepackages.extend(extrapackages.split(' '))
1644 py2exepackages.extend(extrapackages.split(' '))
1645
1645
1646 excludes = os.environ.get('HG_PY2EXE_EXTRA_EXCLUDES')
1646 excludes = os.environ.get('HG_PY2EXE_EXTRA_EXCLUDES')
1647 if excludes:
1647 if excludes:
1648 py2exeexcludes.extend(excludes.split(' '))
1648 py2exeexcludes.extend(excludes.split(' '))
1649
1649
1650 dllexcludes = os.environ.get('HG_PY2EXE_EXTRA_DLL_EXCLUDES')
1650 dllexcludes = os.environ.get('HG_PY2EXE_EXTRA_DLL_EXCLUDES')
1651 if dllexcludes:
1651 if dllexcludes:
1652 py2exedllexcludes.extend(dllexcludes.split(' '))
1652 py2exedllexcludes.extend(dllexcludes.split(' '))
1653
1653
1654 if os.name == 'nt':
1654 if os.name == 'nt':
1655 # Windows binary file versions for exe/dll files must have the
1655 # Windows binary file versions for exe/dll files must have the
1656 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
1656 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
1657 setupversion = setupversion.split(r'+', 1)[0]
1657 setupversion = setupversion.split(r'+', 1)[0]
1658
1658
1659 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
1659 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
1660 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines()
1660 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines()
1661 if version:
1661 if version:
1662 version = version[0]
1662 version = version[0]
1663 if sys.version_info[0] == 3:
1663 if sys.version_info[0] == 3:
1664 version = version.decode('utf-8')
1664 version = version.decode('utf-8')
1665 xcode4 = version.startswith('Xcode') and StrictVersion(
1665 xcode4 = version.startswith('Xcode') and StrictVersion(
1666 version.split()[1]
1666 version.split()[1]
1667 ) >= StrictVersion('4.0')
1667 ) >= StrictVersion('4.0')
1668 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
1668 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
1669 else:
1669 else:
1670 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
1670 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
1671 # installed, but instead with only command-line tools. Assume
1671 # installed, but instead with only command-line tools. Assume
1672 # that only happens on >= Lion, thus no PPC support.
1672 # that only happens on >= Lion, thus no PPC support.
1673 xcode4 = True
1673 xcode4 = True
1674 xcode51 = False
1674 xcode51 = False
1675
1675
1676 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
1676 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
1677 # distutils.sysconfig
1677 # distutils.sysconfig
1678 if xcode4:
1678 if xcode4:
1679 os.environ['ARCHFLAGS'] = ''
1679 os.environ['ARCHFLAGS'] = ''
1680
1680
1681 # XCode 5.1 changes clang such that it now fails to compile if the
1681 # XCode 5.1 changes clang such that it now fails to compile if the
1682 # -mno-fused-madd flag is passed, but the version of Python shipped with
1682 # -mno-fused-madd flag is passed, but the version of Python shipped with
1683 # OS X 10.9 Mavericks includes this flag. This causes problems in all
1683 # OS X 10.9 Mavericks includes this flag. This causes problems in all
1684 # C extension modules, and a bug has been filed upstream at
1684 # C extension modules, and a bug has been filed upstream at
1685 # http://bugs.python.org/issue21244. We also need to patch this here
1685 # http://bugs.python.org/issue21244. We also need to patch this here
1686 # so Mercurial can continue to compile in the meantime.
1686 # so Mercurial can continue to compile in the meantime.
1687 if xcode51:
1687 if xcode51:
1688 cflags = get_config_var('CFLAGS')
1688 cflags = get_config_var('CFLAGS')
1689 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
1689 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
1690 os.environ['CFLAGS'] = (
1690 os.environ['CFLAGS'] = (
1691 os.environ.get('CFLAGS', '') + ' -Qunused-arguments'
1691 os.environ.get('CFLAGS', '') + ' -Qunused-arguments'
1692 )
1692 )
1693
1693
1694 setup(
1694 setup(
1695 name='mercurial',
1695 name='mercurial',
1696 version=setupversion,
1696 version=setupversion,
1697 author='Matt Mackall and many others',
1697 author='Matt Mackall and many others',
1698 author_email='mercurial@mercurial-scm.org',
1698 author_email='mercurial@mercurial-scm.org',
1699 url='https://mercurial-scm.org/',
1699 url='https://mercurial-scm.org/',
1700 download_url='https://mercurial-scm.org/release/',
1700 download_url='https://mercurial-scm.org/release/',
1701 description=(
1701 description=(
1702 'Fast scalable distributed SCM (revision control, version '
1702 'Fast scalable distributed SCM (revision control, version '
1703 'control) system'
1703 'control) system'
1704 ),
1704 ),
1705 long_description=(
1705 long_description=(
1706 'Mercurial is a distributed SCM tool written in Python.'
1706 'Mercurial is a distributed SCM tool written in Python.'
1707 ' It is used by a number of large projects that require'
1707 ' It is used by a number of large projects that require'
1708 ' fast, reliable distributed revision control, such as '
1708 ' fast, reliable distributed revision control, such as '
1709 'Mozilla.'
1709 'Mozilla.'
1710 ),
1710 ),
1711 license='GNU GPLv2 or any later version',
1711 license='GNU GPLv2 or any later version',
1712 classifiers=[
1712 classifiers=[
1713 'Development Status :: 6 - Mature',
1713 'Development Status :: 6 - Mature',
1714 'Environment :: Console',
1714 'Environment :: Console',
1715 'Intended Audience :: Developers',
1715 'Intended Audience :: Developers',
1716 'Intended Audience :: System Administrators',
1716 'Intended Audience :: System Administrators',
1717 'License :: OSI Approved :: GNU General Public License (GPL)',
1717 'License :: OSI Approved :: GNU General Public License (GPL)',
1718 'Natural Language :: Danish',
1718 'Natural Language :: Danish',
1719 'Natural Language :: English',
1719 'Natural Language :: English',
1720 'Natural Language :: German',
1720 'Natural Language :: German',
1721 'Natural Language :: Italian',
1721 'Natural Language :: Italian',
1722 'Natural Language :: Japanese',
1722 'Natural Language :: Japanese',
1723 'Natural Language :: Portuguese (Brazilian)',
1723 'Natural Language :: Portuguese (Brazilian)',
1724 'Operating System :: Microsoft :: Windows',
1724 'Operating System :: Microsoft :: Windows',
1725 'Operating System :: OS Independent',
1725 'Operating System :: OS Independent',
1726 'Operating System :: POSIX',
1726 'Operating System :: POSIX',
1727 'Programming Language :: C',
1727 'Programming Language :: C',
1728 'Programming Language :: Python',
1728 'Programming Language :: Python',
1729 'Topic :: Software Development :: Version Control',
1729 'Topic :: Software Development :: Version Control',
1730 ],
1730 ],
1731 scripts=scripts,
1731 scripts=scripts,
1732 packages=packages,
1732 packages=packages,
1733 ext_modules=extmodules,
1733 ext_modules=extmodules,
1734 data_files=datafiles,
1734 data_files=datafiles,
1735 package_data=packagedata,
1735 package_data=packagedata,
1736 cmdclass=cmdclass,
1736 cmdclass=cmdclass,
1737 distclass=hgdist,
1737 distclass=hgdist,
1738 options={
1738 options={
1739 'py2exe': {
1739 'py2exe': {
1740 'bundle_files': 3,
1740 'bundle_files': 3,
1741 'dll_excludes': py2exedllexcludes,
1741 'dll_excludes': py2exedllexcludes,
1742 'excludes': py2exeexcludes,
1742 'excludes': py2exeexcludes,
1743 'packages': py2exepackages,
1743 'packages': py2exepackages,
1744 },
1744 },
1745 'bdist_mpkg': {
1745 'bdist_mpkg': {
1746 'zipdist': False,
1746 'zipdist': False,
1747 'license': 'COPYING',
1747 'license': 'COPYING',
1748 'readme': 'contrib/packaging/macosx/Readme.html',
1748 'readme': 'contrib/packaging/macosx/Readme.html',
1749 'welcome': 'contrib/packaging/macosx/Welcome.html',
1749 'welcome': 'contrib/packaging/macosx/Welcome.html',
1750 },
1750 },
1751 },
1751 },
1752 **extra
1752 **extra
1753 )
1753 )
General Comments 0
You need to be logged in to leave comments. Login now