##// END OF EJS Templates
branching: merge with stable
Martin von Zweigbergk -
r46348:79d68175 merge default
parent child Browse files
Show More
@@ -1,204 +1,205 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,217 +1,218 b''
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
208 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1
208 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1
209 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2
209 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2
210 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0
210 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0
211 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4
211 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4
212 065704cbdbdbb05dcd6bb814eb9bbdd982211b28 5.4.1
212 065704cbdbdbb05dcd6bb814eb9bbdd982211b28 5.4.1
213 0ea9c86fac8974cd74dc12ea681c8986eb6da6c4 5.4.2
213 0ea9c86fac8974cd74dc12ea681c8986eb6da6c4 5.4.2
214 28163c5de797e5416f9b588940f4608269b4d50a 5.5rc0
214 28163c5de797e5416f9b588940f4608269b4d50a 5.5rc0
215 7fc3c5fbc65f6fe85d70ea63923b8767dda4f2e0 5.5
215 7fc3c5fbc65f6fe85d70ea63923b8767dda4f2e0 5.5
216 f62bb5d07848ca598aa860a517394130b61bf2ee 5.5.1
216 f62bb5d07848ca598aa860a517394130b61bf2ee 5.5.1
217 07731064ac41dacdf0ec869ebd05c2e848c14fbf 5.5.2
217 07731064ac41dacdf0ec869ebd05c2e848c14fbf 5.5.2
218 0e06a7ab9e0d5c65af4e511aee1e0342998799df 5.6rc0
@@ -1,597 +1,597 b''
1 # linux.py - Linux specific automation functionality
1 # linux.py - Linux specific automation functionality
2 #
2 #
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.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 # no-check-code because Python 3 native.
8 # no-check-code because Python 3 native.
9
9
10 import os
10 import os
11 import pathlib
11 import pathlib
12 import shlex
12 import shlex
13 import subprocess
13 import subprocess
14 import tempfile
14 import tempfile
15
15
16 from .ssh import exec_command
16 from .ssh import exec_command
17
17
18
18
19 # Linux distributions that are supported.
19 # Linux distributions that are supported.
20 DISTROS = {
20 DISTROS = {
21 'debian9',
21 'debian9',
22 'debian10',
22 'debian10',
23 'ubuntu18.04',
23 'ubuntu18.04',
24 'ubuntu19.04',
24 'ubuntu19.04',
25 }
25 }
26
26
27 INSTALL_PYTHONS = r'''
27 INSTALL_PYTHONS = r'''
28 PYENV2_VERSIONS="2.7.17 pypy2.7-7.2.0"
28 PYENV2_VERSIONS="2.7.17 pypy2.7-7.2.0"
29 PYENV3_VERSIONS="3.5.10 3.6.12 3.7.9 3.8.6 3.9.0 pypy3.5-7.0.0 pypy3.6-7.3.0"
29 PYENV3_VERSIONS="3.5.10 3.6.12 3.7.9 3.8.6 3.9.0 pypy3.5-7.0.0 pypy3.6-7.3.0"
30
30
31 git clone https://github.com/pyenv/pyenv.git /hgdev/pyenv
31 git clone https://github.com/pyenv/pyenv.git /hgdev/pyenv
32 pushd /hgdev/pyenv
32 pushd /hgdev/pyenv
33 git checkout 8ac91b4fd678a8c04356f5ec85cfcd565c265e9a
33 git checkout 8ac91b4fd678a8c04356f5ec85cfcd565c265e9a
34 popd
34 popd
35
35
36 export PYENV_ROOT="/hgdev/pyenv"
36 export PYENV_ROOT="/hgdev/pyenv"
37 export PATH="$PYENV_ROOT/bin:$PATH"
37 export PATH="$PYENV_ROOT/bin:$PATH"
38
38
39 # pip 19.2.3.
39 # pip 19.2.3.
40 PIP_SHA256=57e3643ff19f018f8a00dfaa6b7e4620e3c1a7a2171fd218425366ec006b3bfe
40 PIP_SHA256=57e3643ff19f018f8a00dfaa6b7e4620e3c1a7a2171fd218425366ec006b3bfe
41 wget -O get-pip.py --progress dot:mega https://github.com/pypa/get-pip/raw/309a56c5fd94bd1134053a541cb4657a4e47e09d/get-pip.py
41 wget -O get-pip.py --progress dot:mega https://github.com/pypa/get-pip/raw/309a56c5fd94bd1134053a541cb4657a4e47e09d/get-pip.py
42 echo "${PIP_SHA256} get-pip.py" | sha256sum --check -
42 echo "${PIP_SHA256} get-pip.py" | sha256sum --check -
43
43
44 VIRTUALENV_SHA256=f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2
44 VIRTUALENV_SHA256=f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2
45 VIRTUALENV_TARBALL=virtualenv-16.7.5.tar.gz
45 VIRTUALENV_TARBALL=virtualenv-16.7.5.tar.gz
46 wget -O ${VIRTUALENV_TARBALL} --progress dot:mega https://files.pythonhosted.org/packages/66/f0/6867af06d2e2f511e4e1d7094ff663acdebc4f15d4a0cb0fed1007395124/${VIRTUALENV_TARBALL}
46 wget -O ${VIRTUALENV_TARBALL} --progress dot:mega https://files.pythonhosted.org/packages/66/f0/6867af06d2e2f511e4e1d7094ff663acdebc4f15d4a0cb0fed1007395124/${VIRTUALENV_TARBALL}
47 echo "${VIRTUALENV_SHA256} ${VIRTUALENV_TARBALL}" | sha256sum --check -
47 echo "${VIRTUALENV_SHA256} ${VIRTUALENV_TARBALL}" | sha256sum --check -
48
48
49 for v in ${PYENV2_VERSIONS}; do
49 for v in ${PYENV2_VERSIONS}; do
50 pyenv install -v ${v}
50 pyenv install -v ${v}
51 ${PYENV_ROOT}/versions/${v}/bin/python get-pip.py
51 ${PYENV_ROOT}/versions/${v}/bin/python get-pip.py
52 ${PYENV_ROOT}/versions/${v}/bin/pip install ${VIRTUALENV_TARBALL}
52 ${PYENV_ROOT}/versions/${v}/bin/pip install ${VIRTUALENV_TARBALL}
53 ${PYENV_ROOT}/versions/${v}/bin/pip install -r /hgdev/requirements-py2.txt
53 ${PYENV_ROOT}/versions/${v}/bin/pip install -r /hgdev/requirements-py2.txt
54 done
54 done
55
55
56 for v in ${PYENV3_VERSIONS}; do
56 for v in ${PYENV3_VERSIONS}; do
57 pyenv install -v ${v}
57 pyenv install -v ${v}
58 ${PYENV_ROOT}/versions/${v}/bin/python get-pip.py
58 ${PYENV_ROOT}/versions/${v}/bin/python get-pip.py
59 ${PYENV_ROOT}/versions/${v}/bin/pip install -r /hgdev/requirements-py3.txt
59 ${PYENV_ROOT}/versions/${v}/bin/pip install -r /hgdev/requirements-py3.txt
60 done
60 done
61
61
62 pyenv global ${PYENV2_VERSIONS} ${PYENV3_VERSIONS} system
62 pyenv global ${PYENV2_VERSIONS} ${PYENV3_VERSIONS} system
63 '''.lstrip().replace(
63 '''.lstrip().replace(
64 '\r\n', '\n'
64 '\r\n', '\n'
65 )
65 )
66
66
67
67
68 INSTALL_RUST = r'''
68 INSTALL_RUST = r'''
69 RUSTUP_INIT_SHA256=a46fe67199b7bcbbde2dcbc23ae08db6f29883e260e23899a88b9073effc9076
69 RUSTUP_INIT_SHA256=a46fe67199b7bcbbde2dcbc23ae08db6f29883e260e23899a88b9073effc9076
70 wget -O rustup-init --progress dot:mega https://static.rust-lang.org/rustup/archive/1.18.3/x86_64-unknown-linux-gnu/rustup-init
70 wget -O rustup-init --progress dot:mega https://static.rust-lang.org/rustup/archive/1.18.3/x86_64-unknown-linux-gnu/rustup-init
71 echo "${RUSTUP_INIT_SHA256} rustup-init" | sha256sum --check -
71 echo "${RUSTUP_INIT_SHA256} rustup-init" | sha256sum --check -
72
72
73 chmod +x rustup-init
73 chmod +x rustup-init
74 sudo -H -u hg -g hg ./rustup-init -y
74 sudo -H -u hg -g hg ./rustup-init -y
75 sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup install 1.31.1 1.46.0
75 sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup install 1.31.1 1.46.0
76 sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup component add clippy
76 sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup component add clippy
77
77
78 sudo -H -u hg -g hg /home/hg/.cargo/bin/cargo install --git https://github.com/indygreg/PyOxidizer.git --rev 4697fb25918dfad6dc73288daeea501063963a08 pyoxidizer
78 sudo -H -u hg -g hg /home/hg/.cargo/bin/cargo install --version 0.9.0 pyoxidizer
79 '''
79 '''
80
80
81
81
82 BOOTSTRAP_VIRTUALENV = r'''
82 BOOTSTRAP_VIRTUALENV = r'''
83 /usr/bin/virtualenv /hgdev/venv-bootstrap
83 /usr/bin/virtualenv /hgdev/venv-bootstrap
84
84
85 HG_SHA256=35fc8ba5e0379c1b3affa2757e83fb0509e8ac314cbd9f1fd133cf265d16e49f
85 HG_SHA256=35fc8ba5e0379c1b3affa2757e83fb0509e8ac314cbd9f1fd133cf265d16e49f
86 HG_TARBALL=mercurial-5.1.1.tar.gz
86 HG_TARBALL=mercurial-5.1.1.tar.gz
87
87
88 wget -O ${HG_TARBALL} --progress dot:mega https://www.mercurial-scm.org/release/${HG_TARBALL}
88 wget -O ${HG_TARBALL} --progress dot:mega https://www.mercurial-scm.org/release/${HG_TARBALL}
89 echo "${HG_SHA256} ${HG_TARBALL}" | sha256sum --check -
89 echo "${HG_SHA256} ${HG_TARBALL}" | sha256sum --check -
90
90
91 /hgdev/venv-bootstrap/bin/pip install ${HG_TARBALL}
91 /hgdev/venv-bootstrap/bin/pip install ${HG_TARBALL}
92 '''.lstrip().replace(
92 '''.lstrip().replace(
93 '\r\n', '\n'
93 '\r\n', '\n'
94 )
94 )
95
95
96
96
97 BOOTSTRAP_DEBIAN = (
97 BOOTSTRAP_DEBIAN = (
98 r'''
98 r'''
99 #!/bin/bash
99 #!/bin/bash
100
100
101 set -ex
101 set -ex
102
102
103 DISTRO=`grep DISTRIB_ID /etc/lsb-release | awk -F= '{{print $2}}'`
103 DISTRO=`grep DISTRIB_ID /etc/lsb-release | awk -F= '{{print $2}}'`
104 DEBIAN_VERSION=`cat /etc/debian_version`
104 DEBIAN_VERSION=`cat /etc/debian_version`
105 LSB_RELEASE=`lsb_release -cs`
105 LSB_RELEASE=`lsb_release -cs`
106
106
107 sudo /usr/sbin/groupadd hg
107 sudo /usr/sbin/groupadd hg
108 sudo /usr/sbin/groupadd docker
108 sudo /usr/sbin/groupadd docker
109 sudo /usr/sbin/useradd -g hg -G sudo,docker -d /home/hg -m -s /bin/bash hg
109 sudo /usr/sbin/useradd -g hg -G sudo,docker -d /home/hg -m -s /bin/bash hg
110 sudo mkdir /home/hg/.ssh
110 sudo mkdir /home/hg/.ssh
111 sudo cp ~/.ssh/authorized_keys /home/hg/.ssh/authorized_keys
111 sudo cp ~/.ssh/authorized_keys /home/hg/.ssh/authorized_keys
112 sudo chown -R hg:hg /home/hg/.ssh
112 sudo chown -R hg:hg /home/hg/.ssh
113 sudo chmod 700 /home/hg/.ssh
113 sudo chmod 700 /home/hg/.ssh
114 sudo chmod 600 /home/hg/.ssh/authorized_keys
114 sudo chmod 600 /home/hg/.ssh/authorized_keys
115
115
116 cat << EOF | sudo tee /etc/sudoers.d/90-hg
116 cat << EOF | sudo tee /etc/sudoers.d/90-hg
117 hg ALL=(ALL) NOPASSWD:ALL
117 hg ALL=(ALL) NOPASSWD:ALL
118 EOF
118 EOF
119
119
120 sudo apt-get update
120 sudo apt-get update
121 sudo DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade
121 sudo DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade
122
122
123 # Install packages necessary to set up Docker Apt repo.
123 # Install packages necessary to set up Docker Apt repo.
124 sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install --no-install-recommends \
124 sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install --no-install-recommends \
125 apt-transport-https \
125 apt-transport-https \
126 gnupg
126 gnupg
127
127
128 cat > docker-apt-key << EOF
128 cat > docker-apt-key << EOF
129 -----BEGIN PGP PUBLIC KEY BLOCK-----
129 -----BEGIN PGP PUBLIC KEY BLOCK-----
130
130
131 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
188 YT90qFF93M3v01BbxP+EIY2/9tiIPbrd
188 YT90qFF93M3v01BbxP+EIY2/9tiIPbrd
189 =0YYh
189 =0YYh
190 -----END PGP PUBLIC KEY BLOCK-----
190 -----END PGP PUBLIC KEY BLOCK-----
191 EOF
191 EOF
192
192
193 sudo apt-key add docker-apt-key
193 sudo apt-key add docker-apt-key
194
194
195 if [ "$LSB_RELEASE" = "stretch" ]; then
195 if [ "$LSB_RELEASE" = "stretch" ]; then
196 cat << EOF | sudo tee -a /etc/apt/sources.list
196 cat << EOF | sudo tee -a /etc/apt/sources.list
197 # Need backports for clang-format-6.0
197 # Need backports for clang-format-6.0
198 deb http://deb.debian.org/debian stretch-backports main
198 deb http://deb.debian.org/debian stretch-backports main
199 EOF
199 EOF
200 fi
200 fi
201
201
202 if [ "$LSB_RELEASE" = "stretch" -o "$LSB_RELEASE" = "buster" ]; then
202 if [ "$LSB_RELEASE" = "stretch" -o "$LSB_RELEASE" = "buster" ]; then
203 cat << EOF | sudo tee -a /etc/apt/sources.list
203 cat << EOF | sudo tee -a /etc/apt/sources.list
204 # Sources are useful if we want to compile things locally.
204 # Sources are useful if we want to compile things locally.
205 deb-src http://deb.debian.org/debian $LSB_RELEASE main
205 deb-src http://deb.debian.org/debian $LSB_RELEASE main
206 deb-src http://security.debian.org/debian-security $LSB_RELEASE/updates main
206 deb-src http://security.debian.org/debian-security $LSB_RELEASE/updates main
207 deb-src http://deb.debian.org/debian $LSB_RELEASE-updates main
207 deb-src http://deb.debian.org/debian $LSB_RELEASE-updates main
208 deb-src http://deb.debian.org/debian $LSB_RELEASE-backports main
208 deb-src http://deb.debian.org/debian $LSB_RELEASE-backports main
209
209
210 deb [arch=amd64] https://download.docker.com/linux/debian $LSB_RELEASE stable
210 deb [arch=amd64] https://download.docker.com/linux/debian $LSB_RELEASE stable
211 EOF
211 EOF
212
212
213 elif [ "$DISTRO" = "Ubuntu" ]; then
213 elif [ "$DISTRO" = "Ubuntu" ]; then
214 cat << EOF | sudo tee -a /etc/apt/sources.list
214 cat << EOF | sudo tee -a /etc/apt/sources.list
215 deb [arch=amd64] https://download.docker.com/linux/ubuntu $LSB_RELEASE stable
215 deb [arch=amd64] https://download.docker.com/linux/ubuntu $LSB_RELEASE stable
216 EOF
216 EOF
217
217
218 fi
218 fi
219
219
220 sudo apt-get update
220 sudo apt-get update
221
221
222 PACKAGES="\
222 PACKAGES="\
223 awscli \
223 awscli \
224 btrfs-progs \
224 btrfs-progs \
225 build-essential \
225 build-essential \
226 bzr \
226 bzr \
227 clang-format-6.0 \
227 clang-format-6.0 \
228 cvs \
228 cvs \
229 darcs \
229 darcs \
230 debhelper \
230 debhelper \
231 devscripts \
231 devscripts \
232 docker-ce \
232 docker-ce \
233 dpkg-dev \
233 dpkg-dev \
234 dstat \
234 dstat \
235 emacs \
235 emacs \
236 gettext \
236 gettext \
237 git \
237 git \
238 htop \
238 htop \
239 iotop \
239 iotop \
240 jfsutils \
240 jfsutils \
241 libbz2-dev \
241 libbz2-dev \
242 libexpat1-dev \
242 libexpat1-dev \
243 libffi-dev \
243 libffi-dev \
244 libgdbm-dev \
244 libgdbm-dev \
245 liblzma-dev \
245 liblzma-dev \
246 libncurses5-dev \
246 libncurses5-dev \
247 libnss3-dev \
247 libnss3-dev \
248 libreadline-dev \
248 libreadline-dev \
249 libsqlite3-dev \
249 libsqlite3-dev \
250 libssl-dev \
250 libssl-dev \
251 netbase \
251 netbase \
252 ntfs-3g \
252 ntfs-3g \
253 nvme-cli \
253 nvme-cli \
254 pyflakes \
254 pyflakes \
255 pyflakes3 \
255 pyflakes3 \
256 pylint \
256 pylint \
257 pylint3 \
257 pylint3 \
258 python-all-dev \
258 python-all-dev \
259 python-dev \
259 python-dev \
260 python-docutils \
260 python-docutils \
261 python-fuzzywuzzy \
261 python-fuzzywuzzy \
262 python-pygments \
262 python-pygments \
263 python-subversion \
263 python-subversion \
264 python-vcr \
264 python-vcr \
265 python3-boto3 \
265 python3-boto3 \
266 python3-dev \
266 python3-dev \
267 python3-docutils \
267 python3-docutils \
268 python3-fuzzywuzzy \
268 python3-fuzzywuzzy \
269 python3-pygments \
269 python3-pygments \
270 python3-vcr \
270 python3-vcr \
271 python3-venv \
271 python3-venv \
272 rsync \
272 rsync \
273 sqlite3 \
273 sqlite3 \
274 subversion \
274 subversion \
275 tcl-dev \
275 tcl-dev \
276 tk-dev \
276 tk-dev \
277 tla \
277 tla \
278 unzip \
278 unzip \
279 uuid-dev \
279 uuid-dev \
280 vim \
280 vim \
281 virtualenv \
281 virtualenv \
282 wget \
282 wget \
283 xfsprogs \
283 xfsprogs \
284 zip \
284 zip \
285 zlib1g-dev"
285 zlib1g-dev"
286
286
287 if [ "LSB_RELEASE" = "stretch" ]; then
287 if [ "LSB_RELEASE" = "stretch" ]; then
288 PACKAGES="$PACKAGES linux-perf"
288 PACKAGES="$PACKAGES linux-perf"
289 elif [ "$DISTRO" = "Ubuntu" ]; then
289 elif [ "$DISTRO" = "Ubuntu" ]; then
290 PACKAGES="$PACKAGES linux-tools-common"
290 PACKAGES="$PACKAGES linux-tools-common"
291 fi
291 fi
292
292
293 # Monotone only available in older releases.
293 # Monotone only available in older releases.
294 if [ "$LSB_RELEASE" = "stretch" -o "$LSB_RELEASE" = "xenial" ]; then
294 if [ "$LSB_RELEASE" = "stretch" -o "$LSB_RELEASE" = "xenial" ]; then
295 PACKAGES="$PACKAGES monotone"
295 PACKAGES="$PACKAGES monotone"
296 fi
296 fi
297
297
298 sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install --no-install-recommends $PACKAGES
298 sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install --no-install-recommends $PACKAGES
299
299
300 # Create clang-format symlink so test harness finds it.
300 # Create clang-format symlink so test harness finds it.
301 sudo update-alternatives --install /usr/bin/clang-format clang-format \
301 sudo update-alternatives --install /usr/bin/clang-format clang-format \
302 /usr/bin/clang-format-6.0 1000
302 /usr/bin/clang-format-6.0 1000
303
303
304 sudo mkdir /hgdev
304 sudo mkdir /hgdev
305 # Will be normalized to hg:hg later.
305 # Will be normalized to hg:hg later.
306 sudo chown `whoami` /hgdev
306 sudo chown `whoami` /hgdev
307
307
308 {install_rust}
308 {install_rust}
309
309
310 cp requirements-py2.txt /hgdev/requirements-py2.txt
310 cp requirements-py2.txt /hgdev/requirements-py2.txt
311 cp requirements-py3.txt /hgdev/requirements-py3.txt
311 cp requirements-py3.txt /hgdev/requirements-py3.txt
312
312
313 # Disable the pip version check because it uses the network and can
313 # Disable the pip version check because it uses the network and can
314 # be annoying.
314 # be annoying.
315 cat << EOF | sudo tee -a /etc/pip.conf
315 cat << EOF | sudo tee -a /etc/pip.conf
316 [global]
316 [global]
317 disable-pip-version-check = True
317 disable-pip-version-check = True
318 EOF
318 EOF
319
319
320 {install_pythons}
320 {install_pythons}
321 {bootstrap_virtualenv}
321 {bootstrap_virtualenv}
322
322
323 /hgdev/venv-bootstrap/bin/hg clone https://www.mercurial-scm.org/repo/hg /hgdev/src
323 /hgdev/venv-bootstrap/bin/hg clone https://www.mercurial-scm.org/repo/hg /hgdev/src
324
324
325 # Mark the repo as non-publishing.
325 # Mark the repo as non-publishing.
326 cat >> /hgdev/src/.hg/hgrc << EOF
326 cat >> /hgdev/src/.hg/hgrc << EOF
327 [phases]
327 [phases]
328 publish = false
328 publish = false
329 EOF
329 EOF
330
330
331 sudo chown -R hg:hg /hgdev
331 sudo chown -R hg:hg /hgdev
332 '''.lstrip()
332 '''.lstrip()
333 .format(
333 .format(
334 install_rust=INSTALL_RUST,
334 install_rust=INSTALL_RUST,
335 install_pythons=INSTALL_PYTHONS,
335 install_pythons=INSTALL_PYTHONS,
336 bootstrap_virtualenv=BOOTSTRAP_VIRTUALENV,
336 bootstrap_virtualenv=BOOTSTRAP_VIRTUALENV,
337 )
337 )
338 .replace('\r\n', '\n')
338 .replace('\r\n', '\n')
339 )
339 )
340
340
341
341
342 # Prepares /hgdev for operations.
342 # Prepares /hgdev for operations.
343 PREPARE_HGDEV = '''
343 PREPARE_HGDEV = '''
344 #!/bin/bash
344 #!/bin/bash
345
345
346 set -e
346 set -e
347
347
348 FS=$1
348 FS=$1
349
349
350 ensure_device() {
350 ensure_device() {
351 if [ -z "${DEVICE}" ]; then
351 if [ -z "${DEVICE}" ]; then
352 echo "could not find block device to format"
352 echo "could not find block device to format"
353 exit 1
353 exit 1
354 fi
354 fi
355 }
355 }
356
356
357 # Determine device to partition for extra filesystem.
357 # Determine device to partition for extra filesystem.
358 # If only 1 volume is present, it will be the root volume and
358 # If only 1 volume is present, it will be the root volume and
359 # should be /dev/nvme0. If multiple volumes are present, the
359 # should be /dev/nvme0. If multiple volumes are present, the
360 # root volume could be nvme0 or nvme1. Use whichever one doesn't have
360 # root volume could be nvme0 or nvme1. Use whichever one doesn't have
361 # a partition.
361 # a partition.
362 if [ -e /dev/nvme1n1 ]; then
362 if [ -e /dev/nvme1n1 ]; then
363 if [ -e /dev/nvme0n1p1 ]; then
363 if [ -e /dev/nvme0n1p1 ]; then
364 DEVICE=/dev/nvme1n1
364 DEVICE=/dev/nvme1n1
365 else
365 else
366 DEVICE=/dev/nvme0n1
366 DEVICE=/dev/nvme0n1
367 fi
367 fi
368 else
368 else
369 DEVICE=
369 DEVICE=
370 fi
370 fi
371
371
372 sudo mkdir /hgwork
372 sudo mkdir /hgwork
373
373
374 if [ "${FS}" != "default" -a "${FS}" != "tmpfs" ]; then
374 if [ "${FS}" != "default" -a "${FS}" != "tmpfs" ]; then
375 ensure_device
375 ensure_device
376 echo "creating ${FS} filesystem on ${DEVICE}"
376 echo "creating ${FS} filesystem on ${DEVICE}"
377 fi
377 fi
378
378
379 if [ "${FS}" = "default" ]; then
379 if [ "${FS}" = "default" ]; then
380 :
380 :
381
381
382 elif [ "${FS}" = "btrfs" ]; then
382 elif [ "${FS}" = "btrfs" ]; then
383 sudo mkfs.btrfs ${DEVICE}
383 sudo mkfs.btrfs ${DEVICE}
384 sudo mount ${DEVICE} /hgwork
384 sudo mount ${DEVICE} /hgwork
385
385
386 elif [ "${FS}" = "ext3" ]; then
386 elif [ "${FS}" = "ext3" ]; then
387 # lazy_journal_init speeds up filesystem creation at the expense of
387 # lazy_journal_init speeds up filesystem creation at the expense of
388 # integrity if things crash. We are an ephemeral instance, so we don't
388 # integrity if things crash. We are an ephemeral instance, so we don't
389 # care about integrity.
389 # care about integrity.
390 sudo mkfs.ext3 -E lazy_journal_init=1 ${DEVICE}
390 sudo mkfs.ext3 -E lazy_journal_init=1 ${DEVICE}
391 sudo mount ${DEVICE} /hgwork
391 sudo mount ${DEVICE} /hgwork
392
392
393 elif [ "${FS}" = "ext4" ]; then
393 elif [ "${FS}" = "ext4" ]; then
394 sudo mkfs.ext4 -E lazy_journal_init=1 ${DEVICE}
394 sudo mkfs.ext4 -E lazy_journal_init=1 ${DEVICE}
395 sudo mount ${DEVICE} /hgwork
395 sudo mount ${DEVICE} /hgwork
396
396
397 elif [ "${FS}" = "jfs" ]; then
397 elif [ "${FS}" = "jfs" ]; then
398 sudo mkfs.jfs ${DEVICE}
398 sudo mkfs.jfs ${DEVICE}
399 sudo mount ${DEVICE} /hgwork
399 sudo mount ${DEVICE} /hgwork
400
400
401 elif [ "${FS}" = "tmpfs" ]; then
401 elif [ "${FS}" = "tmpfs" ]; then
402 echo "creating tmpfs volume in /hgwork"
402 echo "creating tmpfs volume in /hgwork"
403 sudo mount -t tmpfs -o size=1024M tmpfs /hgwork
403 sudo mount -t tmpfs -o size=1024M tmpfs /hgwork
404
404
405 elif [ "${FS}" = "xfs" ]; then
405 elif [ "${FS}" = "xfs" ]; then
406 sudo mkfs.xfs ${DEVICE}
406 sudo mkfs.xfs ${DEVICE}
407 sudo mount ${DEVICE} /hgwork
407 sudo mount ${DEVICE} /hgwork
408
408
409 else
409 else
410 echo "unsupported filesystem: ${FS}"
410 echo "unsupported filesystem: ${FS}"
411 exit 1
411 exit 1
412 fi
412 fi
413
413
414 echo "/hgwork ready"
414 echo "/hgwork ready"
415
415
416 sudo chown hg:hg /hgwork
416 sudo chown hg:hg /hgwork
417 mkdir /hgwork/tmp
417 mkdir /hgwork/tmp
418 chown hg:hg /hgwork/tmp
418 chown hg:hg /hgwork/tmp
419
419
420 rsync -a /hgdev/src /hgwork/
420 rsync -a /hgdev/src /hgwork/
421 '''.lstrip().replace(
421 '''.lstrip().replace(
422 '\r\n', '\n'
422 '\r\n', '\n'
423 )
423 )
424
424
425
425
426 HG_UPDATE_CLEAN = '''
426 HG_UPDATE_CLEAN = '''
427 set -ex
427 set -ex
428
428
429 HG=/hgdev/venv-bootstrap/bin/hg
429 HG=/hgdev/venv-bootstrap/bin/hg
430
430
431 cd /hgwork/src
431 cd /hgwork/src
432 ${HG} --config extensions.purge= purge --all
432 ${HG} --config extensions.purge= purge --all
433 ${HG} update -C $1
433 ${HG} update -C $1
434 ${HG} log -r .
434 ${HG} log -r .
435 '''.lstrip().replace(
435 '''.lstrip().replace(
436 '\r\n', '\n'
436 '\r\n', '\n'
437 )
437 )
438
438
439
439
440 def prepare_exec_environment(ssh_client, filesystem='default'):
440 def prepare_exec_environment(ssh_client, filesystem='default'):
441 """Prepare an EC2 instance to execute things.
441 """Prepare an EC2 instance to execute things.
442
442
443 The AMI has an ``/hgdev`` bootstrapped with various Python installs
443 The AMI has an ``/hgdev`` bootstrapped with various Python installs
444 and a clone of the Mercurial repo.
444 and a clone of the Mercurial repo.
445
445
446 In EC2, EBS volumes launched from snapshots have wonky performance behavior.
446 In EC2, EBS volumes launched from snapshots have wonky performance behavior.
447 Notably, blocks have to be copied on first access, which makes volume
447 Notably, blocks have to be copied on first access, which makes volume
448 I/O extremely slow on fresh volumes.
448 I/O extremely slow on fresh volumes.
449
449
450 Furthermore, we may want to run operations, tests, etc on alternative
450 Furthermore, we may want to run operations, tests, etc on alternative
451 filesystems so we examine behavior on different filesystems.
451 filesystems so we examine behavior on different filesystems.
452
452
453 This function is used to facilitate executing operations on alternate
453 This function is used to facilitate executing operations on alternate
454 volumes.
454 volumes.
455 """
455 """
456 sftp = ssh_client.open_sftp()
456 sftp = ssh_client.open_sftp()
457
457
458 with sftp.open('/hgdev/prepare-hgdev', 'wb') as fh:
458 with sftp.open('/hgdev/prepare-hgdev', 'wb') as fh:
459 fh.write(PREPARE_HGDEV)
459 fh.write(PREPARE_HGDEV)
460 fh.chmod(0o0777)
460 fh.chmod(0o0777)
461
461
462 command = 'sudo /hgdev/prepare-hgdev %s' % filesystem
462 command = 'sudo /hgdev/prepare-hgdev %s' % filesystem
463 chan, stdin, stdout = exec_command(ssh_client, command)
463 chan, stdin, stdout = exec_command(ssh_client, command)
464 stdin.close()
464 stdin.close()
465
465
466 for line in stdout:
466 for line in stdout:
467 print(line, end='')
467 print(line, end='')
468
468
469 res = chan.recv_exit_status()
469 res = chan.recv_exit_status()
470
470
471 if res:
471 if res:
472 raise Exception('non-0 exit code updating working directory; %d' % res)
472 raise Exception('non-0 exit code updating working directory; %d' % res)
473
473
474
474
475 def synchronize_hg(
475 def synchronize_hg(
476 source_path: pathlib.Path, ec2_instance, revision: str = None
476 source_path: pathlib.Path, ec2_instance, revision: str = None
477 ):
477 ):
478 """Synchronize a local Mercurial source path to remote EC2 instance."""
478 """Synchronize a local Mercurial source path to remote EC2 instance."""
479
479
480 with tempfile.TemporaryDirectory() as temp_dir:
480 with tempfile.TemporaryDirectory() as temp_dir:
481 temp_dir = pathlib.Path(temp_dir)
481 temp_dir = pathlib.Path(temp_dir)
482
482
483 ssh_dir = temp_dir / '.ssh'
483 ssh_dir = temp_dir / '.ssh'
484 ssh_dir.mkdir()
484 ssh_dir.mkdir()
485 ssh_dir.chmod(0o0700)
485 ssh_dir.chmod(0o0700)
486
486
487 public_ip = ec2_instance.public_ip_address
487 public_ip = ec2_instance.public_ip_address
488
488
489 ssh_config = ssh_dir / 'config'
489 ssh_config = ssh_dir / 'config'
490
490
491 with ssh_config.open('w', encoding='utf-8') as fh:
491 with ssh_config.open('w', encoding='utf-8') as fh:
492 fh.write('Host %s\n' % public_ip)
492 fh.write('Host %s\n' % public_ip)
493 fh.write(' User hg\n')
493 fh.write(' User hg\n')
494 fh.write(' StrictHostKeyChecking no\n')
494 fh.write(' StrictHostKeyChecking no\n')
495 fh.write(' UserKnownHostsFile %s\n' % (ssh_dir / 'known_hosts'))
495 fh.write(' UserKnownHostsFile %s\n' % (ssh_dir / 'known_hosts'))
496 fh.write(' IdentityFile %s\n' % ec2_instance.ssh_private_key_path)
496 fh.write(' IdentityFile %s\n' % ec2_instance.ssh_private_key_path)
497
497
498 if not (source_path / '.hg').is_dir():
498 if not (source_path / '.hg').is_dir():
499 raise Exception(
499 raise Exception(
500 '%s is not a Mercurial repository; synchronization '
500 '%s is not a Mercurial repository; synchronization '
501 'not yet supported' % source_path
501 'not yet supported' % source_path
502 )
502 )
503
503
504 env = dict(os.environ)
504 env = dict(os.environ)
505 env['HGPLAIN'] = '1'
505 env['HGPLAIN'] = '1'
506 env['HGENCODING'] = 'utf-8'
506 env['HGENCODING'] = 'utf-8'
507
507
508 hg_bin = source_path / 'hg'
508 hg_bin = source_path / 'hg'
509
509
510 res = subprocess.run(
510 res = subprocess.run(
511 ['python2.7', str(hg_bin), 'log', '-r', revision, '-T', '{node}'],
511 ['python2.7', str(hg_bin), 'log', '-r', revision, '-T', '{node}'],
512 cwd=str(source_path),
512 cwd=str(source_path),
513 env=env,
513 env=env,
514 check=True,
514 check=True,
515 capture_output=True,
515 capture_output=True,
516 )
516 )
517
517
518 full_revision = res.stdout.decode('ascii')
518 full_revision = res.stdout.decode('ascii')
519
519
520 args = [
520 args = [
521 'python2.7',
521 'python2.7',
522 str(hg_bin),
522 str(hg_bin),
523 '--config',
523 '--config',
524 'ui.ssh=ssh -F %s' % ssh_config,
524 'ui.ssh=ssh -F %s' % ssh_config,
525 '--config',
525 '--config',
526 'ui.remotecmd=/hgdev/venv-bootstrap/bin/hg',
526 'ui.remotecmd=/hgdev/venv-bootstrap/bin/hg',
527 # Also ensure .hgtags changes are present so auto version
527 # Also ensure .hgtags changes are present so auto version
528 # calculation works.
528 # calculation works.
529 'push',
529 'push',
530 '-f',
530 '-f',
531 '-r',
531 '-r',
532 full_revision,
532 full_revision,
533 '-r',
533 '-r',
534 'file(.hgtags)',
534 'file(.hgtags)',
535 'ssh://%s//hgwork/src' % public_ip,
535 'ssh://%s//hgwork/src' % public_ip,
536 ]
536 ]
537
537
538 res = subprocess.run(args, cwd=str(source_path), env=env)
538 res = subprocess.run(args, cwd=str(source_path), env=env)
539
539
540 # Allow 1 (no-op) to not trigger error.
540 # Allow 1 (no-op) to not trigger error.
541 if res.returncode not in (0, 1):
541 if res.returncode not in (0, 1):
542 res.check_returncode()
542 res.check_returncode()
543
543
544 # TODO support synchronizing dirty working directory.
544 # TODO support synchronizing dirty working directory.
545
545
546 sftp = ec2_instance.ssh_client.open_sftp()
546 sftp = ec2_instance.ssh_client.open_sftp()
547
547
548 with sftp.open('/hgdev/hgup', 'wb') as fh:
548 with sftp.open('/hgdev/hgup', 'wb') as fh:
549 fh.write(HG_UPDATE_CLEAN)
549 fh.write(HG_UPDATE_CLEAN)
550 fh.chmod(0o0700)
550 fh.chmod(0o0700)
551
551
552 chan, stdin, stdout = exec_command(
552 chan, stdin, stdout = exec_command(
553 ec2_instance.ssh_client, '/hgdev/hgup %s' % full_revision
553 ec2_instance.ssh_client, '/hgdev/hgup %s' % full_revision
554 )
554 )
555 stdin.close()
555 stdin.close()
556
556
557 for line in stdout:
557 for line in stdout:
558 print(line, end='')
558 print(line, end='')
559
559
560 res = chan.recv_exit_status()
560 res = chan.recv_exit_status()
561
561
562 if res:
562 if res:
563 raise Exception(
563 raise Exception(
564 'non-0 exit code updating working directory; %d' % res
564 'non-0 exit code updating working directory; %d' % res
565 )
565 )
566
566
567
567
568 def run_tests(ssh_client, python_version, test_flags=None):
568 def run_tests(ssh_client, python_version, test_flags=None):
569 """Run tests on a remote Linux machine via an SSH client."""
569 """Run tests on a remote Linux machine via an SSH client."""
570 test_flags = test_flags or []
570 test_flags = test_flags or []
571
571
572 print('running tests')
572 print('running tests')
573
573
574 if python_version == 'system2':
574 if python_version == 'system2':
575 python = '/usr/bin/python2'
575 python = '/usr/bin/python2'
576 elif python_version == 'system3':
576 elif python_version == 'system3':
577 python = '/usr/bin/python3'
577 python = '/usr/bin/python3'
578 elif python_version.startswith('pypy'):
578 elif python_version.startswith('pypy'):
579 python = '/hgdev/pyenv/shims/%s' % python_version
579 python = '/hgdev/pyenv/shims/%s' % python_version
580 else:
580 else:
581 python = '/hgdev/pyenv/shims/python%s' % python_version
581 python = '/hgdev/pyenv/shims/python%s' % python_version
582
582
583 test_flags = ' '.join(shlex.quote(a) for a in test_flags)
583 test_flags = ' '.join(shlex.quote(a) for a in test_flags)
584
584
585 command = (
585 command = (
586 '/bin/sh -c "export TMPDIR=/hgwork/tmp; '
586 '/bin/sh -c "export TMPDIR=/hgwork/tmp; '
587 'cd /hgwork/src/tests && %s run-tests.py %s"' % (python, test_flags)
587 'cd /hgwork/src/tests && %s run-tests.py %s"' % (python, test_flags)
588 )
588 )
589
589
590 chan, stdin, stdout = exec_command(ssh_client, command)
590 chan, stdin, stdout = exec_command(ssh_client, command)
591
591
592 stdin.close()
592 stdin.close()
593
593
594 for line in stdout:
594 for line in stdout:
595 print(line, end='')
595 print(line, end='')
596
596
597 return chan.recv_exit_status()
597 return chan.recv_exit_status()
@@ -1,663 +1,669 b''
1 # windows.py - Automation specific to Windows
1 # windows.py - Automation specific to Windows
2 #
2 #
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.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 # no-check-code because Python 3 native.
8 # no-check-code because Python 3 native.
9
9
10 import datetime
10 import datetime
11 import os
11 import os
12 import paramiko
12 import paramiko
13 import pathlib
13 import pathlib
14 import re
14 import re
15 import subprocess
15 import subprocess
16 import tempfile
16 import tempfile
17
17
18 from .pypi import upload as pypi_upload
18 from .pypi import upload as pypi_upload
19 from .winrm import run_powershell
19 from .winrm import run_powershell
20
20
21
21
22 # PowerShell commands to activate a Visual Studio 2008 environment.
22 # PowerShell commands to activate a Visual Studio 2008 environment.
23 # This is essentially a port of vcvarsall.bat to PowerShell.
23 # This is essentially a port of vcvarsall.bat to PowerShell.
24 ACTIVATE_VC9_AMD64 = r'''
24 ACTIVATE_VC9_AMD64 = r'''
25 Write-Output "activating Visual Studio 2008 environment for AMD64"
25 Write-Output "activating Visual Studio 2008 environment for AMD64"
26 $root = "$env:LOCALAPPDATA\Programs\Common\Microsoft\Visual C++ for Python\9.0"
26 $root = "$env:LOCALAPPDATA\Programs\Common\Microsoft\Visual C++ for Python\9.0"
27 $Env:VCINSTALLDIR = "${root}\VC\"
27 $Env:VCINSTALLDIR = "${root}\VC\"
28 $Env:WindowsSdkDir = "${root}\WinSDK\"
28 $Env:WindowsSdkDir = "${root}\WinSDK\"
29 $Env:PATH = "${root}\VC\Bin\amd64;${root}\WinSDK\Bin\x64;${root}\WinSDK\Bin;$Env:PATH"
29 $Env:PATH = "${root}\VC\Bin\amd64;${root}\WinSDK\Bin\x64;${root}\WinSDK\Bin;$Env:PATH"
30 $Env:INCLUDE = "${root}\VC\Include;${root}\WinSDK\Include;$Env:PATH"
30 $Env:INCLUDE = "${root}\VC\Include;${root}\WinSDK\Include;$Env:PATH"
31 $Env:LIB = "${root}\VC\Lib\amd64;${root}\WinSDK\Lib\x64;$Env:LIB"
31 $Env:LIB = "${root}\VC\Lib\amd64;${root}\WinSDK\Lib\x64;$Env:LIB"
32 $Env:LIBPATH = "${root}\VC\Lib\amd64;${root}\WinSDK\Lib\x64;$Env:LIBPATH"
32 $Env:LIBPATH = "${root}\VC\Lib\amd64;${root}\WinSDK\Lib\x64;$Env:LIBPATH"
33 '''.lstrip()
33 '''.lstrip()
34
34
35 ACTIVATE_VC9_X86 = r'''
35 ACTIVATE_VC9_X86 = r'''
36 Write-Output "activating Visual Studio 2008 environment for x86"
36 Write-Output "activating Visual Studio 2008 environment for x86"
37 $root = "$env:LOCALAPPDATA\Programs\Common\Microsoft\Visual C++ for Python\9.0"
37 $root = "$env:LOCALAPPDATA\Programs\Common\Microsoft\Visual C++ for Python\9.0"
38 $Env:VCINSTALLDIR = "${root}\VC\"
38 $Env:VCINSTALLDIR = "${root}\VC\"
39 $Env:WindowsSdkDir = "${root}\WinSDK\"
39 $Env:WindowsSdkDir = "${root}\WinSDK\"
40 $Env:PATH = "${root}\VC\Bin;${root}\WinSDK\Bin;$Env:PATH"
40 $Env:PATH = "${root}\VC\Bin;${root}\WinSDK\Bin;$Env:PATH"
41 $Env:INCLUDE = "${root}\VC\Include;${root}\WinSDK\Include;$Env:INCLUDE"
41 $Env:INCLUDE = "${root}\VC\Include;${root}\WinSDK\Include;$Env:INCLUDE"
42 $Env:LIB = "${root}\VC\Lib;${root}\WinSDK\Lib;$Env:LIB"
42 $Env:LIB = "${root}\VC\Lib;${root}\WinSDK\Lib;$Env:LIB"
43 $Env:LIBPATH = "${root}\VC\lib;${root}\WinSDK\Lib;$Env:LIBPATH"
43 $Env:LIBPATH = "${root}\VC\lib;${root}\WinSDK\Lib;$Env:LIBPATH"
44 '''.lstrip()
44 '''.lstrip()
45
45
46 HG_PURGE = r'''
46 HG_PURGE = r'''
47 $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH"
47 $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH"
48 Set-Location C:\hgdev\src
48 Set-Location C:\hgdev\src
49 hg.exe --config extensions.purge= purge --all
49 hg.exe --config extensions.purge= purge --all
50 if ($LASTEXITCODE -ne 0) {
50 if ($LASTEXITCODE -ne 0) {
51 throw "process exited non-0: $LASTEXITCODE"
51 throw "process exited non-0: $LASTEXITCODE"
52 }
52 }
53 Write-Output "purged Mercurial repo"
53 Write-Output "purged Mercurial repo"
54 '''
54 '''
55
55
56 HG_UPDATE_CLEAN = r'''
56 HG_UPDATE_CLEAN = r'''
57 $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH"
57 $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH"
58 Set-Location C:\hgdev\src
58 Set-Location C:\hgdev\src
59 hg.exe --config extensions.purge= purge --all
59 hg.exe --config extensions.purge= purge --all
60 if ($LASTEXITCODE -ne 0) {{
60 if ($LASTEXITCODE -ne 0) {{
61 throw "process exited non-0: $LASTEXITCODE"
61 throw "process exited non-0: $LASTEXITCODE"
62 }}
62 }}
63 hg.exe update -C {revision}
63 hg.exe update -C {revision}
64 if ($LASTEXITCODE -ne 0) {{
64 if ($LASTEXITCODE -ne 0) {{
65 throw "process exited non-0: $LASTEXITCODE"
65 throw "process exited non-0: $LASTEXITCODE"
66 }}
66 }}
67 hg.exe log -r .
67 hg.exe log -r .
68 Write-Output "updated Mercurial working directory to {revision}"
68 Write-Output "updated Mercurial working directory to {revision}"
69 '''.lstrip()
69 '''.lstrip()
70
70
71 BUILD_INNO_PYTHON3 = r'''
71 BUILD_INNO_PYTHON3 = r'''
72 $Env:RUSTUP_HOME = "C:\hgdev\rustup"
72 $Env:RUSTUP_HOME = "C:\hgdev\rustup"
73 $Env:CARGO_HOME = "C:\hgdev\cargo"
73 $Env:CARGO_HOME = "C:\hgdev\cargo"
74 Set-Location C:\hgdev\src
74 Set-Location C:\hgdev\src
75 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --pyoxidizer-target {pyoxidizer_target} --version {version}
75 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --pyoxidizer-target {pyoxidizer_target} --version {version}
76 if ($LASTEXITCODE -ne 0) {{
76 if ($LASTEXITCODE -ne 0) {{
77 throw "process exited non-0: $LASTEXITCODE"
77 throw "process exited non-0: $LASTEXITCODE"
78 }}
78 }}
79 '''
79 '''
80
80
81 BUILD_INNO_PYTHON2 = r'''
81 BUILD_INNO_PYTHON2 = r'''
82 Set-Location C:\hgdev\src
82 Set-Location C:\hgdev\src
83 $python = "C:\hgdev\python27-{arch}\python.exe"
83 $python = "C:\hgdev\python27-{arch}\python.exe"
84 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --python $python {extra_args}
84 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --python $python {extra_args}
85 if ($LASTEXITCODE -ne 0) {{
85 if ($LASTEXITCODE -ne 0) {{
86 throw "process exited non-0: $LASTEXITCODE"
86 throw "process exited non-0: $LASTEXITCODE"
87 }}
87 }}
88 '''.lstrip()
88 '''.lstrip()
89
89
90 BUILD_WHEEL = r'''
90 BUILD_WHEEL = r'''
91 Set-Location C:\hgdev\src
91 Set-Location C:\hgdev\src
92 C:\hgdev\python{python_version}-{arch}\python.exe -m pip wheel --wheel-dir dist .
92 C:\hgdev\python{python_version}-{arch}\python.exe -m pip wheel --wheel-dir dist .
93 if ($LASTEXITCODE -ne 0) {{
93 if ($LASTEXITCODE -ne 0) {{
94 throw "process exited non-0: $LASTEXITCODE"
94 throw "process exited non-0: $LASTEXITCODE"
95 }}
95 }}
96 '''
96 '''
97
97
98 BUILD_WIX_PYTHON3 = r'''
98 BUILD_WIX_PYTHON3 = r'''
99 $Env:RUSTUP_HOME = "C:\hgdev\rustup"
99 $Env:RUSTUP_HOME = "C:\hgdev\rustup"
100 $Env:CARGO_HOME = "C:\hgdev\cargo"
100 $Env:CARGO_HOME = "C:\hgdev\cargo"
101 Set-Location C:\hgdev\src
101 Set-Location C:\hgdev\src
102 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --pyoxidizer-target {pyoxidizer_target} --version {version}
102 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --pyoxidizer-target {pyoxidizer_target} --version {version}
103 if ($LASTEXITCODE -ne 0) {{
103 if ($LASTEXITCODE -ne 0) {{
104 throw "process exited non-0: $LASTEXITCODE"
104 throw "process exited non-0: $LASTEXITCODE"
105 }}
105 }}
106 '''
106 '''
107
107
108 BUILD_WIX_PYTHON2 = r'''
108 BUILD_WIX_PYTHON2 = r'''
109 Set-Location C:\hgdev\src
109 Set-Location C:\hgdev\src
110 $python = "C:\hgdev\python27-{arch}\python.exe"
110 $python = "C:\hgdev\python27-{arch}\python.exe"
111 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --python $python {extra_args}
111 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --python $python {extra_args}
112 if ($LASTEXITCODE -ne 0) {{
112 if ($LASTEXITCODE -ne 0) {{
113 throw "process exited non-0: $LASTEXITCODE"
113 throw "process exited non-0: $LASTEXITCODE"
114 }}
114 }}
115 '''
115 '''
116
116
117 RUN_TESTS = r'''
117 RUN_TESTS = r'''
118 C:\hgdev\MinGW\msys\1.0\bin\sh.exe --login -c "cd /c/hgdev/src/tests && /c/hgdev/{python_path}/python.exe run-tests.py {test_flags}"
118 C:\hgdev\MinGW\msys\1.0\bin\sh.exe --login -c "cd /c/hgdev/src/tests && /c/hgdev/{python_path}/python.exe run-tests.py {test_flags}"
119 if ($LASTEXITCODE -ne 0) {{
119 if ($LASTEXITCODE -ne 0) {{
120 throw "process exited non-0: $LASTEXITCODE"
120 throw "process exited non-0: $LASTEXITCODE"
121 }}
121 }}
122 '''
122 '''
123
123
124 WHEEL_FILENAME_PYTHON27_X86 = 'mercurial-{version}-cp27-cp27m-win32.whl'
124 WHEEL_FILENAME_PYTHON27_X86 = 'mercurial-{version}-cp27-cp27m-win32.whl'
125 WHEEL_FILENAME_PYTHON27_X64 = 'mercurial-{version}-cp27-cp27m-win_amd64.whl'
125 WHEEL_FILENAME_PYTHON27_X64 = 'mercurial-{version}-cp27-cp27m-win_amd64.whl'
126 WHEEL_FILENAME_PYTHON37_X86 = 'mercurial-{version}-cp37-cp37m-win32.whl'
126 WHEEL_FILENAME_PYTHON37_X86 = 'mercurial-{version}-cp37-cp37m-win32.whl'
127 WHEEL_FILENAME_PYTHON37_X64 = 'mercurial-{version}-cp37-cp37m-win_amd64.whl'
127 WHEEL_FILENAME_PYTHON37_X64 = 'mercurial-{version}-cp37-cp37m-win_amd64.whl'
128 WHEEL_FILENAME_PYTHON38_X86 = 'mercurial-{version}-cp38-cp38-win32.whl'
128 WHEEL_FILENAME_PYTHON38_X86 = 'mercurial-{version}-cp38-cp38-win32.whl'
129 WHEEL_FILENAME_PYTHON38_X64 = 'mercurial-{version}-cp38-cp38-win_amd64.whl'
129 WHEEL_FILENAME_PYTHON38_X64 = 'mercurial-{version}-cp38-cp38-win_amd64.whl'
130 WHEEL_FILENAME_PYTHON39_X86 = 'mercurial-{version}-cp39-cp39-win32.whl'
131 WHEEL_FILENAME_PYTHON39_X64 = 'mercurial-{version}-cp39-cp39-win_amd64.whl'
130
132
131 EXE_FILENAME_PYTHON2_X86 = 'Mercurial-{version}-x86-python2.exe'
133 EXE_FILENAME_PYTHON2_X86 = 'Mercurial-{version}-x86-python2.exe'
132 EXE_FILENAME_PYTHON2_X64 = 'Mercurial-{version}-x64-python2.exe'
134 EXE_FILENAME_PYTHON2_X64 = 'Mercurial-{version}-x64-python2.exe'
133 EXE_FILENAME_PYTHON3_X86 = 'Mercurial-{version}-x86.exe'
135 EXE_FILENAME_PYTHON3_X86 = 'Mercurial-{version}-x86.exe'
134 EXE_FILENAME_PYTHON3_X64 = 'Mercurial-{version}-x64.exe'
136 EXE_FILENAME_PYTHON3_X64 = 'Mercurial-{version}-x64.exe'
135
137
136 MSI_FILENAME_PYTHON2_X86 = 'mercurial-{version}-x86-python2.msi'
138 MSI_FILENAME_PYTHON2_X86 = 'mercurial-{version}-x86-python2.msi'
137 MSI_FILENAME_PYTHON2_X64 = 'mercurial-{version}-x64-python2.msi'
139 MSI_FILENAME_PYTHON2_X64 = 'mercurial-{version}-x64-python2.msi'
138 MSI_FILENAME_PYTHON3_X86 = 'mercurial-{version}-x86.msi'
140 MSI_FILENAME_PYTHON3_X86 = 'mercurial-{version}-x86.msi'
139 MSI_FILENAME_PYTHON3_X64 = 'mercurial-{version}-x64.msi'
141 MSI_FILENAME_PYTHON3_X64 = 'mercurial-{version}-x64.msi'
140
142
141 MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows'
143 MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows'
142
144
143 X86_USER_AGENT_PATTERN = '.*Windows.*'
145 X86_USER_AGENT_PATTERN = '.*Windows.*'
144 X64_USER_AGENT_PATTERN = '.*Windows.*(WOW|x)64.*'
146 X64_USER_AGENT_PATTERN = '.*Windows.*(WOW|x)64.*'
145
147
146 EXE_PYTHON2_X86_DESCRIPTION = (
148 EXE_PYTHON2_X86_DESCRIPTION = (
147 'Mercurial {version} Inno Setup installer - x86 Windows (Python 2) '
149 'Mercurial {version} Inno Setup installer - x86 Windows (Python 2) '
148 '- does not require admin rights'
150 '- does not require admin rights'
149 )
151 )
150 EXE_PYTHON2_X64_DESCRIPTION = (
152 EXE_PYTHON2_X64_DESCRIPTION = (
151 'Mercurial {version} Inno Setup installer - x64 Windows (Python 2) '
153 'Mercurial {version} Inno Setup installer - x64 Windows (Python 2) '
152 '- does not require admin rights'
154 '- does not require admin rights'
153 )
155 )
154 # TODO remove Python version once Python 2 is dropped.
156 # TODO remove Python version once Python 2 is dropped.
155 EXE_PYTHON3_X86_DESCRIPTION = (
157 EXE_PYTHON3_X86_DESCRIPTION = (
156 'Mercurial {version} Inno Setup installer - x86 Windows (Python 3) '
158 'Mercurial {version} Inno Setup installer - x86 Windows (Python 3) '
157 '- does not require admin rights'
159 '- does not require admin rights'
158 )
160 )
159 EXE_PYTHON3_X64_DESCRIPTION = (
161 EXE_PYTHON3_X64_DESCRIPTION = (
160 'Mercurial {version} Inno Setup installer - x64 Windows (Python 3) '
162 'Mercurial {version} Inno Setup installer - x64 Windows (Python 3) '
161 '- does not require admin rights'
163 '- does not require admin rights'
162 )
164 )
163 MSI_PYTHON2_X86_DESCRIPTION = (
165 MSI_PYTHON2_X86_DESCRIPTION = (
164 'Mercurial {version} MSI installer - x86 Windows (Python 2) '
166 'Mercurial {version} MSI installer - x86 Windows (Python 2) '
165 '- requires admin rights'
167 '- requires admin rights'
166 )
168 )
167 MSI_PYTHON2_X64_DESCRIPTION = (
169 MSI_PYTHON2_X64_DESCRIPTION = (
168 'Mercurial {version} MSI installer - x64 Windows (Python 2) '
170 'Mercurial {version} MSI installer - x64 Windows (Python 2) '
169 '- requires admin rights'
171 '- requires admin rights'
170 )
172 )
171 MSI_PYTHON3_X86_DESCRIPTION = (
173 MSI_PYTHON3_X86_DESCRIPTION = (
172 'Mercurial {version} MSI installer - x86 Windows (Python 3) '
174 'Mercurial {version} MSI installer - x86 Windows (Python 3) '
173 '- requires admin rights'
175 '- requires admin rights'
174 )
176 )
175 MSI_PYTHON3_X64_DESCRIPTION = (
177 MSI_PYTHON3_X64_DESCRIPTION = (
176 'Mercurial {version} MSI installer - x64 Windows (Python 3) '
178 'Mercurial {version} MSI installer - x64 Windows (Python 3) '
177 '- requires admin rights'
179 '- requires admin rights'
178 )
180 )
179
181
180
182
181 def get_vc_prefix(arch):
183 def get_vc_prefix(arch):
182 if arch == 'x86':
184 if arch == 'x86':
183 return ACTIVATE_VC9_X86
185 return ACTIVATE_VC9_X86
184 elif arch == 'x64':
186 elif arch == 'x64':
185 return ACTIVATE_VC9_AMD64
187 return ACTIVATE_VC9_AMD64
186 else:
188 else:
187 raise ValueError('illegal arch: %s; must be x86 or x64' % arch)
189 raise ValueError('illegal arch: %s; must be x86 or x64' % arch)
188
190
189
191
190 def fix_authorized_keys_permissions(winrm_client, path):
192 def fix_authorized_keys_permissions(winrm_client, path):
191 commands = [
193 commands = [
192 '$ErrorActionPreference = "Stop"',
194 '$ErrorActionPreference = "Stop"',
193 'Repair-AuthorizedKeyPermission -FilePath %s -Confirm:$false' % path,
195 'Repair-AuthorizedKeyPermission -FilePath %s -Confirm:$false' % path,
194 r'icacls %s /remove:g "NT Service\sshd"' % path,
196 r'icacls %s /remove:g "NT Service\sshd"' % path,
195 ]
197 ]
196
198
197 run_powershell(winrm_client, '\n'.join(commands))
199 run_powershell(winrm_client, '\n'.join(commands))
198
200
199
201
200 def synchronize_hg(hg_repo: pathlib.Path, revision: str, ec2_instance):
202 def synchronize_hg(hg_repo: pathlib.Path, revision: str, ec2_instance):
201 """Synchronize local Mercurial repo to remote EC2 instance."""
203 """Synchronize local Mercurial repo to remote EC2 instance."""
202
204
203 winrm_client = ec2_instance.winrm_client
205 winrm_client = ec2_instance.winrm_client
204
206
205 with tempfile.TemporaryDirectory() as temp_dir:
207 with tempfile.TemporaryDirectory() as temp_dir:
206 temp_dir = pathlib.Path(temp_dir)
208 temp_dir = pathlib.Path(temp_dir)
207
209
208 ssh_dir = temp_dir / '.ssh'
210 ssh_dir = temp_dir / '.ssh'
209 ssh_dir.mkdir()
211 ssh_dir.mkdir()
210 ssh_dir.chmod(0o0700)
212 ssh_dir.chmod(0o0700)
211
213
212 # Generate SSH key to use for communication.
214 # Generate SSH key to use for communication.
213 subprocess.run(
215 subprocess.run(
214 [
216 [
215 'ssh-keygen',
217 'ssh-keygen',
216 '-t',
218 '-t',
217 'rsa',
219 'rsa',
218 '-b',
220 '-b',
219 '4096',
221 '4096',
220 '-N',
222 '-N',
221 '',
223 '',
222 '-f',
224 '-f',
223 str(ssh_dir / 'id_rsa'),
225 str(ssh_dir / 'id_rsa'),
224 ],
226 ],
225 check=True,
227 check=True,
226 capture_output=True,
228 capture_output=True,
227 )
229 )
228
230
229 # Add it to ~/.ssh/authorized_keys on remote.
231 # Add it to ~/.ssh/authorized_keys on remote.
230 # This assumes the file doesn't already exist.
232 # This assumes the file doesn't already exist.
231 authorized_keys = r'c:\Users\Administrator\.ssh\authorized_keys'
233 authorized_keys = r'c:\Users\Administrator\.ssh\authorized_keys'
232 winrm_client.execute_cmd(r'mkdir c:\Users\Administrator\.ssh')
234 winrm_client.execute_cmd(r'mkdir c:\Users\Administrator\.ssh')
233 winrm_client.copy(str(ssh_dir / 'id_rsa.pub'), authorized_keys)
235 winrm_client.copy(str(ssh_dir / 'id_rsa.pub'), authorized_keys)
234 fix_authorized_keys_permissions(winrm_client, authorized_keys)
236 fix_authorized_keys_permissions(winrm_client, authorized_keys)
235
237
236 public_ip = ec2_instance.public_ip_address
238 public_ip = ec2_instance.public_ip_address
237
239
238 ssh_config = temp_dir / '.ssh' / 'config'
240 ssh_config = temp_dir / '.ssh' / 'config'
239
241
240 with open(ssh_config, 'w', encoding='utf-8') as fh:
242 with open(ssh_config, 'w', encoding='utf-8') as fh:
241 fh.write('Host %s\n' % public_ip)
243 fh.write('Host %s\n' % public_ip)
242 fh.write(' User Administrator\n')
244 fh.write(' User Administrator\n')
243 fh.write(' StrictHostKeyChecking no\n')
245 fh.write(' StrictHostKeyChecking no\n')
244 fh.write(' UserKnownHostsFile %s\n' % (ssh_dir / 'known_hosts'))
246 fh.write(' UserKnownHostsFile %s\n' % (ssh_dir / 'known_hosts'))
245 fh.write(' IdentityFile %s\n' % (ssh_dir / 'id_rsa'))
247 fh.write(' IdentityFile %s\n' % (ssh_dir / 'id_rsa'))
246
248
247 if not (hg_repo / '.hg').is_dir():
249 if not (hg_repo / '.hg').is_dir():
248 raise Exception(
250 raise Exception(
249 '%s is not a Mercurial repository; '
251 '%s is not a Mercurial repository; '
250 'synchronization not yet supported' % hg_repo
252 'synchronization not yet supported' % hg_repo
251 )
253 )
252
254
253 env = dict(os.environ)
255 env = dict(os.environ)
254 env['HGPLAIN'] = '1'
256 env['HGPLAIN'] = '1'
255 env['HGENCODING'] = 'utf-8'
257 env['HGENCODING'] = 'utf-8'
256
258
257 hg_bin = hg_repo / 'hg'
259 hg_bin = hg_repo / 'hg'
258
260
259 res = subprocess.run(
261 res = subprocess.run(
260 ['python2.7', str(hg_bin), 'log', '-r', revision, '-T', '{node}'],
262 ['python2.7', str(hg_bin), 'log', '-r', revision, '-T', '{node}'],
261 cwd=str(hg_repo),
263 cwd=str(hg_repo),
262 env=env,
264 env=env,
263 check=True,
265 check=True,
264 capture_output=True,
266 capture_output=True,
265 )
267 )
266
268
267 full_revision = res.stdout.decode('ascii')
269 full_revision = res.stdout.decode('ascii')
268
270
269 args = [
271 args = [
270 'python2.7',
272 'python2.7',
271 hg_bin,
273 hg_bin,
272 '--config',
274 '--config',
273 'ui.ssh=ssh -F %s' % ssh_config,
275 'ui.ssh=ssh -F %s' % ssh_config,
274 '--config',
276 '--config',
275 'ui.remotecmd=c:/hgdev/venv-bootstrap/Scripts/hg.exe',
277 'ui.remotecmd=c:/hgdev/venv-bootstrap/Scripts/hg.exe',
276 # Also ensure .hgtags changes are present so auto version
278 # Also ensure .hgtags changes are present so auto version
277 # calculation works.
279 # calculation works.
278 'push',
280 'push',
279 '-f',
281 '-f',
280 '-r',
282 '-r',
281 full_revision,
283 full_revision,
282 '-r',
284 '-r',
283 'file(.hgtags)',
285 'file(.hgtags)',
284 'ssh://%s/c:/hgdev/src' % public_ip,
286 'ssh://%s/c:/hgdev/src' % public_ip,
285 ]
287 ]
286
288
287 res = subprocess.run(args, cwd=str(hg_repo), env=env)
289 res = subprocess.run(args, cwd=str(hg_repo), env=env)
288
290
289 # Allow 1 (no-op) to not trigger error.
291 # Allow 1 (no-op) to not trigger error.
290 if res.returncode not in (0, 1):
292 if res.returncode not in (0, 1):
291 res.check_returncode()
293 res.check_returncode()
292
294
293 run_powershell(
295 run_powershell(
294 winrm_client, HG_UPDATE_CLEAN.format(revision=full_revision)
296 winrm_client, HG_UPDATE_CLEAN.format(revision=full_revision)
295 )
297 )
296
298
297 # TODO detect dirty local working directory and synchronize accordingly.
299 # TODO detect dirty local working directory and synchronize accordingly.
298
300
299
301
300 def purge_hg(winrm_client):
302 def purge_hg(winrm_client):
301 """Purge the Mercurial source repository on an EC2 instance."""
303 """Purge the Mercurial source repository on an EC2 instance."""
302 run_powershell(winrm_client, HG_PURGE)
304 run_powershell(winrm_client, HG_PURGE)
303
305
304
306
305 def find_latest_dist(winrm_client, pattern):
307 def find_latest_dist(winrm_client, pattern):
306 """Find path to newest file in dist/ directory matching a pattern."""
308 """Find path to newest file in dist/ directory matching a pattern."""
307
309
308 res = winrm_client.execute_ps(
310 res = winrm_client.execute_ps(
309 r'$v = Get-ChildItem -Path C:\hgdev\src\dist -Filter "%s" '
311 r'$v = Get-ChildItem -Path C:\hgdev\src\dist -Filter "%s" '
310 '| Sort-Object LastWriteTime -Descending '
312 '| Sort-Object LastWriteTime -Descending '
311 '| Select-Object -First 1\n'
313 '| Select-Object -First 1\n'
312 '$v.name' % pattern
314 '$v.name' % pattern
313 )
315 )
314 return res[0]
316 return res[0]
315
317
316
318
317 def copy_latest_dist(winrm_client, pattern, dest_path):
319 def copy_latest_dist(winrm_client, pattern, dest_path):
318 """Copy latest file matching pattern in dist/ directory.
320 """Copy latest file matching pattern in dist/ directory.
319
321
320 Given a WinRM client and a file pattern, find the latest file on the remote
322 Given a WinRM client and a file pattern, find the latest file on the remote
321 matching that pattern and copy it to the ``dest_path`` directory on the
323 matching that pattern and copy it to the ``dest_path`` directory on the
322 local machine.
324 local machine.
323 """
325 """
324 latest = find_latest_dist(winrm_client, pattern)
326 latest = find_latest_dist(winrm_client, pattern)
325 source = r'C:\hgdev\src\dist\%s' % latest
327 source = r'C:\hgdev\src\dist\%s' % latest
326 dest = dest_path / latest
328 dest = dest_path / latest
327 print('copying %s to %s' % (source, dest))
329 print('copying %s to %s' % (source, dest))
328 winrm_client.fetch(source, str(dest))
330 winrm_client.fetch(source, str(dest))
329
331
330
332
331 def build_inno_installer(
333 def build_inno_installer(
332 winrm_client,
334 winrm_client,
333 python_version: int,
335 python_version: int,
334 arch: str,
336 arch: str,
335 dest_path: pathlib.Path,
337 dest_path: pathlib.Path,
336 version=None,
338 version=None,
337 ):
339 ):
338 """Build the Inno Setup installer on a remote machine.
340 """Build the Inno Setup installer on a remote machine.
339
341
340 Using a WinRM client, remote commands are executed to build
342 Using a WinRM client, remote commands are executed to build
341 a Mercurial Inno Setup installer.
343 a Mercurial Inno Setup installer.
342 """
344 """
343 print(
345 print(
344 'building Inno Setup installer for Python %d %s'
346 'building Inno Setup installer for Python %d %s'
345 % (python_version, arch)
347 % (python_version, arch)
346 )
348 )
347
349
348 if python_version == 3:
350 if python_version == 3:
349 # TODO fix this limitation in packaging code
351 # TODO fix this limitation in packaging code
350 if not version:
352 if not version:
351 raise Exception(
353 raise Exception(
352 "version string is required when building for Python 3"
354 "version string is required when building for Python 3"
353 )
355 )
354
356
355 if arch == "x86":
357 if arch == "x86":
356 target_triple = "i686-pc-windows-msvc"
358 target_triple = "i686-pc-windows-msvc"
357 elif arch == "x64":
359 elif arch == "x64":
358 target_triple = "x86_64-pc-windows-msvc"
360 target_triple = "x86_64-pc-windows-msvc"
359 else:
361 else:
360 raise Exception("unhandled arch: %s" % arch)
362 raise Exception("unhandled arch: %s" % arch)
361
363
362 ps = BUILD_INNO_PYTHON3.format(
364 ps = BUILD_INNO_PYTHON3.format(
363 pyoxidizer_target=target_triple, version=version,
365 pyoxidizer_target=target_triple, version=version,
364 )
366 )
365 else:
367 else:
366 extra_args = []
368 extra_args = []
367 if version:
369 if version:
368 extra_args.extend(['--version', version])
370 extra_args.extend(['--version', version])
369
371
370 ps = get_vc_prefix(arch) + BUILD_INNO_PYTHON2.format(
372 ps = get_vc_prefix(arch) + BUILD_INNO_PYTHON2.format(
371 arch=arch, extra_args=' '.join(extra_args)
373 arch=arch, extra_args=' '.join(extra_args)
372 )
374 )
373
375
374 run_powershell(winrm_client, ps)
376 run_powershell(winrm_client, ps)
375 copy_latest_dist(winrm_client, '*.exe', dest_path)
377 copy_latest_dist(winrm_client, '*.exe', dest_path)
376
378
377
379
378 def build_wheel(
380 def build_wheel(
379 winrm_client, python_version: str, arch: str, dest_path: pathlib.Path
381 winrm_client, python_version: str, arch: str, dest_path: pathlib.Path
380 ):
382 ):
381 """Build Python wheels on a remote machine.
383 """Build Python wheels on a remote machine.
382
384
383 Using a WinRM client, remote commands are executed to build a Python wheel
385 Using a WinRM client, remote commands are executed to build a Python wheel
384 for Mercurial.
386 for Mercurial.
385 """
387 """
386 print('Building Windows wheel for Python %s %s' % (python_version, arch))
388 print('Building Windows wheel for Python %s %s' % (python_version, arch))
387
389
388 ps = BUILD_WHEEL.format(
390 ps = BUILD_WHEEL.format(
389 python_version=python_version.replace(".", ""), arch=arch
391 python_version=python_version.replace(".", ""), arch=arch
390 )
392 )
391
393
392 # Python 2.7 requires an activated environment.
394 # Python 2.7 requires an activated environment.
393 if python_version == "2.7":
395 if python_version == "2.7":
394 ps = get_vc_prefix(arch) + ps
396 ps = get_vc_prefix(arch) + ps
395
397
396 run_powershell(winrm_client, ps)
398 run_powershell(winrm_client, ps)
397 copy_latest_dist(winrm_client, '*.whl', dest_path)
399 copy_latest_dist(winrm_client, '*.whl', dest_path)
398
400
399
401
400 def build_wix_installer(
402 def build_wix_installer(
401 winrm_client,
403 winrm_client,
402 python_version: int,
404 python_version: int,
403 arch: str,
405 arch: str,
404 dest_path: pathlib.Path,
406 dest_path: pathlib.Path,
405 version=None,
407 version=None,
406 ):
408 ):
407 """Build the WiX installer on a remote machine.
409 """Build the WiX installer on a remote machine.
408
410
409 Using a WinRM client, remote commands are executed to build a WiX installer.
411 Using a WinRM client, remote commands are executed to build a WiX installer.
410 """
412 """
411 print('Building WiX installer for Python %d %s' % (python_version, arch))
413 print('Building WiX installer for Python %d %s' % (python_version, arch))
412
414
413 if python_version == 3:
415 if python_version == 3:
414 # TODO fix this limitation in packaging code
416 # TODO fix this limitation in packaging code
415 if not version:
417 if not version:
416 raise Exception(
418 raise Exception(
417 "version string is required when building for Python 3"
419 "version string is required when building for Python 3"
418 )
420 )
419
421
420 if arch == "x86":
422 if arch == "x86":
421 target_triple = "i686-pc-windows-msvc"
423 target_triple = "i686-pc-windows-msvc"
422 elif arch == "x64":
424 elif arch == "x64":
423 target_triple = "x86_64-pc-windows-msvc"
425 target_triple = "x86_64-pc-windows-msvc"
424 else:
426 else:
425 raise Exception("unhandled arch: %s" % arch)
427 raise Exception("unhandled arch: %s" % arch)
426
428
427 ps = BUILD_WIX_PYTHON3.format(
429 ps = BUILD_WIX_PYTHON3.format(
428 pyoxidizer_target=target_triple, version=version,
430 pyoxidizer_target=target_triple, version=version,
429 )
431 )
430 else:
432 else:
431 extra_args = []
433 extra_args = []
432 if version:
434 if version:
433 extra_args.extend(['--version', version])
435 extra_args.extend(['--version', version])
434
436
435 ps = get_vc_prefix(arch) + BUILD_WIX_PYTHON2.format(
437 ps = get_vc_prefix(arch) + BUILD_WIX_PYTHON2.format(
436 arch=arch, extra_args=' '.join(extra_args)
438 arch=arch, extra_args=' '.join(extra_args)
437 )
439 )
438
440
439 run_powershell(winrm_client, ps)
441 run_powershell(winrm_client, ps)
440 copy_latest_dist(winrm_client, '*.msi', dest_path)
442 copy_latest_dist(winrm_client, '*.msi', dest_path)
441
443
442
444
443 def run_tests(winrm_client, python_version, arch, test_flags=''):
445 def run_tests(winrm_client, python_version, arch, test_flags=''):
444 """Run tests on a remote Windows machine.
446 """Run tests on a remote Windows machine.
445
447
446 ``python_version`` is a ``X.Y`` string like ``2.7`` or ``3.7``.
448 ``python_version`` is a ``X.Y`` string like ``2.7`` or ``3.7``.
447 ``arch`` is ``x86`` or ``x64``.
449 ``arch`` is ``x86`` or ``x64``.
448 ``test_flags`` is a str representing extra arguments to pass to
450 ``test_flags`` is a str representing extra arguments to pass to
449 ``run-tests.py``.
451 ``run-tests.py``.
450 """
452 """
451 if not re.match(r'\d\.\d', python_version):
453 if not re.match(r'\d\.\d', python_version):
452 raise ValueError(
454 raise ValueError(
453 r'python_version must be \d.\d; got %s' % python_version
455 r'python_version must be \d.\d; got %s' % python_version
454 )
456 )
455
457
456 if arch not in ('x86', 'x64'):
458 if arch not in ('x86', 'x64'):
457 raise ValueError('arch must be x86 or x64; got %s' % arch)
459 raise ValueError('arch must be x86 or x64; got %s' % arch)
458
460
459 python_path = 'python%s-%s' % (python_version.replace('.', ''), arch)
461 python_path = 'python%s-%s' % (python_version.replace('.', ''), arch)
460
462
461 ps = RUN_TESTS.format(python_path=python_path, test_flags=test_flags or '',)
463 ps = RUN_TESTS.format(python_path=python_path, test_flags=test_flags or '',)
462
464
463 run_powershell(winrm_client, ps)
465 run_powershell(winrm_client, ps)
464
466
465
467
466 def resolve_wheel_artifacts(dist_path: pathlib.Path, version: str):
468 def resolve_wheel_artifacts(dist_path: pathlib.Path, version: str):
467 return (
469 return (
468 dist_path / WHEEL_FILENAME_PYTHON27_X86.format(version=version),
470 dist_path / WHEEL_FILENAME_PYTHON27_X86.format(version=version),
469 dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version),
471 dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version),
470 dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version),
472 dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version),
471 dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version),
473 dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version),
472 dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version),
474 dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version),
473 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version),
475 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version),
476 dist_path / WHEEL_FILENAME_PYTHON39_X86.format(version=version),
477 dist_path / WHEEL_FILENAME_PYTHON39_X64.format(version=version),
474 )
478 )
475
479
476
480
477 def resolve_all_artifacts(dist_path: pathlib.Path, version: str):
481 def resolve_all_artifacts(dist_path: pathlib.Path, version: str):
478 return (
482 return (
479 dist_path / WHEEL_FILENAME_PYTHON27_X86.format(version=version),
483 dist_path / WHEEL_FILENAME_PYTHON27_X86.format(version=version),
480 dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version),
484 dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version),
481 dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version),
485 dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version),
482 dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version),
486 dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version),
483 dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version),
487 dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version),
484 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version),
488 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version),
489 dist_path / WHEEL_FILENAME_PYTHON39_X86.format(version=version),
490 dist_path / WHEEL_FILENAME_PYTHON39_X64.format(version=version),
485 dist_path / EXE_FILENAME_PYTHON2_X86.format(version=version),
491 dist_path / EXE_FILENAME_PYTHON2_X86.format(version=version),
486 dist_path / EXE_FILENAME_PYTHON2_X64.format(version=version),
492 dist_path / EXE_FILENAME_PYTHON2_X64.format(version=version),
487 dist_path / EXE_FILENAME_PYTHON3_X86.format(version=version),
493 dist_path / EXE_FILENAME_PYTHON3_X86.format(version=version),
488 dist_path / EXE_FILENAME_PYTHON3_X64.format(version=version),
494 dist_path / EXE_FILENAME_PYTHON3_X64.format(version=version),
489 dist_path / MSI_FILENAME_PYTHON2_X86.format(version=version),
495 dist_path / MSI_FILENAME_PYTHON2_X86.format(version=version),
490 dist_path / MSI_FILENAME_PYTHON2_X64.format(version=version),
496 dist_path / MSI_FILENAME_PYTHON2_X64.format(version=version),
491 dist_path / MSI_FILENAME_PYTHON3_X86.format(version=version),
497 dist_path / MSI_FILENAME_PYTHON3_X86.format(version=version),
492 dist_path / MSI_FILENAME_PYTHON3_X64.format(version=version),
498 dist_path / MSI_FILENAME_PYTHON3_X64.format(version=version),
493 )
499 )
494
500
495
501
496 def generate_latest_dat(version: str):
502 def generate_latest_dat(version: str):
497 python2_x86_exe_filename = EXE_FILENAME_PYTHON2_X86.format(version=version)
503 python2_x86_exe_filename = EXE_FILENAME_PYTHON2_X86.format(version=version)
498 python2_x64_exe_filename = EXE_FILENAME_PYTHON2_X64.format(version=version)
504 python2_x64_exe_filename = EXE_FILENAME_PYTHON2_X64.format(version=version)
499 python3_x86_exe_filename = EXE_FILENAME_PYTHON3_X86.format(version=version)
505 python3_x86_exe_filename = EXE_FILENAME_PYTHON3_X86.format(version=version)
500 python3_x64_exe_filename = EXE_FILENAME_PYTHON3_X64.format(version=version)
506 python3_x64_exe_filename = EXE_FILENAME_PYTHON3_X64.format(version=version)
501 python2_x86_msi_filename = MSI_FILENAME_PYTHON2_X86.format(version=version)
507 python2_x86_msi_filename = MSI_FILENAME_PYTHON2_X86.format(version=version)
502 python2_x64_msi_filename = MSI_FILENAME_PYTHON2_X64.format(version=version)
508 python2_x64_msi_filename = MSI_FILENAME_PYTHON2_X64.format(version=version)
503 python3_x86_msi_filename = MSI_FILENAME_PYTHON3_X86.format(version=version)
509 python3_x86_msi_filename = MSI_FILENAME_PYTHON3_X86.format(version=version)
504 python3_x64_msi_filename = MSI_FILENAME_PYTHON3_X64.format(version=version)
510 python3_x64_msi_filename = MSI_FILENAME_PYTHON3_X64.format(version=version)
505
511
506 entries = (
512 entries = (
507 (
513 (
508 '10',
514 '10',
509 version,
515 version,
510 X86_USER_AGENT_PATTERN,
516 X86_USER_AGENT_PATTERN,
511 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_exe_filename),
517 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_exe_filename),
512 EXE_PYTHON3_X86_DESCRIPTION.format(version=version),
518 EXE_PYTHON3_X86_DESCRIPTION.format(version=version),
513 ),
519 ),
514 (
520 (
515 '10',
521 '10',
516 version,
522 version,
517 X64_USER_AGENT_PATTERN,
523 X64_USER_AGENT_PATTERN,
518 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_exe_filename),
524 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_exe_filename),
519 EXE_PYTHON3_X64_DESCRIPTION.format(version=version),
525 EXE_PYTHON3_X64_DESCRIPTION.format(version=version),
520 ),
526 ),
521 (
527 (
522 '9',
528 '9',
523 version,
529 version,
524 X86_USER_AGENT_PATTERN,
530 X86_USER_AGENT_PATTERN,
525 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x86_exe_filename),
531 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x86_exe_filename),
526 EXE_PYTHON2_X86_DESCRIPTION.format(version=version),
532 EXE_PYTHON2_X86_DESCRIPTION.format(version=version),
527 ),
533 ),
528 (
534 (
529 '9',
535 '9',
530 version,
536 version,
531 X64_USER_AGENT_PATTERN,
537 X64_USER_AGENT_PATTERN,
532 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x64_exe_filename),
538 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x64_exe_filename),
533 EXE_PYTHON2_X64_DESCRIPTION.format(version=version),
539 EXE_PYTHON2_X64_DESCRIPTION.format(version=version),
534 ),
540 ),
535 (
541 (
536 '10',
542 '10',
537 version,
543 version,
538 X86_USER_AGENT_PATTERN,
544 X86_USER_AGENT_PATTERN,
539 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_msi_filename),
545 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_msi_filename),
540 MSI_PYTHON3_X86_DESCRIPTION.format(version=version),
546 MSI_PYTHON3_X86_DESCRIPTION.format(version=version),
541 ),
547 ),
542 (
548 (
543 '10',
549 '10',
544 version,
550 version,
545 X64_USER_AGENT_PATTERN,
551 X64_USER_AGENT_PATTERN,
546 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_msi_filename),
552 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_msi_filename),
547 MSI_PYTHON3_X64_DESCRIPTION.format(version=version),
553 MSI_PYTHON3_X64_DESCRIPTION.format(version=version),
548 ),
554 ),
549 (
555 (
550 '9',
556 '9',
551 version,
557 version,
552 X86_USER_AGENT_PATTERN,
558 X86_USER_AGENT_PATTERN,
553 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x86_msi_filename),
559 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x86_msi_filename),
554 MSI_PYTHON2_X86_DESCRIPTION.format(version=version),
560 MSI_PYTHON2_X86_DESCRIPTION.format(version=version),
555 ),
561 ),
556 (
562 (
557 '9',
563 '9',
558 version,
564 version,
559 X64_USER_AGENT_PATTERN,
565 X64_USER_AGENT_PATTERN,
560 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x64_msi_filename),
566 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x64_msi_filename),
561 MSI_PYTHON2_X64_DESCRIPTION.format(version=version),
567 MSI_PYTHON2_X64_DESCRIPTION.format(version=version),
562 ),
568 ),
563 )
569 )
564
570
565 lines = ['\t'.join(e) for e in entries]
571 lines = ['\t'.join(e) for e in entries]
566
572
567 return '\n'.join(lines) + '\n'
573 return '\n'.join(lines) + '\n'
568
574
569
575
570 def publish_artifacts_pypi(dist_path: pathlib.Path, version: str):
576 def publish_artifacts_pypi(dist_path: pathlib.Path, version: str):
571 """Publish Windows release artifacts to PyPI."""
577 """Publish Windows release artifacts to PyPI."""
572
578
573 wheel_paths = resolve_wheel_artifacts(dist_path, version)
579 wheel_paths = resolve_wheel_artifacts(dist_path, version)
574
580
575 for p in wheel_paths:
581 for p in wheel_paths:
576 if not p.exists():
582 if not p.exists():
577 raise Exception('%s not found' % p)
583 raise Exception('%s not found' % p)
578
584
579 print('uploading wheels to PyPI (you may be prompted for credentials)')
585 print('uploading wheels to PyPI (you may be prompted for credentials)')
580 pypi_upload(wheel_paths)
586 pypi_upload(wheel_paths)
581
587
582
588
583 def publish_artifacts_mercurial_scm_org(
589 def publish_artifacts_mercurial_scm_org(
584 dist_path: pathlib.Path, version: str, ssh_username=None
590 dist_path: pathlib.Path, version: str, ssh_username=None
585 ):
591 ):
586 """Publish Windows release artifacts to mercurial-scm.org."""
592 """Publish Windows release artifacts to mercurial-scm.org."""
587 all_paths = resolve_all_artifacts(dist_path, version)
593 all_paths = resolve_all_artifacts(dist_path, version)
588
594
589 for p in all_paths:
595 for p in all_paths:
590 if not p.exists():
596 if not p.exists():
591 raise Exception('%s not found' % p)
597 raise Exception('%s not found' % p)
592
598
593 client = paramiko.SSHClient()
599 client = paramiko.SSHClient()
594 client.load_system_host_keys()
600 client.load_system_host_keys()
595 # We assume the system SSH configuration knows how to connect.
601 # We assume the system SSH configuration knows how to connect.
596 print('connecting to mercurial-scm.org via ssh...')
602 print('connecting to mercurial-scm.org via ssh...')
597 try:
603 try:
598 client.connect('mercurial-scm.org', username=ssh_username)
604 client.connect('mercurial-scm.org', username=ssh_username)
599 except paramiko.AuthenticationException:
605 except paramiko.AuthenticationException:
600 print('error authenticating; is an SSH key available in an SSH agent?')
606 print('error authenticating; is an SSH key available in an SSH agent?')
601 raise
607 raise
602
608
603 print('SSH connection established')
609 print('SSH connection established')
604
610
605 print('opening SFTP client...')
611 print('opening SFTP client...')
606 sftp = client.open_sftp()
612 sftp = client.open_sftp()
607 print('SFTP client obtained')
613 print('SFTP client obtained')
608
614
609 for p in all_paths:
615 for p in all_paths:
610 dest_path = '/var/www/release/windows/%s' % p.name
616 dest_path = '/var/www/release/windows/%s' % p.name
611 print('uploading %s to %s' % (p, dest_path))
617 print('uploading %s to %s' % (p, dest_path))
612
618
613 with p.open('rb') as fh:
619 with p.open('rb') as fh:
614 data = fh.read()
620 data = fh.read()
615
621
616 with sftp.open(dest_path, 'wb') as fh:
622 with sftp.open(dest_path, 'wb') as fh:
617 fh.write(data)
623 fh.write(data)
618 fh.chmod(0o0664)
624 fh.chmod(0o0664)
619
625
620 latest_dat_path = '/var/www/release/windows/latest.dat'
626 latest_dat_path = '/var/www/release/windows/latest.dat'
621
627
622 now = datetime.datetime.utcnow()
628 now = datetime.datetime.utcnow()
623 backup_path = dist_path / (
629 backup_path = dist_path / (
624 'latest-windows-%s.dat' % now.strftime('%Y%m%dT%H%M%S')
630 'latest-windows-%s.dat' % now.strftime('%Y%m%dT%H%M%S')
625 )
631 )
626 print('backing up %s to %s' % (latest_dat_path, backup_path))
632 print('backing up %s to %s' % (latest_dat_path, backup_path))
627
633
628 with sftp.open(latest_dat_path, 'rb') as fh:
634 with sftp.open(latest_dat_path, 'rb') as fh:
629 latest_dat_old = fh.read()
635 latest_dat_old = fh.read()
630
636
631 with backup_path.open('wb') as fh:
637 with backup_path.open('wb') as fh:
632 fh.write(latest_dat_old)
638 fh.write(latest_dat_old)
633
639
634 print('writing %s with content:' % latest_dat_path)
640 print('writing %s with content:' % latest_dat_path)
635 latest_dat_content = generate_latest_dat(version)
641 latest_dat_content = generate_latest_dat(version)
636 print(latest_dat_content)
642 print(latest_dat_content)
637
643
638 with sftp.open(latest_dat_path, 'wb') as fh:
644 with sftp.open(latest_dat_path, 'wb') as fh:
639 fh.write(latest_dat_content.encode('ascii'))
645 fh.write(latest_dat_content.encode('ascii'))
640
646
641
647
642 def publish_artifacts(
648 def publish_artifacts(
643 dist_path: pathlib.Path,
649 dist_path: pathlib.Path,
644 version: str,
650 version: str,
645 pypi=True,
651 pypi=True,
646 mercurial_scm_org=True,
652 mercurial_scm_org=True,
647 ssh_username=None,
653 ssh_username=None,
648 ):
654 ):
649 """Publish Windows release artifacts.
655 """Publish Windows release artifacts.
650
656
651 Files are found in `dist_path`. We will look for files with version string
657 Files are found in `dist_path`. We will look for files with version string
652 `version`.
658 `version`.
653
659
654 `pypi` controls whether we upload to PyPI.
660 `pypi` controls whether we upload to PyPI.
655 `mercurial_scm_org` controls whether we upload to mercurial-scm.org.
661 `mercurial_scm_org` controls whether we upload to mercurial-scm.org.
656 """
662 """
657 if pypi:
663 if pypi:
658 publish_artifacts_pypi(dist_path, version)
664 publish_artifacts_pypi(dist_path, version)
659
665
660 if mercurial_scm_org:
666 if mercurial_scm_org:
661 publish_artifacts_mercurial_scm_org(
667 publish_artifacts_mercurial_scm_org(
662 dist_path, version, ssh_username=ssh_username
668 dist_path, version, ssh_username=ssh_username
663 )
669 )
@@ -1,211 +1,211 b''
1 # install-dependencies.ps1 - Install Windows dependencies for building Mercurial
1 # install-dependencies.ps1 - Install Windows dependencies for building Mercurial
2 #
2 #
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.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 # This script can be used to bootstrap a Mercurial build environment on
8 # This script can be used to bootstrap a Mercurial build environment on
9 # Windows.
9 # Windows.
10 #
10 #
11 # The script makes a lot of assumptions about how things should work.
11 # The script makes a lot of assumptions about how things should work.
12 # For example, the install location of Python is hardcoded to c:\hgdev\*.
12 # For example, the install location of Python is hardcoded to c:\hgdev\*.
13 #
13 #
14 # The script should be executed from a PowerShell with elevated privileges
14 # The script should be executed from a PowerShell with elevated privileges
15 # if you don't want to see a UAC prompt for various installers.
15 # if you don't want to see a UAC prompt for various installers.
16 #
16 #
17 # The script is tested on Windows 10 and Windows Server 2019 (in EC2).
17 # The script is tested on Windows 10 and Windows Server 2019 (in EC2).
18
18
19 $VS_BUILD_TOOLS_URL = "https://download.visualstudio.microsoft.com/download/pr/a1603c02-8a66-4b83-b821-811e3610a7c4/aa2db8bb39e0cbd23e9940d8951e0bc3/vs_buildtools.exe"
19 $VS_BUILD_TOOLS_URL = "https://download.visualstudio.microsoft.com/download/pr/a1603c02-8a66-4b83-b821-811e3610a7c4/aa2db8bb39e0cbd23e9940d8951e0bc3/vs_buildtools.exe"
20 $VS_BUILD_TOOLS_SHA256 = "911E292B8E6E5F46CBC17003BDCD2D27A70E616E8D5E6E69D5D489A605CAA139"
20 $VS_BUILD_TOOLS_SHA256 = "911E292B8E6E5F46CBC17003BDCD2D27A70E616E8D5E6E69D5D489A605CAA139"
21
21
22 $VC9_PYTHON_URL = "https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi"
22 $VC9_PYTHON_URL = "https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi"
23 $VC9_PYTHON_SHA256 = "070474db76a2e625513a5835df4595df9324d820f9cc97eab2a596dcbc2f5cbf"
23 $VC9_PYTHON_SHA256 = "070474db76a2e625513a5835df4595df9324d820f9cc97eab2a596dcbc2f5cbf"
24
24
25 $PYTHON27_x64_URL = "https://www.python.org/ftp/python/2.7.18/python-2.7.18.amd64.msi"
25 $PYTHON27_x64_URL = "https://www.python.org/ftp/python/2.7.18/python-2.7.18.amd64.msi"
26 $PYTHON27_x64_SHA256 = "b74a3afa1e0bf2a6fc566a7b70d15c9bfabba3756fb077797d16fffa27800c05"
26 $PYTHON27_x64_SHA256 = "b74a3afa1e0bf2a6fc566a7b70d15c9bfabba3756fb077797d16fffa27800c05"
27 $PYTHON27_X86_URL = "https://www.python.org/ftp/python/2.7.18/python-2.7.18.msi"
27 $PYTHON27_X86_URL = "https://www.python.org/ftp/python/2.7.18/python-2.7.18.msi"
28 $PYTHON27_X86_SHA256 = "d901802e90026e9bad76b8a81f8dd7e43c7d7e8269d9281c9e9df7a9c40480a9"
28 $PYTHON27_X86_SHA256 = "d901802e90026e9bad76b8a81f8dd7e43c7d7e8269d9281c9e9df7a9c40480a9"
29
29
30 $PYTHON37_x86_URL = "https://www.python.org/ftp/python/3.7.9/python-3.7.9.exe"
30 $PYTHON37_x86_URL = "https://www.python.org/ftp/python/3.7.9/python-3.7.9.exe"
31 $PYTHON37_x86_SHA256 = "769bb7c74ad1df6d7d74071cc16a984ff6182e4016e11b8949b93db487977220"
31 $PYTHON37_x86_SHA256 = "769bb7c74ad1df6d7d74071cc16a984ff6182e4016e11b8949b93db487977220"
32 $PYTHON37_X64_URL = "https://www.python.org/ftp/python/3.7.9/python-3.7.9-amd64.exe"
32 $PYTHON37_X64_URL = "https://www.python.org/ftp/python/3.7.9/python-3.7.9-amd64.exe"
33 $PYTHON37_x64_SHA256 = "e69ed52afb5a722e5c56f6c21d594e85c17cb29f12f18bb69751cf1714e0f987"
33 $PYTHON37_x64_SHA256 = "e69ed52afb5a722e5c56f6c21d594e85c17cb29f12f18bb69751cf1714e0f987"
34
34
35 $PYTHON38_x86_URL = "https://www.python.org/ftp/python/3.8.6/python-3.8.6.exe"
35 $PYTHON38_x86_URL = "https://www.python.org/ftp/python/3.8.6/python-3.8.6.exe"
36 $PYTHON38_x86_SHA256 = "287d5df01ff22ff09e6a487ae018603ee19eade71d462ec703850c96f1d5e8a0"
36 $PYTHON38_x86_SHA256 = "287d5df01ff22ff09e6a487ae018603ee19eade71d462ec703850c96f1d5e8a0"
37 $PYTHON38_x64_URL = "https://www.python.org/ftp/python/3.8.6/python-3.8.6-amd64.exe"
37 $PYTHON38_x64_URL = "https://www.python.org/ftp/python/3.8.6/python-3.8.6-amd64.exe"
38 $PYTHON38_x64_SHA256 = "328a257f189cb500606bb26ab0fbdd298ed0e05d8c36540a322a1744f489a0a0"
38 $PYTHON38_x64_SHA256 = "328a257f189cb500606bb26ab0fbdd298ed0e05d8c36540a322a1744f489a0a0"
39
39
40 $PYTHON39_x86_URL = "https://www.python.org/ftp/python/3.9.0/python-3.9.0.exe"
40 $PYTHON39_x86_URL = "https://www.python.org/ftp/python/3.9.0/python-3.9.0.exe"
41 $PYTHON39_x86_SHA256 = "a4c65917f4225d1543959342f0615c813a4e9e7ff1137c4394ff6a5290ac1913"
41 $PYTHON39_x86_SHA256 = "a4c65917f4225d1543959342f0615c813a4e9e7ff1137c4394ff6a5290ac1913"
42 $PYTHON39_x64_URL = "https://www.python.org/ftp/python/3.9.0/python-3.9.0-amd64.exe"
42 $PYTHON39_x64_URL = "https://www.python.org/ftp/python/3.9.0/python-3.9.0-amd64.exe"
43 $PYTHON39_x64_SHA256 = "fd2e2c6612d43bb6b213b72fc53f07d73d99059fa72c96e44bde12e7815073ae"
43 $PYTHON39_x64_SHA256 = "fd2e2c6612d43bb6b213b72fc53f07d73d99059fa72c96e44bde12e7815073ae"
44
44
45 # PIP 19.2.3.
45 # PIP 19.2.3.
46 $PIP_URL = "https://github.com/pypa/get-pip/raw/309a56c5fd94bd1134053a541cb4657a4e47e09d/get-pip.py"
46 $PIP_URL = "https://github.com/pypa/get-pip/raw/309a56c5fd94bd1134053a541cb4657a4e47e09d/get-pip.py"
47 $PIP_SHA256 = "57e3643ff19f018f8a00dfaa6b7e4620e3c1a7a2171fd218425366ec006b3bfe"
47 $PIP_SHA256 = "57e3643ff19f018f8a00dfaa6b7e4620e3c1a7a2171fd218425366ec006b3bfe"
48
48
49 $VIRTUALENV_URL = "https://files.pythonhosted.org/packages/66/f0/6867af06d2e2f511e4e1d7094ff663acdebc4f15d4a0cb0fed1007395124/virtualenv-16.7.5.tar.gz"
49 $VIRTUALENV_URL = "https://files.pythonhosted.org/packages/66/f0/6867af06d2e2f511e4e1d7094ff663acdebc4f15d4a0cb0fed1007395124/virtualenv-16.7.5.tar.gz"
50 $VIRTUALENV_SHA256 = "f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2"
50 $VIRTUALENV_SHA256 = "f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2"
51
51
52 $INNO_SETUP_URL = "http://files.jrsoftware.org/is/5/innosetup-5.6.1-unicode.exe"
52 $INNO_SETUP_URL = "http://files.jrsoftware.org/is/5/innosetup-5.6.1-unicode.exe"
53 $INNO_SETUP_SHA256 = "27D49E9BC769E9D1B214C153011978DB90DC01C2ACD1DDCD9ED7B3FE3B96B538"
53 $INNO_SETUP_SHA256 = "27D49E9BC769E9D1B214C153011978DB90DC01C2ACD1DDCD9ED7B3FE3B96B538"
54
54
55 $MINGW_BIN_URL = "https://osdn.net/frs/redir.php?m=constant&f=mingw%2F68260%2Fmingw-get-0.6.3-mingw32-pre-20170905-1-bin.zip"
55 $MINGW_BIN_URL = "https://osdn.net/frs/redir.php?m=constant&f=mingw%2F68260%2Fmingw-get-0.6.3-mingw32-pre-20170905-1-bin.zip"
56 $MINGW_BIN_SHA256 = "2AB8EFD7C7D1FC8EAF8B2FA4DA4EEF8F3E47768284C021599BC7435839A046DF"
56 $MINGW_BIN_SHA256 = "2AB8EFD7C7D1FC8EAF8B2FA4DA4EEF8F3E47768284C021599BC7435839A046DF"
57
57
58 $MERCURIAL_WHEEL_FILENAME = "mercurial-5.1.2-cp27-cp27m-win_amd64.whl"
58 $MERCURIAL_WHEEL_FILENAME = "mercurial-5.1.2-cp27-cp27m-win_amd64.whl"
59 $MERCURIAL_WHEEL_URL = "https://files.pythonhosted.org/packages/6d/47/e031e47f7fe9b16e4e3383da47e2b0a7eae6e603996bc67a03ec4fa1b3f4/$MERCURIAL_WHEEL_FILENAME"
59 $MERCURIAL_WHEEL_URL = "https://files.pythonhosted.org/packages/6d/47/e031e47f7fe9b16e4e3383da47e2b0a7eae6e603996bc67a03ec4fa1b3f4/$MERCURIAL_WHEEL_FILENAME"
60 $MERCURIAL_WHEEL_SHA256 = "1d18c7f6ca1456f0f62ee65c9a50c14cbba48ce6e924930cdb10537f5c9eaf5f"
60 $MERCURIAL_WHEEL_SHA256 = "1d18c7f6ca1456f0f62ee65c9a50c14cbba48ce6e924930cdb10537f5c9eaf5f"
61
61
62 $RUSTUP_INIT_URL = "https://static.rust-lang.org/rustup/archive/1.21.1/x86_64-pc-windows-gnu/rustup-init.exe"
62 $RUSTUP_INIT_URL = "https://static.rust-lang.org/rustup/archive/1.21.1/x86_64-pc-windows-gnu/rustup-init.exe"
63 $RUSTUP_INIT_SHA256 = "d17df34ba974b9b19cf5c75883a95475aa22ddc364591d75d174090d55711c72"
63 $RUSTUP_INIT_SHA256 = "d17df34ba974b9b19cf5c75883a95475aa22ddc364591d75d174090d55711c72"
64
64
65 # Writing progress slows down downloads substantially. So disable it.
65 # Writing progress slows down downloads substantially. So disable it.
66 $progressPreference = 'silentlyContinue'
66 $progressPreference = 'silentlyContinue'
67
67
68 function Secure-Download($url, $path, $sha256) {
68 function Secure-Download($url, $path, $sha256) {
69 if (Test-Path -Path $path) {
69 if (Test-Path -Path $path) {
70 Get-FileHash -Path $path -Algorithm SHA256 -OutVariable hash
70 Get-FileHash -Path $path -Algorithm SHA256 -OutVariable hash
71
71
72 if ($hash.Hash -eq $sha256) {
72 if ($hash.Hash -eq $sha256) {
73 Write-Output "SHA256 of $path verified as $sha256"
73 Write-Output "SHA256 of $path verified as $sha256"
74 return
74 return
75 }
75 }
76
76
77 Write-Output "hash mismatch on $path; downloading again"
77 Write-Output "hash mismatch on $path; downloading again"
78 }
78 }
79
79
80 Write-Output "downloading $url to $path"
80 Write-Output "downloading $url to $path"
81 Invoke-WebRequest -Uri $url -OutFile $path
81 Invoke-WebRequest -Uri $url -OutFile $path
82 Get-FileHash -Path $path -Algorithm SHA256 -OutVariable hash
82 Get-FileHash -Path $path -Algorithm SHA256 -OutVariable hash
83
83
84 if ($hash.Hash -ne $sha256) {
84 if ($hash.Hash -ne $sha256) {
85 Remove-Item -Path $path
85 Remove-Item -Path $path
86 throw "hash mismatch when downloading $url; got $($hash.Hash), expected $sha256"
86 throw "hash mismatch when downloading $url; got $($hash.Hash), expected $sha256"
87 }
87 }
88 }
88 }
89
89
90 function Invoke-Process($path, $arguments) {
90 function Invoke-Process($path, $arguments) {
91 $p = Start-Process -FilePath $path -ArgumentList $arguments -Wait -PassThru -WindowStyle Hidden
91 $p = Start-Process -FilePath $path -ArgumentList $arguments -Wait -PassThru -WindowStyle Hidden
92
92
93 if ($p.ExitCode -ne 0) {
93 if ($p.ExitCode -ne 0) {
94 throw "process exited non-0: $($p.ExitCode)"
94 throw "process exited non-0: $($p.ExitCode)"
95 }
95 }
96 }
96 }
97
97
98 function Install-Python3($name, $installer, $dest, $pip) {
98 function Install-Python3($name, $installer, $dest, $pip) {
99 Write-Output "installing $name"
99 Write-Output "installing $name"
100
100
101 # We hit this when running the script as part of Simple Systems Manager in
101 # We hit this when running the script as part of Simple Systems Manager in
102 # EC2. The Python 3 installer doesn't seem to like per-user installs
102 # EC2. The Python 3 installer doesn't seem to like per-user installs
103 # when running as the SYSTEM user. So enable global installs if executed in
103 # when running as the SYSTEM user. So enable global installs if executed in
104 # this mode.
104 # this mode.
105 if ($env:USERPROFILE -eq "C:\Windows\system32\config\systemprofile") {
105 if ($env:USERPROFILE -eq "C:\Windows\system32\config\systemprofile") {
106 Write-Output "running with SYSTEM account; installing for all users"
106 Write-Output "running with SYSTEM account; installing for all users"
107 $allusers = "1"
107 $allusers = "1"
108 }
108 }
109 else {
109 else {
110 $allusers = "0"
110 $allusers = "0"
111 }
111 }
112
112
113 Invoke-Process $installer "/quiet TargetDir=${dest} InstallAllUsers=${allusers} AssociateFiles=0 CompileAll=0 PrependPath=0 Include_doc=0 Include_launcher=0 InstallLauncherAllUsers=0 Include_pip=0 Include_test=0"
113 Invoke-Process $installer "/quiet TargetDir=${dest} InstallAllUsers=${allusers} AssociateFiles=0 CompileAll=0 PrependPath=0 Include_doc=0 Include_launcher=0 InstallLauncherAllUsers=0 Include_pip=0 Include_test=0"
114 Invoke-Process ${dest}\python.exe $pip
114 Invoke-Process ${dest}\python.exe $pip
115 }
115 }
116
116
117 function Install-Rust($prefix) {
117 function Install-Rust($prefix) {
118 Write-Output "installing Rust"
118 Write-Output "installing Rust"
119 $Env:RUSTUP_HOME = "${prefix}\rustup"
119 $Env:RUSTUP_HOME = "${prefix}\rustup"
120 $Env:CARGO_HOME = "${prefix}\cargo"
120 $Env:CARGO_HOME = "${prefix}\cargo"
121
121
122 Invoke-Process "${prefix}\assets\rustup-init.exe" "-y --default-host x86_64-pc-windows-msvc"
122 Invoke-Process "${prefix}\assets\rustup-init.exe" "-y --default-host x86_64-pc-windows-msvc"
123 Invoke-Process "${prefix}\cargo\bin\rustup.exe" "target add i686-pc-windows-msvc"
123 Invoke-Process "${prefix}\cargo\bin\rustup.exe" "target add i686-pc-windows-msvc"
124 Invoke-Process "${prefix}\cargo\bin\rustup.exe" "install 1.46.0"
124 Invoke-Process "${prefix}\cargo\bin\rustup.exe" "install 1.46.0"
125 Invoke-Process "${prefix}\cargo\bin\rustup.exe" "component add clippy"
125 Invoke-Process "${prefix}\cargo\bin\rustup.exe" "component add clippy"
126
126
127 # Install PyOxidizer for packaging.
127 # Install PyOxidizer for packaging.
128 Invoke-Process "${prefix}\cargo\bin\cargo.exe" "install --git https://github.com/indygreg/PyOxidizer.git --rev 4697fb25918dfad6dc73288daeea501063963a08 pyoxidizer"
128 Invoke-Process "${prefix}\cargo\bin\cargo.exe" "install --version 0.9.0 pyoxidizer"
129 }
129 }
130
130
131 function Install-Dependencies($prefix) {
131 function Install-Dependencies($prefix) {
132 if (!(Test-Path -Path $prefix\assets)) {
132 if (!(Test-Path -Path $prefix\assets)) {
133 New-Item -Path $prefix\assets -ItemType Directory
133 New-Item -Path $prefix\assets -ItemType Directory
134 }
134 }
135
135
136 $pip = "${prefix}\assets\get-pip.py"
136 $pip = "${prefix}\assets\get-pip.py"
137
137
138 Secure-Download $VC9_PYTHON_URL ${prefix}\assets\VCForPython27.msi $VC9_PYTHON_SHA256
138 Secure-Download $VC9_PYTHON_URL ${prefix}\assets\VCForPython27.msi $VC9_PYTHON_SHA256
139 Secure-Download $PYTHON27_x86_URL ${prefix}\assets\python27-x86.msi $PYTHON27_x86_SHA256
139 Secure-Download $PYTHON27_x86_URL ${prefix}\assets\python27-x86.msi $PYTHON27_x86_SHA256
140 Secure-Download $PYTHON27_x64_URL ${prefix}\assets\python27-x64.msi $PYTHON27_x64_SHA256
140 Secure-Download $PYTHON27_x64_URL ${prefix}\assets\python27-x64.msi $PYTHON27_x64_SHA256
141 Secure-Download $PYTHON37_x86_URL ${prefix}\assets\python37-x86.exe $PYTHON37_x86_SHA256
141 Secure-Download $PYTHON37_x86_URL ${prefix}\assets\python37-x86.exe $PYTHON37_x86_SHA256
142 Secure-Download $PYTHON37_x64_URL ${prefix}\assets\python37-x64.exe $PYTHON37_x64_SHA256
142 Secure-Download $PYTHON37_x64_URL ${prefix}\assets\python37-x64.exe $PYTHON37_x64_SHA256
143 Secure-Download $PYTHON38_x86_URL ${prefix}\assets\python38-x86.exe $PYTHON38_x86_SHA256
143 Secure-Download $PYTHON38_x86_URL ${prefix}\assets\python38-x86.exe $PYTHON38_x86_SHA256
144 Secure-Download $PYTHON38_x64_URL ${prefix}\assets\python38-x64.exe $PYTHON38_x64_SHA256
144 Secure-Download $PYTHON38_x64_URL ${prefix}\assets\python38-x64.exe $PYTHON38_x64_SHA256
145 Secure-Download $PYTHON39_x86_URL ${prefix}\assets\python39-x86.exe $PYTHON39_x86_SHA256
145 Secure-Download $PYTHON39_x86_URL ${prefix}\assets\python39-x86.exe $PYTHON39_x86_SHA256
146 Secure-Download $PYTHON39_x64_URL ${prefix}\assets\python39-x64.exe $PYTHON39_x64_SHA256
146 Secure-Download $PYTHON39_x64_URL ${prefix}\assets\python39-x64.exe $PYTHON39_x64_SHA256
147 Secure-Download $PIP_URL ${pip} $PIP_SHA256
147 Secure-Download $PIP_URL ${pip} $PIP_SHA256
148 Secure-Download $VIRTUALENV_URL ${prefix}\assets\virtualenv.tar.gz $VIRTUALENV_SHA256
148 Secure-Download $VIRTUALENV_URL ${prefix}\assets\virtualenv.tar.gz $VIRTUALENV_SHA256
149 Secure-Download $VS_BUILD_TOOLS_URL ${prefix}\assets\vs_buildtools.exe $VS_BUILD_TOOLS_SHA256
149 Secure-Download $VS_BUILD_TOOLS_URL ${prefix}\assets\vs_buildtools.exe $VS_BUILD_TOOLS_SHA256
150 Secure-Download $INNO_SETUP_URL ${prefix}\assets\InnoSetup.exe $INNO_SETUP_SHA256
150 Secure-Download $INNO_SETUP_URL ${prefix}\assets\InnoSetup.exe $INNO_SETUP_SHA256
151 Secure-Download $MINGW_BIN_URL ${prefix}\assets\mingw-get-bin.zip $MINGW_BIN_SHA256
151 Secure-Download $MINGW_BIN_URL ${prefix}\assets\mingw-get-bin.zip $MINGW_BIN_SHA256
152 Secure-Download $MERCURIAL_WHEEL_URL ${prefix}\assets\${MERCURIAL_WHEEL_FILENAME} $MERCURIAL_WHEEL_SHA256
152 Secure-Download $MERCURIAL_WHEEL_URL ${prefix}\assets\${MERCURIAL_WHEEL_FILENAME} $MERCURIAL_WHEEL_SHA256
153 Secure-Download $RUSTUP_INIT_URL ${prefix}\assets\rustup-init.exe $RUSTUP_INIT_SHA256
153 Secure-Download $RUSTUP_INIT_URL ${prefix}\assets\rustup-init.exe $RUSTUP_INIT_SHA256
154
154
155 Write-Output "installing Python 2.7 32-bit"
155 Write-Output "installing Python 2.7 32-bit"
156 Invoke-Process msiexec.exe "/i ${prefix}\assets\python27-x86.msi /l* ${prefix}\assets\python27-x86.log /q TARGETDIR=${prefix}\python27-x86 ALLUSERS="
156 Invoke-Process msiexec.exe "/i ${prefix}\assets\python27-x86.msi /l* ${prefix}\assets\python27-x86.log /q TARGETDIR=${prefix}\python27-x86 ALLUSERS="
157 Invoke-Process ${prefix}\python27-x86\python.exe ${prefix}\assets\get-pip.py
157 Invoke-Process ${prefix}\python27-x86\python.exe ${prefix}\assets\get-pip.py
158 Invoke-Process ${prefix}\python27-x86\Scripts\pip.exe "install ${prefix}\assets\virtualenv.tar.gz"
158 Invoke-Process ${prefix}\python27-x86\Scripts\pip.exe "install ${prefix}\assets\virtualenv.tar.gz"
159
159
160 Write-Output "installing Python 2.7 64-bit"
160 Write-Output "installing Python 2.7 64-bit"
161 Invoke-Process msiexec.exe "/i ${prefix}\assets\python27-x64.msi /l* ${prefix}\assets\python27-x64.log /q TARGETDIR=${prefix}\python27-x64 ALLUSERS="
161 Invoke-Process msiexec.exe "/i ${prefix}\assets\python27-x64.msi /l* ${prefix}\assets\python27-x64.log /q TARGETDIR=${prefix}\python27-x64 ALLUSERS="
162 Invoke-Process ${prefix}\python27-x64\python.exe ${prefix}\assets\get-pip.py
162 Invoke-Process ${prefix}\python27-x64\python.exe ${prefix}\assets\get-pip.py
163 Invoke-Process ${prefix}\python27-x64\Scripts\pip.exe "install ${prefix}\assets\virtualenv.tar.gz"
163 Invoke-Process ${prefix}\python27-x64\Scripts\pip.exe "install ${prefix}\assets\virtualenv.tar.gz"
164
164
165 Install-Python3 "Python 3.7 32-bit" ${prefix}\assets\python37-x86.exe ${prefix}\python37-x86 ${pip}
165 Install-Python3 "Python 3.7 32-bit" ${prefix}\assets\python37-x86.exe ${prefix}\python37-x86 ${pip}
166 Install-Python3 "Python 3.7 64-bit" ${prefix}\assets\python37-x64.exe ${prefix}\python37-x64 ${pip}
166 Install-Python3 "Python 3.7 64-bit" ${prefix}\assets\python37-x64.exe ${prefix}\python37-x64 ${pip}
167 Install-Python3 "Python 3.8 32-bit" ${prefix}\assets\python38-x86.exe ${prefix}\python38-x86 ${pip}
167 Install-Python3 "Python 3.8 32-bit" ${prefix}\assets\python38-x86.exe ${prefix}\python38-x86 ${pip}
168 Install-Python3 "Python 3.8 64-bit" ${prefix}\assets\python38-x64.exe ${prefix}\python38-x64 ${pip}
168 Install-Python3 "Python 3.8 64-bit" ${prefix}\assets\python38-x64.exe ${prefix}\python38-x64 ${pip}
169 Install-Python3 "Python 3.9 32-bit" ${prefix}\assets\python39-x86.exe ${prefix}\python39-x86 ${pip}
169 Install-Python3 "Python 3.9 32-bit" ${prefix}\assets\python39-x86.exe ${prefix}\python39-x86 ${pip}
170 Install-Python3 "Python 3.9 64-bit" ${prefix}\assets\python39-x64.exe ${prefix}\python39-x64 ${pip}
170 Install-Python3 "Python 3.9 64-bit" ${prefix}\assets\python39-x64.exe ${prefix}\python39-x64 ${pip}
171
171
172 Write-Output "installing Visual Studio 2017 Build Tools and SDKs"
172 Write-Output "installing Visual Studio 2017 Build Tools and SDKs"
173 Invoke-Process ${prefix}\assets\vs_buildtools.exe "--quiet --wait --norestart --nocache --channelUri https://aka.ms/vs/15/release/channel --add Microsoft.VisualStudio.Workload.MSBuildTools --add Microsoft.VisualStudio.Component.Windows10SDK.17763 --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.Windows10SDK --add Microsoft.VisualStudio.Component.VC.140"
173 Invoke-Process ${prefix}\assets\vs_buildtools.exe "--quiet --wait --norestart --nocache --channelUri https://aka.ms/vs/15/release/channel --add Microsoft.VisualStudio.Workload.MSBuildTools --add Microsoft.VisualStudio.Component.Windows10SDK.17763 --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.Windows10SDK --add Microsoft.VisualStudio.Component.VC.140"
174
174
175 Install-Rust ${prefix}
175 Install-Rust ${prefix}
176
176
177 Write-Output "installing Visual C++ 9.0 for Python 2.7"
177 Write-Output "installing Visual C++ 9.0 for Python 2.7"
178 Invoke-Process msiexec.exe "/i ${prefix}\assets\VCForPython27.msi /l* ${prefix}\assets\VCForPython27.log /q"
178 Invoke-Process msiexec.exe "/i ${prefix}\assets\VCForPython27.msi /l* ${prefix}\assets\VCForPython27.log /q"
179
179
180 Write-Output "installing Inno Setup"
180 Write-Output "installing Inno Setup"
181 Invoke-Process ${prefix}\assets\InnoSetup.exe "/SP- /VERYSILENT /SUPPRESSMSGBOXES"
181 Invoke-Process ${prefix}\assets\InnoSetup.exe "/SP- /VERYSILENT /SUPPRESSMSGBOXES"
182
182
183 Write-Output "extracting MinGW base archive"
183 Write-Output "extracting MinGW base archive"
184 Expand-Archive -Path ${prefix}\assets\mingw-get-bin.zip -DestinationPath "${prefix}\MinGW" -Force
184 Expand-Archive -Path ${prefix}\assets\mingw-get-bin.zip -DestinationPath "${prefix}\MinGW" -Force
185
185
186 Write-Output "updating MinGW package catalogs"
186 Write-Output "updating MinGW package catalogs"
187 Invoke-Process ${prefix}\MinGW\bin\mingw-get.exe "update"
187 Invoke-Process ${prefix}\MinGW\bin\mingw-get.exe "update"
188
188
189 Write-Output "installing MinGW packages"
189 Write-Output "installing MinGW packages"
190 Invoke-Process ${prefix}\MinGW\bin\mingw-get.exe "install msys-base msys-coreutils msys-diffutils msys-unzip"
190 Invoke-Process ${prefix}\MinGW\bin\mingw-get.exe "install msys-base msys-coreutils msys-diffutils msys-unzip"
191
191
192 # Construct a virtualenv useful for bootstrapping. It conveniently contains a
192 # Construct a virtualenv useful for bootstrapping. It conveniently contains a
193 # Mercurial install.
193 # Mercurial install.
194 Write-Output "creating bootstrap virtualenv with Mercurial"
194 Write-Output "creating bootstrap virtualenv with Mercurial"
195 Invoke-Process "$prefix\python27-x64\Scripts\virtualenv.exe" "${prefix}\venv-bootstrap"
195 Invoke-Process "$prefix\python27-x64\Scripts\virtualenv.exe" "${prefix}\venv-bootstrap"
196 Invoke-Process "${prefix}\venv-bootstrap\Scripts\pip.exe" "install ${prefix}\assets\${MERCURIAL_WHEEL_FILENAME}"
196 Invoke-Process "${prefix}\venv-bootstrap\Scripts\pip.exe" "install ${prefix}\assets\${MERCURIAL_WHEEL_FILENAME}"
197 }
197 }
198
198
199 function Clone-Mercurial-Repo($prefix, $repo_url, $dest) {
199 function Clone-Mercurial-Repo($prefix, $repo_url, $dest) {
200 Write-Output "cloning $repo_url to $dest"
200 Write-Output "cloning $repo_url to $dest"
201 # TODO Figure out why CA verification isn't working in EC2 and remove
201 # TODO Figure out why CA verification isn't working in EC2 and remove
202 # --insecure.
202 # --insecure.
203 Invoke-Process "${prefix}\venv-bootstrap\Scripts\hg.exe" "clone --insecure $repo_url $dest"
203 Invoke-Process "${prefix}\venv-bootstrap\Scripts\hg.exe" "clone --insecure $repo_url $dest"
204
204
205 # Mark repo as non-publishing by default for convenience.
205 # Mark repo as non-publishing by default for convenience.
206 Add-Content -Path "$dest\.hg\hgrc" -Value "`n[phases]`npublish = false"
206 Add-Content -Path "$dest\.hg\hgrc" -Value "`n[phases]`npublish = false"
207 }
207 }
208
208
209 $prefix = "c:\hgdev"
209 $prefix = "c:\hgdev"
210 Install-Dependencies $prefix
210 Install-Dependencies $prefix
211 Clone-Mercurial-Repo $prefix "https://www.mercurial-scm.org/repo/hg" $prefix\src
211 Clone-Mercurial-Repo $prefix "https://www.mercurial-scm.org/repo/hg" $prefix\src
@@ -1,232 +1,232 b''
1 # inno.py - Inno Setup functionality.
1 # inno.py - Inno Setup functionality.
2 #
2 #
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.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 # no-check-code because Python 3 native.
8 # no-check-code because Python 3 native.
9
9
10 import os
10 import os
11 import pathlib
11 import pathlib
12 import shutil
12 import shutil
13 import subprocess
13 import subprocess
14
14
15 import jinja2
15 import jinja2
16
16
17 from .py2exe import (
17 from .py2exe import (
18 build_py2exe,
18 build_py2exe,
19 stage_install,
19 stage_install,
20 )
20 )
21 from .pyoxidizer import run_pyoxidizer
21 from .pyoxidizer import run_pyoxidizer
22 from .util import (
22 from .util import (
23 find_legacy_vc_runtime_files,
23 find_legacy_vc_runtime_files,
24 normalize_windows_version,
24 normalize_windows_version,
25 process_install_rules,
25 process_install_rules,
26 read_version_py,
26 read_version_py,
27 )
27 )
28
28
29 EXTRA_PACKAGES = {
29 EXTRA_PACKAGES = {
30 'dulwich',
30 'dulwich',
31 'keyring',
31 'keyring',
32 'pygments',
32 'pygments',
33 'win32ctypes',
33 'win32ctypes',
34 }
34 }
35
35
36 EXTRA_INSTALL_RULES = [
36 EXTRA_INSTALL_RULES = [
37 ('contrib/win32/mercurial.ini', 'defaultrc/mercurial.rc'),
37 ('contrib/win32/mercurial.ini', 'defaultrc/mercurial.rc'),
38 ]
38 ]
39
39
40 PACKAGE_FILES_METADATA = {
40 PACKAGE_FILES_METADATA = {
41 'ReadMe.html': 'Flags: isreadme',
41 'ReadMe.html': 'Flags: isreadme',
42 }
42 }
43
43
44
44
45 def build_with_py2exe(
45 def build_with_py2exe(
46 source_dir: pathlib.Path,
46 source_dir: pathlib.Path,
47 build_dir: pathlib.Path,
47 build_dir: pathlib.Path,
48 python_exe: pathlib.Path,
48 python_exe: pathlib.Path,
49 iscc_exe: pathlib.Path,
49 iscc_exe: pathlib.Path,
50 version=None,
50 version=None,
51 ):
51 ):
52 """Build the Inno installer using py2exe.
52 """Build the Inno installer using py2exe.
53
53
54 Build files will be placed in ``build_dir``.
54 Build files will be placed in ``build_dir``.
55
55
56 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
56 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
57 for finding the Python 2.7 toolchain. So, we require the environment
57 for finding the Python 2.7 toolchain. So, we require the environment
58 to already be configured with an active toolchain.
58 to already be configured with an active toolchain.
59 """
59 """
60 if not iscc_exe.exists():
60 if not iscc_exe.exists():
61 raise Exception('%s does not exist' % iscc_exe)
61 raise Exception('%s does not exist' % iscc_exe)
62
62
63 vc_x64 = r'\x64' in os.environ.get('LIB', '')
63 vc_x64 = r'\x64' in os.environ.get('LIB', '')
64 arch = 'x64' if vc_x64 else 'x86'
64 arch = 'x64' if vc_x64 else 'x86'
65 inno_build_dir = build_dir / ('inno-py2exe-%s' % arch)
65 inno_build_dir = build_dir / ('inno-py2exe-%s' % arch)
66 staging_dir = inno_build_dir / 'stage'
66 staging_dir = inno_build_dir / 'stage'
67
67
68 requirements_txt = (
68 requirements_txt = (
69 source_dir / 'contrib' / 'packaging' / 'requirements_win32.txt'
69 source_dir / 'contrib' / 'packaging' / 'requirements-windows-py2.txt'
70 )
70 )
71
71
72 inno_build_dir.mkdir(parents=True, exist_ok=True)
72 inno_build_dir.mkdir(parents=True, exist_ok=True)
73
73
74 build_py2exe(
74 build_py2exe(
75 source_dir,
75 source_dir,
76 build_dir,
76 build_dir,
77 python_exe,
77 python_exe,
78 'inno',
78 'inno',
79 requirements_txt,
79 requirements_txt,
80 extra_packages=EXTRA_PACKAGES,
80 extra_packages=EXTRA_PACKAGES,
81 )
81 )
82
82
83 # Purge the staging directory for every build so packaging is
83 # Purge the staging directory for every build so packaging is
84 # pristine.
84 # pristine.
85 if staging_dir.exists():
85 if staging_dir.exists():
86 print('purging %s' % staging_dir)
86 print('purging %s' % staging_dir)
87 shutil.rmtree(staging_dir)
87 shutil.rmtree(staging_dir)
88
88
89 # Now assemble all the packaged files into the staging directory.
89 # Now assemble all the packaged files into the staging directory.
90 stage_install(source_dir, staging_dir)
90 stage_install(source_dir, staging_dir)
91
91
92 # We also install some extra files.
92 # We also install some extra files.
93 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
93 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
94
94
95 # hg.exe depends on VC9 runtime DLLs. Copy those into place.
95 # hg.exe depends on VC9 runtime DLLs. Copy those into place.
96 for f in find_legacy_vc_runtime_files(vc_x64):
96 for f in find_legacy_vc_runtime_files(vc_x64):
97 if f.name.endswith('.manifest'):
97 if f.name.endswith('.manifest'):
98 basename = 'Microsoft.VC90.CRT.manifest'
98 basename = 'Microsoft.VC90.CRT.manifest'
99 else:
99 else:
100 basename = f.name
100 basename = f.name
101
101
102 dest_path = staging_dir / basename
102 dest_path = staging_dir / basename
103
103
104 print('copying %s to %s' % (f, dest_path))
104 print('copying %s to %s' % (f, dest_path))
105 shutil.copyfile(f, dest_path)
105 shutil.copyfile(f, dest_path)
106
106
107 build_installer(
107 build_installer(
108 source_dir,
108 source_dir,
109 inno_build_dir,
109 inno_build_dir,
110 staging_dir,
110 staging_dir,
111 iscc_exe,
111 iscc_exe,
112 version,
112 version,
113 arch="x64" if vc_x64 else None,
113 arch="x64" if vc_x64 else None,
114 suffix="-python2",
114 suffix="-python2",
115 )
115 )
116
116
117
117
118 def build_with_pyoxidizer(
118 def build_with_pyoxidizer(
119 source_dir: pathlib.Path,
119 source_dir: pathlib.Path,
120 build_dir: pathlib.Path,
120 build_dir: pathlib.Path,
121 target_triple: str,
121 target_triple: str,
122 iscc_exe: pathlib.Path,
122 iscc_exe: pathlib.Path,
123 version=None,
123 version=None,
124 ):
124 ):
125 """Build the Inno installer using PyOxidizer."""
125 """Build the Inno installer using PyOxidizer."""
126 if not iscc_exe.exists():
126 if not iscc_exe.exists():
127 raise Exception("%s does not exist" % iscc_exe)
127 raise Exception("%s does not exist" % iscc_exe)
128
128
129 inno_build_dir = build_dir / ("inno-pyoxidizer-%s" % target_triple)
129 inno_build_dir = build_dir / ("inno-pyoxidizer-%s" % target_triple)
130 staging_dir = inno_build_dir / "stage"
130 staging_dir = inno_build_dir / "stage"
131
131
132 inno_build_dir.mkdir(parents=True, exist_ok=True)
132 inno_build_dir.mkdir(parents=True, exist_ok=True)
133 run_pyoxidizer(source_dir, inno_build_dir, staging_dir, target_triple)
133 run_pyoxidizer(source_dir, inno_build_dir, staging_dir, target_triple)
134
134
135 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
135 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
136
136
137 build_installer(
137 build_installer(
138 source_dir,
138 source_dir,
139 inno_build_dir,
139 inno_build_dir,
140 staging_dir,
140 staging_dir,
141 iscc_exe,
141 iscc_exe,
142 version,
142 version,
143 arch="x64" if "x86_64" in target_triple else None,
143 arch="x64" if "x86_64" in target_triple else None,
144 )
144 )
145
145
146
146
147 def build_installer(
147 def build_installer(
148 source_dir: pathlib.Path,
148 source_dir: pathlib.Path,
149 inno_build_dir: pathlib.Path,
149 inno_build_dir: pathlib.Path,
150 staging_dir: pathlib.Path,
150 staging_dir: pathlib.Path,
151 iscc_exe: pathlib.Path,
151 iscc_exe: pathlib.Path,
152 version,
152 version,
153 arch=None,
153 arch=None,
154 suffix="",
154 suffix="",
155 ):
155 ):
156 """Build an Inno installer from staged Mercurial files.
156 """Build an Inno installer from staged Mercurial files.
157
157
158 This function is agnostic about how to build Mercurial. It just
158 This function is agnostic about how to build Mercurial. It just
159 cares that Mercurial files are in ``staging_dir``.
159 cares that Mercurial files are in ``staging_dir``.
160 """
160 """
161 inno_source_dir = source_dir / "contrib" / "packaging" / "inno"
161 inno_source_dir = source_dir / "contrib" / "packaging" / "inno"
162
162
163 # The final package layout is simply a mirror of the staging directory.
163 # The final package layout is simply a mirror of the staging directory.
164 package_files = []
164 package_files = []
165 for root, dirs, files in os.walk(staging_dir):
165 for root, dirs, files in os.walk(staging_dir):
166 dirs.sort()
166 dirs.sort()
167
167
168 root = pathlib.Path(root)
168 root = pathlib.Path(root)
169
169
170 for f in sorted(files):
170 for f in sorted(files):
171 full = root / f
171 full = root / f
172 rel = full.relative_to(staging_dir)
172 rel = full.relative_to(staging_dir)
173 if str(rel.parent) == '.':
173 if str(rel.parent) == '.':
174 dest_dir = '{app}'
174 dest_dir = '{app}'
175 else:
175 else:
176 dest_dir = '{app}\\%s' % rel.parent
176 dest_dir = '{app}\\%s' % rel.parent
177
177
178 package_files.append(
178 package_files.append(
179 {
179 {
180 'source': rel,
180 'source': rel,
181 'dest_dir': dest_dir,
181 'dest_dir': dest_dir,
182 'metadata': PACKAGE_FILES_METADATA.get(str(rel), None),
182 'metadata': PACKAGE_FILES_METADATA.get(str(rel), None),
183 }
183 }
184 )
184 )
185
185
186 print('creating installer')
186 print('creating installer')
187
187
188 # Install Inno files by rendering a template.
188 # Install Inno files by rendering a template.
189 jinja_env = jinja2.Environment(
189 jinja_env = jinja2.Environment(
190 loader=jinja2.FileSystemLoader(str(inno_source_dir)),
190 loader=jinja2.FileSystemLoader(str(inno_source_dir)),
191 # Need to change these to prevent conflict with Inno Setup.
191 # Need to change these to prevent conflict with Inno Setup.
192 comment_start_string='{##',
192 comment_start_string='{##',
193 comment_end_string='##}',
193 comment_end_string='##}',
194 )
194 )
195
195
196 try:
196 try:
197 template = jinja_env.get_template('mercurial.iss')
197 template = jinja_env.get_template('mercurial.iss')
198 except jinja2.TemplateSyntaxError as e:
198 except jinja2.TemplateSyntaxError as e:
199 raise Exception(
199 raise Exception(
200 'template syntax error at %s:%d: %s'
200 'template syntax error at %s:%d: %s'
201 % (e.name, e.lineno, e.message,)
201 % (e.name, e.lineno, e.message,)
202 )
202 )
203
203
204 content = template.render(package_files=package_files)
204 content = template.render(package_files=package_files)
205
205
206 with (inno_build_dir / 'mercurial.iss').open('w', encoding='utf-8') as fh:
206 with (inno_build_dir / 'mercurial.iss').open('w', encoding='utf-8') as fh:
207 fh.write(content)
207 fh.write(content)
208
208
209 # Copy additional files used by Inno.
209 # Copy additional files used by Inno.
210 for p in ('mercurial.ico', 'postinstall.txt'):
210 for p in ('mercurial.ico', 'postinstall.txt'):
211 shutil.copyfile(
211 shutil.copyfile(
212 source_dir / 'contrib' / 'win32' / p, inno_build_dir / p
212 source_dir / 'contrib' / 'win32' / p, inno_build_dir / p
213 )
213 )
214
214
215 args = [str(iscc_exe)]
215 args = [str(iscc_exe)]
216
216
217 if arch:
217 if arch:
218 args.append('/dARCH=%s' % arch)
218 args.append('/dARCH=%s' % arch)
219 args.append('/dSUFFIX=-%s%s' % (arch, suffix))
219 args.append('/dSUFFIX=-%s%s' % (arch, suffix))
220 else:
220 else:
221 args.append('/dSUFFIX=-x86%s' % suffix)
221 args.append('/dSUFFIX=-x86%s' % suffix)
222
222
223 if not version:
223 if not version:
224 version = read_version_py(source_dir)
224 version = read_version_py(source_dir)
225
225
226 args.append('/dVERSION=%s' % version)
226 args.append('/dVERSION=%s' % version)
227 args.append('/dQUAD_VERSION=%s' % normalize_windows_version(version))
227 args.append('/dQUAD_VERSION=%s' % normalize_windows_version(version))
228
228
229 args.append('/Odist')
229 args.append('/Odist')
230 args.append(str(inno_build_dir / 'mercurial.iss'))
230 args.append(str(inno_build_dir / 'mercurial.iss'))
231
231
232 subprocess.run(args, cwd=str(source_dir), check=True)
232 subprocess.run(args, cwd=str(source_dir), check=True)
@@ -1,539 +1,539 b''
1 # wix.py - WiX installer functionality
1 # wix.py - WiX installer functionality
2 #
2 #
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.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 # no-check-code because Python 3 native.
8 # no-check-code because Python 3 native.
9
9
10 import collections
10 import collections
11 import os
11 import os
12 import pathlib
12 import pathlib
13 import re
13 import re
14 import shutil
14 import shutil
15 import subprocess
15 import subprocess
16 import typing
16 import typing
17 import uuid
17 import uuid
18 import xml.dom.minidom
18 import xml.dom.minidom
19
19
20 from .downloads import download_entry
20 from .downloads import download_entry
21 from .py2exe import (
21 from .py2exe import (
22 build_py2exe,
22 build_py2exe,
23 stage_install,
23 stage_install,
24 )
24 )
25 from .pyoxidizer import run_pyoxidizer
25 from .pyoxidizer import run_pyoxidizer
26 from .util import (
26 from .util import (
27 extract_zip_to_directory,
27 extract_zip_to_directory,
28 normalize_windows_version,
28 normalize_windows_version,
29 process_install_rules,
29 process_install_rules,
30 sign_with_signtool,
30 sign_with_signtool,
31 )
31 )
32
32
33
33
34 EXTRA_PACKAGES = {
34 EXTRA_PACKAGES = {
35 'dulwich',
35 'dulwich',
36 'distutils',
36 'distutils',
37 'keyring',
37 'keyring',
38 'pygments',
38 'pygments',
39 'win32ctypes',
39 'win32ctypes',
40 }
40 }
41
41
42
42
43 EXTRA_INSTALL_RULES = [
43 EXTRA_INSTALL_RULES = [
44 ('contrib/packaging/wix/COPYING.rtf', 'COPYING.rtf'),
44 ('contrib/packaging/wix/COPYING.rtf', 'COPYING.rtf'),
45 ('contrib/win32/mercurial.ini', 'defaultrc/mercurial.rc'),
45 ('contrib/win32/mercurial.ini', 'defaultrc/mercurial.rc'),
46 ]
46 ]
47
47
48 STAGING_REMOVE_FILES = [
48 STAGING_REMOVE_FILES = [
49 # We use the RTF variant.
49 # We use the RTF variant.
50 'copying.txt',
50 'copying.txt',
51 ]
51 ]
52
52
53 SHORTCUTS = {
53 SHORTCUTS = {
54 # hg.1.html'
54 # hg.1.html'
55 'hg.file.5d3e441c_28d9_5542_afd0_cdd4234f12d5': {
55 'hg.file.5d3e441c_28d9_5542_afd0_cdd4234f12d5': {
56 'Name': 'Mercurial Command Reference',
56 'Name': 'Mercurial Command Reference',
57 },
57 },
58 # hgignore.5.html
58 # hgignore.5.html
59 'hg.file.5757d8e0_f207_5e10_a2ec_3ba0a062f431': {
59 'hg.file.5757d8e0_f207_5e10_a2ec_3ba0a062f431': {
60 'Name': 'Mercurial Ignore Files',
60 'Name': 'Mercurial Ignore Files',
61 },
61 },
62 # hgrc.5.html
62 # hgrc.5.html
63 'hg.file.92e605fd_1d1a_5dc6_9fc0_5d2998eb8f5e': {
63 'hg.file.92e605fd_1d1a_5dc6_9fc0_5d2998eb8f5e': {
64 'Name': 'Mercurial Configuration Files',
64 'Name': 'Mercurial Configuration Files',
65 },
65 },
66 }
66 }
67
67
68
68
69 def find_version(source_dir: pathlib.Path):
69 def find_version(source_dir: pathlib.Path):
70 version_py = source_dir / 'mercurial' / '__version__.py'
70 version_py = source_dir / 'mercurial' / '__version__.py'
71
71
72 with version_py.open('r', encoding='utf-8') as fh:
72 with version_py.open('r', encoding='utf-8') as fh:
73 source = fh.read().strip()
73 source = fh.read().strip()
74
74
75 m = re.search('version = b"(.*)"', source)
75 m = re.search('version = b"(.*)"', source)
76 return m.group(1)
76 return m.group(1)
77
77
78
78
79 def ensure_vc90_merge_modules(build_dir):
79 def ensure_vc90_merge_modules(build_dir):
80 x86 = (
80 x86 = (
81 download_entry(
81 download_entry(
82 'vc9-crt-x86-msm',
82 'vc9-crt-x86-msm',
83 build_dir,
83 build_dir,
84 local_name='microsoft.vcxx.crt.x86_msm.msm',
84 local_name='microsoft.vcxx.crt.x86_msm.msm',
85 )[0],
85 )[0],
86 download_entry(
86 download_entry(
87 'vc9-crt-x86-msm-policy',
87 'vc9-crt-x86-msm-policy',
88 build_dir,
88 build_dir,
89 local_name='policy.x.xx.microsoft.vcxx.crt.x86_msm.msm',
89 local_name='policy.x.xx.microsoft.vcxx.crt.x86_msm.msm',
90 )[0],
90 )[0],
91 )
91 )
92
92
93 x64 = (
93 x64 = (
94 download_entry(
94 download_entry(
95 'vc9-crt-x64-msm',
95 'vc9-crt-x64-msm',
96 build_dir,
96 build_dir,
97 local_name='microsoft.vcxx.crt.x64_msm.msm',
97 local_name='microsoft.vcxx.crt.x64_msm.msm',
98 )[0],
98 )[0],
99 download_entry(
99 download_entry(
100 'vc9-crt-x64-msm-policy',
100 'vc9-crt-x64-msm-policy',
101 build_dir,
101 build_dir,
102 local_name='policy.x.xx.microsoft.vcxx.crt.x64_msm.msm',
102 local_name='policy.x.xx.microsoft.vcxx.crt.x64_msm.msm',
103 )[0],
103 )[0],
104 )
104 )
105 return {
105 return {
106 'x86': x86,
106 'x86': x86,
107 'x64': x64,
107 'x64': x64,
108 }
108 }
109
109
110
110
111 def run_candle(wix, cwd, wxs, source_dir, defines=None):
111 def run_candle(wix, cwd, wxs, source_dir, defines=None):
112 args = [
112 args = [
113 str(wix / 'candle.exe'),
113 str(wix / 'candle.exe'),
114 '-nologo',
114 '-nologo',
115 str(wxs),
115 str(wxs),
116 '-dSourceDir=%s' % source_dir,
116 '-dSourceDir=%s' % source_dir,
117 ]
117 ]
118
118
119 if defines:
119 if defines:
120 args.extend('-d%s=%s' % define for define in sorted(defines.items()))
120 args.extend('-d%s=%s' % define for define in sorted(defines.items()))
121
121
122 subprocess.run(args, cwd=str(cwd), check=True)
122 subprocess.run(args, cwd=str(cwd), check=True)
123
123
124
124
125 def make_files_xml(staging_dir: pathlib.Path, is_x64) -> str:
125 def make_files_xml(staging_dir: pathlib.Path, is_x64) -> str:
126 """Create XML string listing every file to be installed."""
126 """Create XML string listing every file to be installed."""
127
127
128 # We derive GUIDs from a deterministic file path identifier.
128 # We derive GUIDs from a deterministic file path identifier.
129 # We shoehorn the name into something that looks like a URL because
129 # We shoehorn the name into something that looks like a URL because
130 # the UUID namespaces are supposed to work that way (even though
130 # the UUID namespaces are supposed to work that way (even though
131 # the input data probably is never validated).
131 # the input data probably is never validated).
132
132
133 doc = xml.dom.minidom.parseString(
133 doc = xml.dom.minidom.parseString(
134 '<?xml version="1.0" encoding="utf-8"?>'
134 '<?xml version="1.0" encoding="utf-8"?>'
135 '<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">'
135 '<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">'
136 '</Wix>'
136 '</Wix>'
137 )
137 )
138
138
139 # Assemble the install layout by directory. This makes it easier to
139 # Assemble the install layout by directory. This makes it easier to
140 # emit XML, since each directory has separate entities.
140 # emit XML, since each directory has separate entities.
141 manifest = collections.defaultdict(dict)
141 manifest = collections.defaultdict(dict)
142
142
143 for root, dirs, files in os.walk(staging_dir):
143 for root, dirs, files in os.walk(staging_dir):
144 dirs.sort()
144 dirs.sort()
145
145
146 root = pathlib.Path(root)
146 root = pathlib.Path(root)
147 rel_dir = root.relative_to(staging_dir)
147 rel_dir = root.relative_to(staging_dir)
148
148
149 for i in range(len(rel_dir.parts)):
149 for i in range(len(rel_dir.parts)):
150 parent = '/'.join(rel_dir.parts[0 : i + 1])
150 parent = '/'.join(rel_dir.parts[0 : i + 1])
151 manifest.setdefault(parent, {})
151 manifest.setdefault(parent, {})
152
152
153 for f in sorted(files):
153 for f in sorted(files):
154 full = root / f
154 full = root / f
155 manifest[str(rel_dir).replace('\\', '/')][full.name] = full
155 manifest[str(rel_dir).replace('\\', '/')][full.name] = full
156
156
157 component_groups = collections.defaultdict(list)
157 component_groups = collections.defaultdict(list)
158
158
159 # Now emit a <Fragment> for each directory.
159 # Now emit a <Fragment> for each directory.
160 # Each directory is composed of a <DirectoryRef> pointing to its parent
160 # Each directory is composed of a <DirectoryRef> pointing to its parent
161 # and defines child <Directory>'s and a <Component> with all the files.
161 # and defines child <Directory>'s and a <Component> with all the files.
162 for dir_name, entries in sorted(manifest.items()):
162 for dir_name, entries in sorted(manifest.items()):
163 # The directory id is derived from the path. But the root directory
163 # The directory id is derived from the path. But the root directory
164 # is special.
164 # is special.
165 if dir_name == '.':
165 if dir_name == '.':
166 parent_directory_id = 'INSTALLDIR'
166 parent_directory_id = 'INSTALLDIR'
167 else:
167 else:
168 parent_directory_id = 'hg.dir.%s' % dir_name.replace(
168 parent_directory_id = 'hg.dir.%s' % dir_name.replace(
169 '/', '.'
169 '/', '.'
170 ).replace('-', '_')
170 ).replace('-', '_')
171
171
172 fragment = doc.createElement('Fragment')
172 fragment = doc.createElement('Fragment')
173 directory_ref = doc.createElement('DirectoryRef')
173 directory_ref = doc.createElement('DirectoryRef')
174 directory_ref.setAttribute('Id', parent_directory_id)
174 directory_ref.setAttribute('Id', parent_directory_id)
175
175
176 # Add <Directory> entries for immediate children directories.
176 # Add <Directory> entries for immediate children directories.
177 for possible_child in sorted(manifest.keys()):
177 for possible_child in sorted(manifest.keys()):
178 if (
178 if (
179 dir_name == '.'
179 dir_name == '.'
180 and '/' not in possible_child
180 and '/' not in possible_child
181 and possible_child != '.'
181 and possible_child != '.'
182 ):
182 ):
183 child_directory_id = ('hg.dir.%s' % possible_child).replace(
183 child_directory_id = ('hg.dir.%s' % possible_child).replace(
184 '-', '_'
184 '-', '_'
185 )
185 )
186 name = possible_child
186 name = possible_child
187 else:
187 else:
188 if not possible_child.startswith('%s/' % dir_name):
188 if not possible_child.startswith('%s/' % dir_name):
189 continue
189 continue
190 name = possible_child[len(dir_name) + 1 :]
190 name = possible_child[len(dir_name) + 1 :]
191 if '/' in name:
191 if '/' in name:
192 continue
192 continue
193
193
194 child_directory_id = 'hg.dir.%s' % possible_child.replace(
194 child_directory_id = 'hg.dir.%s' % possible_child.replace(
195 '/', '.'
195 '/', '.'
196 ).replace('-', '_')
196 ).replace('-', '_')
197
197
198 directory = doc.createElement('Directory')
198 directory = doc.createElement('Directory')
199 directory.setAttribute('Id', child_directory_id)
199 directory.setAttribute('Id', child_directory_id)
200 directory.setAttribute('Name', name)
200 directory.setAttribute('Name', name)
201 directory_ref.appendChild(directory)
201 directory_ref.appendChild(directory)
202
202
203 # Add <Component>s for files in this directory.
203 # Add <Component>s for files in this directory.
204 for rel, source_path in sorted(entries.items()):
204 for rel, source_path in sorted(entries.items()):
205 if dir_name == '.':
205 if dir_name == '.':
206 full_rel = rel
206 full_rel = rel
207 else:
207 else:
208 full_rel = '%s/%s' % (dir_name, rel)
208 full_rel = '%s/%s' % (dir_name, rel)
209
209
210 component_unique_id = (
210 component_unique_id = (
211 'https://www.mercurial-scm.org/wix-installer/0/component/%s'
211 'https://www.mercurial-scm.org/wix-installer/0/component/%s'
212 % full_rel
212 % full_rel
213 )
213 )
214 component_guid = uuid.uuid5(uuid.NAMESPACE_URL, component_unique_id)
214 component_guid = uuid.uuid5(uuid.NAMESPACE_URL, component_unique_id)
215 component_id = 'hg.component.%s' % str(component_guid).replace(
215 component_id = 'hg.component.%s' % str(component_guid).replace(
216 '-', '_'
216 '-', '_'
217 )
217 )
218
218
219 component = doc.createElement('Component')
219 component = doc.createElement('Component')
220
220
221 component.setAttribute('Id', component_id)
221 component.setAttribute('Id', component_id)
222 component.setAttribute('Guid', str(component_guid).upper())
222 component.setAttribute('Guid', str(component_guid).upper())
223 component.setAttribute('Win64', 'yes' if is_x64 else 'no')
223 component.setAttribute('Win64', 'yes' if is_x64 else 'no')
224
224
225 # Assign this component to a top-level group.
225 # Assign this component to a top-level group.
226 if dir_name == '.':
226 if dir_name == '.':
227 component_groups['ROOT'].append(component_id)
227 component_groups['ROOT'].append(component_id)
228 elif '/' in dir_name:
228 elif '/' in dir_name:
229 component_groups[dir_name[0 : dir_name.index('/')]].append(
229 component_groups[dir_name[0 : dir_name.index('/')]].append(
230 component_id
230 component_id
231 )
231 )
232 else:
232 else:
233 component_groups[dir_name].append(component_id)
233 component_groups[dir_name].append(component_id)
234
234
235 unique_id = (
235 unique_id = (
236 'https://www.mercurial-scm.org/wix-installer/0/%s' % full_rel
236 'https://www.mercurial-scm.org/wix-installer/0/%s' % full_rel
237 )
237 )
238 file_guid = uuid.uuid5(uuid.NAMESPACE_URL, unique_id)
238 file_guid = uuid.uuid5(uuid.NAMESPACE_URL, unique_id)
239
239
240 # IDs have length limits. So use GUID to derive them.
240 # IDs have length limits. So use GUID to derive them.
241 file_guid_normalized = str(file_guid).replace('-', '_')
241 file_guid_normalized = str(file_guid).replace('-', '_')
242 file_id = 'hg.file.%s' % file_guid_normalized
242 file_id = 'hg.file.%s' % file_guid_normalized
243
243
244 file_element = doc.createElement('File')
244 file_element = doc.createElement('File')
245 file_element.setAttribute('Id', file_id)
245 file_element.setAttribute('Id', file_id)
246 file_element.setAttribute('Source', str(source_path))
246 file_element.setAttribute('Source', str(source_path))
247 file_element.setAttribute('KeyPath', 'yes')
247 file_element.setAttribute('KeyPath', 'yes')
248 file_element.setAttribute('ReadOnly', 'yes')
248 file_element.setAttribute('ReadOnly', 'yes')
249
249
250 component.appendChild(file_element)
250 component.appendChild(file_element)
251 directory_ref.appendChild(component)
251 directory_ref.appendChild(component)
252
252
253 fragment.appendChild(directory_ref)
253 fragment.appendChild(directory_ref)
254 doc.documentElement.appendChild(fragment)
254 doc.documentElement.appendChild(fragment)
255
255
256 for group, component_ids in sorted(component_groups.items()):
256 for group, component_ids in sorted(component_groups.items()):
257 fragment = doc.createElement('Fragment')
257 fragment = doc.createElement('Fragment')
258 component_group = doc.createElement('ComponentGroup')
258 component_group = doc.createElement('ComponentGroup')
259 component_group.setAttribute('Id', 'hg.group.%s' % group)
259 component_group.setAttribute('Id', 'hg.group.%s' % group)
260
260
261 for component_id in component_ids:
261 for component_id in component_ids:
262 component_ref = doc.createElement('ComponentRef')
262 component_ref = doc.createElement('ComponentRef')
263 component_ref.setAttribute('Id', component_id)
263 component_ref.setAttribute('Id', component_id)
264 component_group.appendChild(component_ref)
264 component_group.appendChild(component_ref)
265
265
266 fragment.appendChild(component_group)
266 fragment.appendChild(component_group)
267 doc.documentElement.appendChild(fragment)
267 doc.documentElement.appendChild(fragment)
268
268
269 # Add <Shortcut> to files that have it defined.
269 # Add <Shortcut> to files that have it defined.
270 for file_id, metadata in sorted(SHORTCUTS.items()):
270 for file_id, metadata in sorted(SHORTCUTS.items()):
271 els = doc.getElementsByTagName('File')
271 els = doc.getElementsByTagName('File')
272 els = [el for el in els if el.getAttribute('Id') == file_id]
272 els = [el for el in els if el.getAttribute('Id') == file_id]
273
273
274 if not els:
274 if not els:
275 raise Exception('could not find File[Id=%s]' % file_id)
275 raise Exception('could not find File[Id=%s]' % file_id)
276
276
277 for el in els:
277 for el in els:
278 shortcut = doc.createElement('Shortcut')
278 shortcut = doc.createElement('Shortcut')
279 shortcut.setAttribute('Id', 'hg.shortcut.%s' % file_id)
279 shortcut.setAttribute('Id', 'hg.shortcut.%s' % file_id)
280 shortcut.setAttribute('Directory', 'ProgramMenuDir')
280 shortcut.setAttribute('Directory', 'ProgramMenuDir')
281 shortcut.setAttribute('Icon', 'hgIcon.ico')
281 shortcut.setAttribute('Icon', 'hgIcon.ico')
282 shortcut.setAttribute('IconIndex', '0')
282 shortcut.setAttribute('IconIndex', '0')
283 shortcut.setAttribute('Advertise', 'yes')
283 shortcut.setAttribute('Advertise', 'yes')
284 for k, v in sorted(metadata.items()):
284 for k, v in sorted(metadata.items()):
285 shortcut.setAttribute(k, v)
285 shortcut.setAttribute(k, v)
286
286
287 el.appendChild(shortcut)
287 el.appendChild(shortcut)
288
288
289 return doc.toprettyxml()
289 return doc.toprettyxml()
290
290
291
291
292 def build_installer_py2exe(
292 def build_installer_py2exe(
293 source_dir: pathlib.Path,
293 source_dir: pathlib.Path,
294 python_exe: pathlib.Path,
294 python_exe: pathlib.Path,
295 msi_name='mercurial',
295 msi_name='mercurial',
296 version=None,
296 version=None,
297 extra_packages_script=None,
297 extra_packages_script=None,
298 extra_wxs: typing.Optional[typing.Dict[str, str]] = None,
298 extra_wxs: typing.Optional[typing.Dict[str, str]] = None,
299 extra_features: typing.Optional[typing.List[str]] = None,
299 extra_features: typing.Optional[typing.List[str]] = None,
300 signing_info: typing.Optional[typing.Dict[str, str]] = None,
300 signing_info: typing.Optional[typing.Dict[str, str]] = None,
301 ):
301 ):
302 """Build a WiX MSI installer using py2exe.
302 """Build a WiX MSI installer using py2exe.
303
303
304 ``source_dir`` is the path to the Mercurial source tree to use.
304 ``source_dir`` is the path to the Mercurial source tree to use.
305 ``arch`` is the target architecture. either ``x86`` or ``x64``.
305 ``arch`` is the target architecture. either ``x86`` or ``x64``.
306 ``python_exe`` is the path to the Python executable to use/bundle.
306 ``python_exe`` is the path to the Python executable to use/bundle.
307 ``version`` is the Mercurial version string. If not defined,
307 ``version`` is the Mercurial version string. If not defined,
308 ``mercurial/__version__.py`` will be consulted.
308 ``mercurial/__version__.py`` will be consulted.
309 ``extra_packages_script`` is a command to be run to inject extra packages
309 ``extra_packages_script`` is a command to be run to inject extra packages
310 into the py2exe binary. It should stage packages into the virtualenv and
310 into the py2exe binary. It should stage packages into the virtualenv and
311 print a null byte followed by a newline-separated list of packages that
311 print a null byte followed by a newline-separated list of packages that
312 should be included in the exe.
312 should be included in the exe.
313 ``extra_wxs`` is a dict of {wxs_name: working_dir_for_wxs_build}.
313 ``extra_wxs`` is a dict of {wxs_name: working_dir_for_wxs_build}.
314 ``extra_features`` is a list of additional named Features to include in
314 ``extra_features`` is a list of additional named Features to include in
315 the build. These must match Feature names in one of the wxs scripts.
315 the build. These must match Feature names in one of the wxs scripts.
316 """
316 """
317 arch = 'x64' if r'\x64' in os.environ.get('LIB', '') else 'x86'
317 arch = 'x64' if r'\x64' in os.environ.get('LIB', '') else 'x86'
318
318
319 hg_build_dir = source_dir / 'build'
319 hg_build_dir = source_dir / 'build'
320
320
321 requirements_txt = (
321 requirements_txt = (
322 source_dir / 'contrib' / 'packaging' / 'requirements_win32.txt'
322 source_dir / 'contrib' / 'packaging' / 'requirements-windows-py2.txt'
323 )
323 )
324
324
325 build_py2exe(
325 build_py2exe(
326 source_dir,
326 source_dir,
327 hg_build_dir,
327 hg_build_dir,
328 python_exe,
328 python_exe,
329 'wix',
329 'wix',
330 requirements_txt,
330 requirements_txt,
331 extra_packages=EXTRA_PACKAGES,
331 extra_packages=EXTRA_PACKAGES,
332 extra_packages_script=extra_packages_script,
332 extra_packages_script=extra_packages_script,
333 )
333 )
334
334
335 build_dir = hg_build_dir / ('wix-%s' % arch)
335 build_dir = hg_build_dir / ('wix-%s' % arch)
336 staging_dir = build_dir / 'stage'
336 staging_dir = build_dir / 'stage'
337
337
338 build_dir.mkdir(exist_ok=True)
338 build_dir.mkdir(exist_ok=True)
339
339
340 # Purge the staging directory for every build so packaging is pristine.
340 # Purge the staging directory for every build so packaging is pristine.
341 if staging_dir.exists():
341 if staging_dir.exists():
342 print('purging %s' % staging_dir)
342 print('purging %s' % staging_dir)
343 shutil.rmtree(staging_dir)
343 shutil.rmtree(staging_dir)
344
344
345 stage_install(source_dir, staging_dir, lower_case=True)
345 stage_install(source_dir, staging_dir, lower_case=True)
346
346
347 # We also install some extra files.
347 # We also install some extra files.
348 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
348 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
349
349
350 # And remove some files we don't want.
350 # And remove some files we don't want.
351 for f in STAGING_REMOVE_FILES:
351 for f in STAGING_REMOVE_FILES:
352 p = staging_dir / f
352 p = staging_dir / f
353 if p.exists():
353 if p.exists():
354 print('removing %s' % p)
354 print('removing %s' % p)
355 p.unlink()
355 p.unlink()
356
356
357 return run_wix_packaging(
357 return run_wix_packaging(
358 source_dir,
358 source_dir,
359 build_dir,
359 build_dir,
360 staging_dir,
360 staging_dir,
361 arch,
361 arch,
362 version=version,
362 version=version,
363 python2=True,
363 python2=True,
364 msi_name=msi_name,
364 msi_name=msi_name,
365 suffix="-python2",
365 suffix="-python2",
366 extra_wxs=extra_wxs,
366 extra_wxs=extra_wxs,
367 extra_features=extra_features,
367 extra_features=extra_features,
368 signing_info=signing_info,
368 signing_info=signing_info,
369 )
369 )
370
370
371
371
372 def build_installer_pyoxidizer(
372 def build_installer_pyoxidizer(
373 source_dir: pathlib.Path,
373 source_dir: pathlib.Path,
374 target_triple: str,
374 target_triple: str,
375 msi_name='mercurial',
375 msi_name='mercurial',
376 version=None,
376 version=None,
377 extra_wxs: typing.Optional[typing.Dict[str, str]] = None,
377 extra_wxs: typing.Optional[typing.Dict[str, str]] = None,
378 extra_features: typing.Optional[typing.List[str]] = None,
378 extra_features: typing.Optional[typing.List[str]] = None,
379 signing_info: typing.Optional[typing.Dict[str, str]] = None,
379 signing_info: typing.Optional[typing.Dict[str, str]] = None,
380 ):
380 ):
381 """Build a WiX MSI installer using PyOxidizer."""
381 """Build a WiX MSI installer using PyOxidizer."""
382 hg_build_dir = source_dir / "build"
382 hg_build_dir = source_dir / "build"
383 build_dir = hg_build_dir / ("wix-%s" % target_triple)
383 build_dir = hg_build_dir / ("wix-%s" % target_triple)
384 staging_dir = build_dir / "stage"
384 staging_dir = build_dir / "stage"
385
385
386 arch = "x64" if "x86_64" in target_triple else "x86"
386 arch = "x64" if "x86_64" in target_triple else "x86"
387
387
388 build_dir.mkdir(parents=True, exist_ok=True)
388 build_dir.mkdir(parents=True, exist_ok=True)
389 run_pyoxidizer(source_dir, build_dir, staging_dir, target_triple)
389 run_pyoxidizer(source_dir, build_dir, staging_dir, target_triple)
390
390
391 # We also install some extra files.
391 # We also install some extra files.
392 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
392 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
393
393
394 # And remove some files we don't want.
394 # And remove some files we don't want.
395 for f in STAGING_REMOVE_FILES:
395 for f in STAGING_REMOVE_FILES:
396 p = staging_dir / f
396 p = staging_dir / f
397 if p.exists():
397 if p.exists():
398 print('removing %s' % p)
398 print('removing %s' % p)
399 p.unlink()
399 p.unlink()
400
400
401 return run_wix_packaging(
401 return run_wix_packaging(
402 source_dir,
402 source_dir,
403 build_dir,
403 build_dir,
404 staging_dir,
404 staging_dir,
405 arch,
405 arch,
406 version,
406 version,
407 python2=False,
407 python2=False,
408 msi_name=msi_name,
408 msi_name=msi_name,
409 extra_wxs=extra_wxs,
409 extra_wxs=extra_wxs,
410 extra_features=extra_features,
410 extra_features=extra_features,
411 signing_info=signing_info,
411 signing_info=signing_info,
412 )
412 )
413
413
414
414
415 def run_wix_packaging(
415 def run_wix_packaging(
416 source_dir: pathlib.Path,
416 source_dir: pathlib.Path,
417 build_dir: pathlib.Path,
417 build_dir: pathlib.Path,
418 staging_dir: pathlib.Path,
418 staging_dir: pathlib.Path,
419 arch: str,
419 arch: str,
420 version: str,
420 version: str,
421 python2: bool,
421 python2: bool,
422 msi_name: typing.Optional[str] = "mercurial",
422 msi_name: typing.Optional[str] = "mercurial",
423 suffix: str = "",
423 suffix: str = "",
424 extra_wxs: typing.Optional[typing.Dict[str, str]] = None,
424 extra_wxs: typing.Optional[typing.Dict[str, str]] = None,
425 extra_features: typing.Optional[typing.List[str]] = None,
425 extra_features: typing.Optional[typing.List[str]] = None,
426 signing_info: typing.Optional[typing.Dict[str, str]] = None,
426 signing_info: typing.Optional[typing.Dict[str, str]] = None,
427 ):
427 ):
428 """Invokes WiX to package up a built Mercurial.
428 """Invokes WiX to package up a built Mercurial.
429
429
430 ``signing_info`` is a dict defining properties to facilitate signing the
430 ``signing_info`` is a dict defining properties to facilitate signing the
431 installer. Recognized keys include ``name``, ``subject_name``,
431 installer. Recognized keys include ``name``, ``subject_name``,
432 ``cert_path``, ``cert_password``, and ``timestamp_url``. If populated,
432 ``cert_path``, ``cert_password``, and ``timestamp_url``. If populated,
433 we will sign both the hg.exe and the .msi using the signing credentials
433 we will sign both the hg.exe and the .msi using the signing credentials
434 specified.
434 specified.
435 """
435 """
436
436
437 orig_version = version or find_version(source_dir)
437 orig_version = version or find_version(source_dir)
438 version = normalize_windows_version(orig_version)
438 version = normalize_windows_version(orig_version)
439 print('using version string: %s' % version)
439 print('using version string: %s' % version)
440 if version != orig_version:
440 if version != orig_version:
441 print('(normalized from: %s)' % orig_version)
441 print('(normalized from: %s)' % orig_version)
442
442
443 if signing_info:
443 if signing_info:
444 sign_with_signtool(
444 sign_with_signtool(
445 staging_dir / "hg.exe",
445 staging_dir / "hg.exe",
446 "%s %s" % (signing_info["name"], version),
446 "%s %s" % (signing_info["name"], version),
447 subject_name=signing_info["subject_name"],
447 subject_name=signing_info["subject_name"],
448 cert_path=signing_info["cert_path"],
448 cert_path=signing_info["cert_path"],
449 cert_password=signing_info["cert_password"],
449 cert_password=signing_info["cert_password"],
450 timestamp_url=signing_info["timestamp_url"],
450 timestamp_url=signing_info["timestamp_url"],
451 )
451 )
452
452
453 wix_dir = source_dir / 'contrib' / 'packaging' / 'wix'
453 wix_dir = source_dir / 'contrib' / 'packaging' / 'wix'
454
454
455 wix_pkg, wix_entry = download_entry('wix', build_dir)
455 wix_pkg, wix_entry = download_entry('wix', build_dir)
456 wix_path = build_dir / ('wix-%s' % wix_entry['version'])
456 wix_path = build_dir / ('wix-%s' % wix_entry['version'])
457
457
458 if not wix_path.exists():
458 if not wix_path.exists():
459 extract_zip_to_directory(wix_pkg, wix_path)
459 extract_zip_to_directory(wix_pkg, wix_path)
460
460
461 if python2:
461 if python2:
462 ensure_vc90_merge_modules(build_dir)
462 ensure_vc90_merge_modules(build_dir)
463
463
464 source_build_rel = pathlib.Path(os.path.relpath(source_dir, build_dir))
464 source_build_rel = pathlib.Path(os.path.relpath(source_dir, build_dir))
465
465
466 defines = {'Platform': arch}
466 defines = {'Platform': arch}
467
467
468 # Derive a .wxs file with the staged files.
468 # Derive a .wxs file with the staged files.
469 manifest_wxs = build_dir / 'stage.wxs'
469 manifest_wxs = build_dir / 'stage.wxs'
470 with manifest_wxs.open('w', encoding='utf-8') as fh:
470 with manifest_wxs.open('w', encoding='utf-8') as fh:
471 fh.write(make_files_xml(staging_dir, is_x64=arch == 'x64'))
471 fh.write(make_files_xml(staging_dir, is_x64=arch == 'x64'))
472
472
473 run_candle(wix_path, build_dir, manifest_wxs, staging_dir, defines=defines)
473 run_candle(wix_path, build_dir, manifest_wxs, staging_dir, defines=defines)
474
474
475 for source, rel_path in sorted((extra_wxs or {}).items()):
475 for source, rel_path in sorted((extra_wxs or {}).items()):
476 run_candle(wix_path, build_dir, source, rel_path, defines=defines)
476 run_candle(wix_path, build_dir, source, rel_path, defines=defines)
477
477
478 source = wix_dir / 'mercurial.wxs'
478 source = wix_dir / 'mercurial.wxs'
479 defines['Version'] = version
479 defines['Version'] = version
480 defines['Comments'] = 'Installs Mercurial version %s' % version
480 defines['Comments'] = 'Installs Mercurial version %s' % version
481
481
482 if python2:
482 if python2:
483 defines["PythonVersion"] = "2"
483 defines["PythonVersion"] = "2"
484 defines['VCRedistSrcDir'] = str(build_dir)
484 defines['VCRedistSrcDir'] = str(build_dir)
485 else:
485 else:
486 defines["PythonVersion"] = "3"
486 defines["PythonVersion"] = "3"
487
487
488 if (staging_dir / "lib").exists():
488 if (staging_dir / "lib").exists():
489 defines["MercurialHasLib"] = "1"
489 defines["MercurialHasLib"] = "1"
490
490
491 if extra_features:
491 if extra_features:
492 assert all(';' not in f for f in extra_features)
492 assert all(';' not in f for f in extra_features)
493 defines['MercurialExtraFeatures'] = ';'.join(extra_features)
493 defines['MercurialExtraFeatures'] = ';'.join(extra_features)
494
494
495 run_candle(wix_path, build_dir, source, source_build_rel, defines=defines)
495 run_candle(wix_path, build_dir, source, source_build_rel, defines=defines)
496
496
497 msi_path = (
497 msi_path = (
498 source_dir
498 source_dir
499 / 'dist'
499 / 'dist'
500 / ('%s-%s-%s%s.msi' % (msi_name, orig_version, arch, suffix))
500 / ('%s-%s-%s%s.msi' % (msi_name, orig_version, arch, suffix))
501 )
501 )
502
502
503 args = [
503 args = [
504 str(wix_path / 'light.exe'),
504 str(wix_path / 'light.exe'),
505 '-nologo',
505 '-nologo',
506 '-ext',
506 '-ext',
507 'WixUIExtension',
507 'WixUIExtension',
508 '-sw1076',
508 '-sw1076',
509 '-spdb',
509 '-spdb',
510 '-o',
510 '-o',
511 str(msi_path),
511 str(msi_path),
512 ]
512 ]
513
513
514 for source, rel_path in sorted((extra_wxs or {}).items()):
514 for source, rel_path in sorted((extra_wxs or {}).items()):
515 assert source.endswith('.wxs')
515 assert source.endswith('.wxs')
516 source = os.path.basename(source)
516 source = os.path.basename(source)
517 args.append(str(build_dir / ('%s.wixobj' % source[:-4])))
517 args.append(str(build_dir / ('%s.wixobj' % source[:-4])))
518
518
519 args.extend(
519 args.extend(
520 [str(build_dir / 'stage.wixobj'), str(build_dir / 'mercurial.wixobj'),]
520 [str(build_dir / 'stage.wixobj'), str(build_dir / 'mercurial.wixobj'),]
521 )
521 )
522
522
523 subprocess.run(args, cwd=str(source_dir), check=True)
523 subprocess.run(args, cwd=str(source_dir), check=True)
524
524
525 print('%s created' % msi_path)
525 print('%s created' % msi_path)
526
526
527 if signing_info:
527 if signing_info:
528 sign_with_signtool(
528 sign_with_signtool(
529 msi_path,
529 msi_path,
530 "%s %s" % (signing_info["name"], version),
530 "%s %s" % (signing_info["name"], version),
531 subject_name=signing_info["subject_name"],
531 subject_name=signing_info["subject_name"],
532 cert_path=signing_info["cert_path"],
532 cert_path=signing_info["cert_path"],
533 cert_password=signing_info["cert_password"],
533 cert_password=signing_info["cert_password"],
534 timestamp_url=signing_info["timestamp_url"],
534 timestamp_url=signing_info["timestamp_url"],
535 )
535 )
536
536
537 return {
537 return {
538 'msi_path': msi_path,
538 'msi_path': msi_path,
539 }
539 }
@@ -1,117 +1,129 b''
1 #
1 #
2 # This file is autogenerated by pip-compile
2 # This file is autogenerated by pip-compile
3 # To update, run:
3 # To update, run:
4 #
4 #
5 # pip-compile --generate-hashes --output-file=contrib/packaging/requirements_win32.txt contrib/packaging/requirements_win32.txt.in
5 # pip-compile --generate-hashes --output-file=contrib/packaging/requirements-windows-py2.txt contrib/packaging/requirements-windows.txt.in
6 #
6 #
7 certifi==2020.6.20 \
7 certifi==2020.6.20 \
8 --hash=sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3 \
8 --hash=sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3 \
9 --hash=sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41 \
9 --hash=sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41 \
10 # via dulwich
10 # via dulwich
11 cffi==1.14.3 \
11 cffi==1.14.3 \
12 --hash=sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d \
12 --hash=sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d \
13 --hash=sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b \
13 --hash=sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b \
14 --hash=sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4 \
14 --hash=sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4 \
15 --hash=sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f \
15 --hash=sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f \
16 --hash=sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3 \
16 --hash=sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3 \
17 --hash=sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579 \
17 --hash=sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579 \
18 --hash=sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537 \
18 --hash=sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537 \
19 --hash=sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e \
19 --hash=sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e \
20 --hash=sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05 \
20 --hash=sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05 \
21 --hash=sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171 \
21 --hash=sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171 \
22 --hash=sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca \
22 --hash=sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca \
23 --hash=sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522 \
23 --hash=sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522 \
24 --hash=sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c \
24 --hash=sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c \
25 --hash=sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc \
25 --hash=sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc \
26 --hash=sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d \
26 --hash=sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d \
27 --hash=sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808 \
27 --hash=sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808 \
28 --hash=sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828 \
28 --hash=sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828 \
29 --hash=sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869 \
29 --hash=sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869 \
30 --hash=sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d \
30 --hash=sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d \
31 --hash=sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9 \
31 --hash=sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9 \
32 --hash=sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0 \
32 --hash=sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0 \
33 --hash=sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc \
33 --hash=sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc \
34 --hash=sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15 \
34 --hash=sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15 \
35 --hash=sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c \
35 --hash=sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c \
36 --hash=sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a \
36 --hash=sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a \
37 --hash=sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3 \
37 --hash=sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3 \
38 --hash=sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1 \
38 --hash=sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1 \
39 --hash=sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768 \
39 --hash=sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768 \
40 --hash=sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d \
40 --hash=sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d \
41 --hash=sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b \
41 --hash=sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b \
42 --hash=sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e \
42 --hash=sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e \
43 --hash=sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d \
43 --hash=sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d \
44 --hash=sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730 \
44 --hash=sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730 \
45 --hash=sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394 \
45 --hash=sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394 \
46 --hash=sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1 \
46 --hash=sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1 \
47 --hash=sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591 \
47 --hash=sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591 \
48 # via cryptography
48 # via cryptography
49 configparser==4.0.2 \
50 --hash=sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c \
51 --hash=sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df \
52 # via entrypoints
49 cryptography==3.1.1 \
53 cryptography==3.1.1 \
50 --hash=sha256:21b47c59fcb1c36f1113f3709d37935368e34815ea1d7073862e92f810dc7499 \
54 --hash=sha256:21b47c59fcb1c36f1113f3709d37935368e34815ea1d7073862e92f810dc7499 \
51 --hash=sha256:451cdf60be4dafb6a3b78802006a020e6cd709c22d240f94f7a0696240a17154 \
55 --hash=sha256:451cdf60be4dafb6a3b78802006a020e6cd709c22d240f94f7a0696240a17154 \
52 --hash=sha256:4549b137d8cbe3c2eadfa56c0c858b78acbeff956bd461e40000b2164d9167c6 \
56 --hash=sha256:4549b137d8cbe3c2eadfa56c0c858b78acbeff956bd461e40000b2164d9167c6 \
53 --hash=sha256:48ee615a779ffa749d7d50c291761dc921d93d7cf203dca2db663b4f193f0e49 \
57 --hash=sha256:48ee615a779ffa749d7d50c291761dc921d93d7cf203dca2db663b4f193f0e49 \
54 --hash=sha256:559d622aef2a2dff98a892eef321433ba5bc55b2485220a8ca289c1ecc2bd54f \
58 --hash=sha256:559d622aef2a2dff98a892eef321433ba5bc55b2485220a8ca289c1ecc2bd54f \
55 --hash=sha256:5d52c72449bb02dd45a773a203196e6d4fae34e158769c896012401f33064396 \
59 --hash=sha256:5d52c72449bb02dd45a773a203196e6d4fae34e158769c896012401f33064396 \
56 --hash=sha256:65beb15e7f9c16e15934569d29fb4def74ea1469d8781f6b3507ab896d6d8719 \
60 --hash=sha256:65beb15e7f9c16e15934569d29fb4def74ea1469d8781f6b3507ab896d6d8719 \
57 --hash=sha256:680da076cad81cdf5ffcac50c477b6790be81768d30f9da9e01960c4b18a66db \
61 --hash=sha256:680da076cad81cdf5ffcac50c477b6790be81768d30f9da9e01960c4b18a66db \
58 --hash=sha256:762bc5a0df03c51ee3f09c621e1cee64e3a079a2b5020de82f1613873d79ee70 \
62 --hash=sha256:762bc5a0df03c51ee3f09c621e1cee64e3a079a2b5020de82f1613873d79ee70 \
59 --hash=sha256:89aceb31cd5f9fc2449fe8cf3810797ca52b65f1489002d58fe190bfb265c536 \
63 --hash=sha256:89aceb31cd5f9fc2449fe8cf3810797ca52b65f1489002d58fe190bfb265c536 \
60 --hash=sha256:983c0c3de4cb9fcba68fd3f45ed846eb86a2a8b8d8bc5bb18364c4d00b3c61fe \
64 --hash=sha256:983c0c3de4cb9fcba68fd3f45ed846eb86a2a8b8d8bc5bb18364c4d00b3c61fe \
61 --hash=sha256:99d4984aabd4c7182050bca76176ce2dbc9fa9748afe583a7865c12954d714ba \
65 --hash=sha256:99d4984aabd4c7182050bca76176ce2dbc9fa9748afe583a7865c12954d714ba \
62 --hash=sha256:9d9fc6a16357965d282dd4ab6531013935425d0dc4950df2e0cf2a1b1ac1017d \
66 --hash=sha256:9d9fc6a16357965d282dd4ab6531013935425d0dc4950df2e0cf2a1b1ac1017d \
63 --hash=sha256:a7597ffc67987b37b12e09c029bd1dc43965f75d328076ae85721b84046e9ca7 \
67 --hash=sha256:a7597ffc67987b37b12e09c029bd1dc43965f75d328076ae85721b84046e9ca7 \
64 --hash=sha256:ab010e461bb6b444eaf7f8c813bb716be2d78ab786103f9608ffd37a4bd7d490 \
68 --hash=sha256:ab010e461bb6b444eaf7f8c813bb716be2d78ab786103f9608ffd37a4bd7d490 \
65 --hash=sha256:b12e715c10a13ca1bd27fbceed9adc8c5ff640f8e1f7ea76416352de703523c8 \
69 --hash=sha256:b12e715c10a13ca1bd27fbceed9adc8c5ff640f8e1f7ea76416352de703523c8 \
66 --hash=sha256:b2bded09c578d19e08bd2c5bb8fed7f103e089752c9cf7ca7ca7de522326e921 \
70 --hash=sha256:b2bded09c578d19e08bd2c5bb8fed7f103e089752c9cf7ca7ca7de522326e921 \
67 --hash=sha256:b372026ebf32fe2523159f27d9f0e9f485092e43b00a5adacf732192a70ba118 \
71 --hash=sha256:b372026ebf32fe2523159f27d9f0e9f485092e43b00a5adacf732192a70ba118 \
68 --hash=sha256:cb179acdd4ae1e4a5a160d80b87841b3d0e0be84af46c7bb2cd7ece57a39c4ba \
72 --hash=sha256:cb179acdd4ae1e4a5a160d80b87841b3d0e0be84af46c7bb2cd7ece57a39c4ba \
69 --hash=sha256:e97a3b627e3cb63c415a16245d6cef2139cca18bb1183d1b9375a1c14e83f3b3 \
73 --hash=sha256:e97a3b627e3cb63c415a16245d6cef2139cca18bb1183d1b9375a1c14e83f3b3 \
70 --hash=sha256:f0e099fc4cc697450c3dd4031791559692dd941a95254cb9aeded66a7aa8b9bc \
74 --hash=sha256:f0e099fc4cc697450c3dd4031791559692dd941a95254cb9aeded66a7aa8b9bc \
71 --hash=sha256:f99317a0fa2e49917689b8cf977510addcfaaab769b3f899b9c481bbd76730c2 \
75 --hash=sha256:f99317a0fa2e49917689b8cf977510addcfaaab769b3f899b9c481bbd76730c2 \
72 # via secretstorage
76 # via secretstorage
73 docutils==0.16 \
77 docutils==0.16 \
74 --hash=sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af \
78 --hash=sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af \
75 --hash=sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc \
79 --hash=sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc \
76 # via -r contrib/packaging/requirements_win32.txt.in
80 # via -r contrib/packaging/requirements-windows.txt.in
77 dulwich==0.19.16 \
81 dulwich==0.19.16 ; python_version <= "2.7" \
78 --hash=sha256:10699277c6268d0c16febe141a5b1c1a6e9744f3144c2d2de1706f4b1adafe63 \
82 --hash=sha256:10699277c6268d0c16febe141a5b1c1a6e9744f3144c2d2de1706f4b1adafe63 \
79 --hash=sha256:267160904e9a1cb6c248c5efc53597a35d038ecc6f60bdc4546b3053bed11982 \
83 --hash=sha256:267160904e9a1cb6c248c5efc53597a35d038ecc6f60bdc4546b3053bed11982 \
80 --hash=sha256:4e3aba5e4844e7c700721c1fc696987ea820ee3528a03604dc4e74eff4196826 \
84 --hash=sha256:4e3aba5e4844e7c700721c1fc696987ea820ee3528a03604dc4e74eff4196826 \
81 --hash=sha256:60bb2c2c92f5025c1b53a556304008f0f624c98ae36f22d870e056b2d4236c11 \
85 --hash=sha256:60bb2c2c92f5025c1b53a556304008f0f624c98ae36f22d870e056b2d4236c11 \
82 --hash=sha256:dddae02d372fc3b5cfb0046d0f62246ef281fa0c088df7601ab5916607add94b \
86 --hash=sha256:dddae02d372fc3b5cfb0046d0f62246ef281fa0c088df7601ab5916607add94b \
83 --hash=sha256:f00d132082b8fcc2eb0d722abc773d4aeb5558c1475d7edd1f0f571146c29db9 \
87 --hash=sha256:f00d132082b8fcc2eb0d722abc773d4aeb5558c1475d7edd1f0f571146c29db9 \
84 --hash=sha256:f74561c448bfb6f04c07de731c1181ae4280017f759b0bb04fa5770aa84ca850 \
88 --hash=sha256:f74561c448bfb6f04c07de731c1181ae4280017f759b0bb04fa5770aa84ca850 \
85 # via -r contrib/packaging/requirements_win32.txt.in
89 # via -r contrib/packaging/requirements-windows.txt.in
86 jeepney==0.4.3 \
90 entrypoints==0.3 \
87 --hash=sha256:3479b861cc2b6407de5188695fa1a8d57e5072d7059322469b62628869b8e36e \
91 --hash=sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19 \
88 --hash=sha256:d6c6b49683446d2407d2fe3acb7a368a77ff063f9182fe427da15d622adc24cf \
92 --hash=sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451 \
89 # via keyring, secretstorage
93 # via keyring
90 keyring==21.4.0 \
94 enum34==1.1.10 \
91 --hash=sha256:4e34ea2fdec90c1c43d6610b5a5fafa1b9097db1802948e90caf5763974b8f8d \
95 --hash=sha256:a98a201d6de3f2ab3db284e70a33b0f896fbf35f8086594e8c9e74b909058d53 \
92 --hash=sha256:9aeadd006a852b78f4b4ef7c7556c2774d2432bbef8ee538a3e9089ac8b11466 \
96 --hash=sha256:c3858660960c984d6ab0ebad691265180da2b43f07e061c0f8dca9ef3cffd328 \
93 # via -r contrib/packaging/requirements_win32.txt.in
97 --hash=sha256:cce6a7477ed816bd2542d03d53db9f0db935dd013b70f336a95c73979289f248 \
98 # via cryptography
99 ipaddress==1.0.23 \
100 --hash=sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc \
101 --hash=sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2 \
102 # via cryptography
103 keyring==18.0.1 \
104 --hash=sha256:67d6cc0132bd77922725fae9f18366bb314fd8f95ff4d323a4df41890a96a838 \
105 --hash=sha256:7b29ebfcf8678c4da531b2478a912eea01e80007e5ddca9ee0c7038cb3489ec6 \
106 # via -r contrib/packaging/requirements-windows.txt.in
94 pycparser==2.20 \
107 pycparser==2.20 \
95 --hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \
108 --hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \
96 --hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705 \
109 --hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705 \
97 # via cffi
110 # via cffi
98 pygments==2.7.1 \
111 pygments==2.5.2 \
99 --hash=sha256:307543fe65c0947b126e83dd5a61bd8acbd84abec11f43caebaf5534cbc17998 \
112 --hash=sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b \
100 --hash=sha256:926c3f319eda178d1bd90851e4317e6d8cdb5e292a3386aac9bd75eca29cf9c7 \
113 --hash=sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe \
101 # via -r contrib/packaging/requirements_win32.txt.in
114 # via -r contrib/packaging/requirements-windows.txt.in
102 pywin32-ctypes==0.2.0 \
115 pywin32-ctypes==0.2.0 \
103 --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
116 --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
104 --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 \
117 --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 \
105 # via -r contrib/packaging/requirements_win32.txt.in
118 # via -r contrib/packaging/requirements-windows.txt.in
106 secretstorage==3.1.2 \
119 secretstorage==2.3.1 \
107 --hash=sha256:15da8a989b65498e29be338b3b279965f1b8f09b9668bd8010da183024c8bff6 \
120 --hash=sha256:3af65c87765323e6f64c83575b05393f9e003431959c9395d1791d51497f29b6 \
108 --hash=sha256:b5ec909dde94d4ae2fa26af7c089036997030f0cf0a5cb372b4cccabd81c143b \
109 # via keyring
121 # via keyring
110 six==1.15.0 \
122 six==1.15.0 \
111 --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \
123 --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \
112 --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \
124 --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \
113 # via cryptography
125 # via cryptography
114 urllib3==1.25.10 \
126 urllib3==1.25.11 \
115 --hash=sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a \
127 --hash=sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2 \
116 --hash=sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461 \
128 --hash=sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e \
117 # via dulwich
129 # via dulwich
@@ -1,117 +1,123 b''
1 #
1 #
2 # This file is autogenerated by pip-compile
2 # This file is autogenerated by pip-compile
3 # To update, run:
3 # To update, run:
4 #
4 #
5 # pip-compile --generate-hashes --output-file=contrib/packaging/requirements_win32.txt contrib/packaging/requirements_win32.txt.in
5 # pip-compile --generate-hashes --output-file=contrib/packaging/requirements-windows-py3.txt contrib/packaging/requirements-windows.txt.in
6 #
6 #
7 certifi==2020.6.20 \
7 certifi==2020.6.20 \
8 --hash=sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3 \
8 --hash=sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3 \
9 --hash=sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41 \
9 --hash=sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41 \
10 # via dulwich
10 # via dulwich
11 cffi==1.14.3 \
11 cffi==1.14.3 \
12 --hash=sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d \
12 --hash=sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d \
13 --hash=sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b \
13 --hash=sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b \
14 --hash=sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4 \
14 --hash=sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4 \
15 --hash=sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f \
15 --hash=sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f \
16 --hash=sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3 \
16 --hash=sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3 \
17 --hash=sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579 \
17 --hash=sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579 \
18 --hash=sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537 \
18 --hash=sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537 \
19 --hash=sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e \
19 --hash=sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e \
20 --hash=sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05 \
20 --hash=sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05 \
21 --hash=sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171 \
21 --hash=sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171 \
22 --hash=sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca \
22 --hash=sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca \
23 --hash=sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522 \
23 --hash=sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522 \
24 --hash=sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c \
24 --hash=sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c \
25 --hash=sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc \
25 --hash=sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc \
26 --hash=sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d \
26 --hash=sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d \
27 --hash=sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808 \
27 --hash=sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808 \
28 --hash=sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828 \
28 --hash=sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828 \
29 --hash=sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869 \
29 --hash=sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869 \
30 --hash=sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d \
30 --hash=sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d \
31 --hash=sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9 \
31 --hash=sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9 \
32 --hash=sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0 \
32 --hash=sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0 \
33 --hash=sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc \
33 --hash=sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc \
34 --hash=sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15 \
34 --hash=sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15 \
35 --hash=sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c \
35 --hash=sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c \
36 --hash=sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a \
36 --hash=sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a \
37 --hash=sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3 \
37 --hash=sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3 \
38 --hash=sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1 \
38 --hash=sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1 \
39 --hash=sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768 \
39 --hash=sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768 \
40 --hash=sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d \
40 --hash=sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d \
41 --hash=sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b \
41 --hash=sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b \
42 --hash=sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e \
42 --hash=sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e \
43 --hash=sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d \
43 --hash=sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d \
44 --hash=sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730 \
44 --hash=sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730 \
45 --hash=sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394 \
45 --hash=sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394 \
46 --hash=sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1 \
46 --hash=sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1 \
47 --hash=sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591 \
47 --hash=sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591 \
48 # via cryptography
48 # via cryptography
49 cryptography==3.1.1 \
49 cryptography==3.1.1 \
50 --hash=sha256:21b47c59fcb1c36f1113f3709d37935368e34815ea1d7073862e92f810dc7499 \
50 --hash=sha256:21b47c59fcb1c36f1113f3709d37935368e34815ea1d7073862e92f810dc7499 \
51 --hash=sha256:451cdf60be4dafb6a3b78802006a020e6cd709c22d240f94f7a0696240a17154 \
51 --hash=sha256:451cdf60be4dafb6a3b78802006a020e6cd709c22d240f94f7a0696240a17154 \
52 --hash=sha256:4549b137d8cbe3c2eadfa56c0c858b78acbeff956bd461e40000b2164d9167c6 \
52 --hash=sha256:4549b137d8cbe3c2eadfa56c0c858b78acbeff956bd461e40000b2164d9167c6 \
53 --hash=sha256:48ee615a779ffa749d7d50c291761dc921d93d7cf203dca2db663b4f193f0e49 \
53 --hash=sha256:48ee615a779ffa749d7d50c291761dc921d93d7cf203dca2db663b4f193f0e49 \
54 --hash=sha256:559d622aef2a2dff98a892eef321433ba5bc55b2485220a8ca289c1ecc2bd54f \
54 --hash=sha256:559d622aef2a2dff98a892eef321433ba5bc55b2485220a8ca289c1ecc2bd54f \
55 --hash=sha256:5d52c72449bb02dd45a773a203196e6d4fae34e158769c896012401f33064396 \
55 --hash=sha256:5d52c72449bb02dd45a773a203196e6d4fae34e158769c896012401f33064396 \
56 --hash=sha256:65beb15e7f9c16e15934569d29fb4def74ea1469d8781f6b3507ab896d6d8719 \
56 --hash=sha256:65beb15e7f9c16e15934569d29fb4def74ea1469d8781f6b3507ab896d6d8719 \
57 --hash=sha256:680da076cad81cdf5ffcac50c477b6790be81768d30f9da9e01960c4b18a66db \
57 --hash=sha256:680da076cad81cdf5ffcac50c477b6790be81768d30f9da9e01960c4b18a66db \
58 --hash=sha256:762bc5a0df03c51ee3f09c621e1cee64e3a079a2b5020de82f1613873d79ee70 \
58 --hash=sha256:762bc5a0df03c51ee3f09c621e1cee64e3a079a2b5020de82f1613873d79ee70 \
59 --hash=sha256:89aceb31cd5f9fc2449fe8cf3810797ca52b65f1489002d58fe190bfb265c536 \
59 --hash=sha256:89aceb31cd5f9fc2449fe8cf3810797ca52b65f1489002d58fe190bfb265c536 \
60 --hash=sha256:983c0c3de4cb9fcba68fd3f45ed846eb86a2a8b8d8bc5bb18364c4d00b3c61fe \
60 --hash=sha256:983c0c3de4cb9fcba68fd3f45ed846eb86a2a8b8d8bc5bb18364c4d00b3c61fe \
61 --hash=sha256:99d4984aabd4c7182050bca76176ce2dbc9fa9748afe583a7865c12954d714ba \
61 --hash=sha256:99d4984aabd4c7182050bca76176ce2dbc9fa9748afe583a7865c12954d714ba \
62 --hash=sha256:9d9fc6a16357965d282dd4ab6531013935425d0dc4950df2e0cf2a1b1ac1017d \
62 --hash=sha256:9d9fc6a16357965d282dd4ab6531013935425d0dc4950df2e0cf2a1b1ac1017d \
63 --hash=sha256:a7597ffc67987b37b12e09c029bd1dc43965f75d328076ae85721b84046e9ca7 \
63 --hash=sha256:a7597ffc67987b37b12e09c029bd1dc43965f75d328076ae85721b84046e9ca7 \
64 --hash=sha256:ab010e461bb6b444eaf7f8c813bb716be2d78ab786103f9608ffd37a4bd7d490 \
64 --hash=sha256:ab010e461bb6b444eaf7f8c813bb716be2d78ab786103f9608ffd37a4bd7d490 \
65 --hash=sha256:b12e715c10a13ca1bd27fbceed9adc8c5ff640f8e1f7ea76416352de703523c8 \
65 --hash=sha256:b12e715c10a13ca1bd27fbceed9adc8c5ff640f8e1f7ea76416352de703523c8 \
66 --hash=sha256:b2bded09c578d19e08bd2c5bb8fed7f103e089752c9cf7ca7ca7de522326e921 \
66 --hash=sha256:b2bded09c578d19e08bd2c5bb8fed7f103e089752c9cf7ca7ca7de522326e921 \
67 --hash=sha256:b372026ebf32fe2523159f27d9f0e9f485092e43b00a5adacf732192a70ba118 \
67 --hash=sha256:b372026ebf32fe2523159f27d9f0e9f485092e43b00a5adacf732192a70ba118 \
68 --hash=sha256:cb179acdd4ae1e4a5a160d80b87841b3d0e0be84af46c7bb2cd7ece57a39c4ba \
68 --hash=sha256:cb179acdd4ae1e4a5a160d80b87841b3d0e0be84af46c7bb2cd7ece57a39c4ba \
69 --hash=sha256:e97a3b627e3cb63c415a16245d6cef2139cca18bb1183d1b9375a1c14e83f3b3 \
69 --hash=sha256:e97a3b627e3cb63c415a16245d6cef2139cca18bb1183d1b9375a1c14e83f3b3 \
70 --hash=sha256:f0e099fc4cc697450c3dd4031791559692dd941a95254cb9aeded66a7aa8b9bc \
70 --hash=sha256:f0e099fc4cc697450c3dd4031791559692dd941a95254cb9aeded66a7aa8b9bc \
71 --hash=sha256:f99317a0fa2e49917689b8cf977510addcfaaab769b3f899b9c481bbd76730c2 \
71 --hash=sha256:f99317a0fa2e49917689b8cf977510addcfaaab769b3f899b9c481bbd76730c2 \
72 # via secretstorage
72 # via secretstorage
73 docutils==0.16 \
73 docutils==0.16 \
74 --hash=sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af \
74 --hash=sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af \
75 --hash=sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc \
75 --hash=sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc \
76 # via -r contrib/packaging/requirements_win32.txt.in
76 # via -r contrib/packaging/requirements-windows.txt.in
77 dulwich==0.19.16 \
77 dulwich==0.20.6 ; python_version >= "3" \
78 --hash=sha256:10699277c6268d0c16febe141a5b1c1a6e9744f3144c2d2de1706f4b1adafe63 \
78 --hash=sha256:1ccd55e38fa9f169290f93e027ab4508202f5bdd6ef534facac4edd3f6903f0d \
79 --hash=sha256:267160904e9a1cb6c248c5efc53597a35d038ecc6f60bdc4546b3053bed11982 \
79 --hash=sha256:2452a0379cc7bbbd7ab893ec104d18039f1ea98b0d6be6bca5646e5cf29e0ae9 \
80 --hash=sha256:4e3aba5e4844e7c700721c1fc696987ea820ee3528a03604dc4e74eff4196826 \
80 --hash=sha256:2f4aebc54ed2d37dcee737024421452375570a422eb682232e676aa7ebc9cb4b \
81 --hash=sha256:60bb2c2c92f5025c1b53a556304008f0f624c98ae36f22d870e056b2d4236c11 \
81 --hash=sha256:304f52b10c49c3a6ddfbd73e2e93d8e979350225cfba9688e51110e74fa2f718 \
82 --hash=sha256:dddae02d372fc3b5cfb0046d0f62246ef281fa0c088df7601ab5916607add94b \
82 --hash=sha256:49e747c72d9099e873bf6196260346d5996c3f28af788294d47a8accdc524de7 \
83 --hash=sha256:f00d132082b8fcc2eb0d722abc773d4aeb5558c1475d7edd1f0f571146c29db9 \
83 --hash=sha256:4fee359928c59b53af153a582a7ed7595259a5a825df400301a29e17fd78dfd3 \
84 --hash=sha256:f74561c448bfb6f04c07de731c1181ae4280017f759b0bb04fa5770aa84ca850 \
84 --hash=sha256:50ef300a9fa4efd9f85009c2bd8b515266ec1529400f8834f85c04fa9f09b2c0 \
85 # via -r contrib/packaging/requirements_win32.txt.in
85 --hash=sha256:5348310f21b2a23847342ce464461499b6652483fa42de03714d0f6421a99698 \
86 --hash=sha256:7e7b5dea5178b6493fdb83adccbe81de9ddff55f79880185ed594c0e3a97209b \
87 --hash=sha256:8f7a7f973be2beedfb10dd8d3eb6bdf9ec466c72ad555704897cbd6357fe5021 \
88 --hash=sha256:bea6e6caffc6c73bfd1647714c5715ab96ac49deb8beb8b67511529afa25685a \
89 --hash=sha256:e5871b86a079e9e290f52ab14559cea1b694a0b8ed2b9ebb898f6ced7f14a406 \
90 --hash=sha256:e593f514b8ac740b4ceeb047745b4719bfc9f334904245c6edcb3a9d002f577b \
91 # via -r contrib/packaging/requirements-windows.txt.in
86 jeepney==0.4.3 \
92 jeepney==0.4.3 \
87 --hash=sha256:3479b861cc2b6407de5188695fa1a8d57e5072d7059322469b62628869b8e36e \
93 --hash=sha256:3479b861cc2b6407de5188695fa1a8d57e5072d7059322469b62628869b8e36e \
88 --hash=sha256:d6c6b49683446d2407d2fe3acb7a368a77ff063f9182fe427da15d622adc24cf \
94 --hash=sha256:d6c6b49683446d2407d2fe3acb7a368a77ff063f9182fe427da15d622adc24cf \
89 # via keyring, secretstorage
95 # via keyring, secretstorage
90 keyring==21.4.0 \
96 keyring==21.4.0 \
91 --hash=sha256:4e34ea2fdec90c1c43d6610b5a5fafa1b9097db1802948e90caf5763974b8f8d \
97 --hash=sha256:4e34ea2fdec90c1c43d6610b5a5fafa1b9097db1802948e90caf5763974b8f8d \
92 --hash=sha256:9aeadd006a852b78f4b4ef7c7556c2774d2432bbef8ee538a3e9089ac8b11466 \
98 --hash=sha256:9aeadd006a852b78f4b4ef7c7556c2774d2432bbef8ee538a3e9089ac8b11466 \
93 # via -r contrib/packaging/requirements_win32.txt.in
99 # via -r contrib/packaging/requirements-windows.txt.in
94 pycparser==2.20 \
100 pycparser==2.20 \
95 --hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \
101 --hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \
96 --hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705 \
102 --hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705 \
97 # via cffi
103 # via cffi
98 pygments==2.7.1 \
104 pygments==2.7.1 \
99 --hash=sha256:307543fe65c0947b126e83dd5a61bd8acbd84abec11f43caebaf5534cbc17998 \
105 --hash=sha256:307543fe65c0947b126e83dd5a61bd8acbd84abec11f43caebaf5534cbc17998 \
100 --hash=sha256:926c3f319eda178d1bd90851e4317e6d8cdb5e292a3386aac9bd75eca29cf9c7 \
106 --hash=sha256:926c3f319eda178d1bd90851e4317e6d8cdb5e292a3386aac9bd75eca29cf9c7 \
101 # via -r contrib/packaging/requirements_win32.txt.in
107 # via -r contrib/packaging/requirements-windows.txt.in
102 pywin32-ctypes==0.2.0 \
108 pywin32-ctypes==0.2.0 \
103 --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
109 --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
104 --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 \
110 --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 \
105 # via -r contrib/packaging/requirements_win32.txt.in
111 # via -r contrib/packaging/requirements-windows.txt.in
106 secretstorage==3.1.2 \
112 secretstorage==3.1.2 \
107 --hash=sha256:15da8a989b65498e29be338b3b279965f1b8f09b9668bd8010da183024c8bff6 \
113 --hash=sha256:15da8a989b65498e29be338b3b279965f1b8f09b9668bd8010da183024c8bff6 \
108 --hash=sha256:b5ec909dde94d4ae2fa26af7c089036997030f0cf0a5cb372b4cccabd81c143b \
114 --hash=sha256:b5ec909dde94d4ae2fa26af7c089036997030f0cf0a5cb372b4cccabd81c143b \
109 # via keyring
115 # via keyring
110 six==1.15.0 \
116 six==1.15.0 \
111 --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \
117 --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \
112 --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \
118 --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \
113 # via cryptography
119 # via cryptography
114 urllib3==1.25.10 \
120 urllib3==1.25.11 \
115 --hash=sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a \
121 --hash=sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2 \
116 --hash=sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461 \
122 --hash=sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e \
117 # via dulwich
123 # via dulwich
@@ -1,8 +1,9 b''
1 docutils
1 docutils
2 # Pinned to an old version because 0.20 drops Python 3 compatibility.
2 # Pinned to an old version because 0.20 drops Python 3 compatibility.
3 dulwich < 0.20
3 dulwich < 0.20 ; python_version <= '2.7'
4 dulwich ; python_version >= '3'
4 keyring
5 keyring
5 pygments
6 pygments
6 # Need to list explicitly so dependency gets pulled in when
7 # Need to list explicitly so dependency gets pulled in when
7 # not running on Windows.
8 # not running on Windows.
8 pywin32-ctypes
9 pywin32-ctypes
@@ -1,184 +1,184 b''
1 # demandimportpy3 - global demand-loading of modules for Mercurial
1 # demandimportpy3 - global demand-loading of modules for Mercurial
2 #
2 #
3 # Copyright 2017 Facebook Inc.
3 # Copyright 2017 Facebook Inc.
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 """Lazy loading for Python 3.6 and above.
8 """Lazy loading for Python 3.6 and above.
9
9
10 This uses the new importlib finder/loader functionality available in Python 3.5
10 This uses the new importlib finder/loader functionality available in Python 3.5
11 and up. The code reuses most of the mechanics implemented inside importlib.util,
11 and up. The code reuses most of the mechanics implemented inside importlib.util,
12 but with a few additions:
12 but with a few additions:
13
13
14 * Allow excluding certain modules from lazy imports.
14 * Allow excluding certain modules from lazy imports.
15 * Expose an interface that's substantially the same as demandimport for
15 * Expose an interface that's substantially the same as demandimport for
16 Python 2.
16 Python 2.
17
17
18 This also has some limitations compared to the Python 2 implementation:
18 This also has some limitations compared to the Python 2 implementation:
19
19
20 * Much of the logic is per-package, not per-module, so any packages loaded
20 * Much of the logic is per-package, not per-module, so any packages loaded
21 before demandimport is enabled will not be lazily imported in the future. In
21 before demandimport is enabled will not be lazily imported in the future. In
22 practice, we only expect builtins to be loaded before demandimport is
22 practice, we only expect builtins to be loaded before demandimport is
23 enabled.
23 enabled.
24 """
24 """
25
25
26 # This line is unnecessary, but it satisfies test-check-py3-compat.t.
26 # This line is unnecessary, but it satisfies test-check-py3-compat.t.
27 from __future__ import absolute_import
27 from __future__ import absolute_import
28
28
29 import contextlib
29 import contextlib
30 import importlib.util
30 import importlib.util
31 import sys
31 import sys
32
32
33 from . import tracing
33 from . import tracing
34
34
35 _deactivated = False
35 _deactivated = False
36
36
37 # Python 3.5's LazyLoader doesn't work for some reason.
37 # Python 3.5's LazyLoader doesn't work for some reason.
38 # https://bugs.python.org/issue26186 is a known issue with extension
38 # https://bugs.python.org/issue26186 is a known issue with extension
39 # importing. But it appears to not have a meaningful effect with
39 # importing. But it appears to not have a meaningful effect with
40 # Mercurial.
40 # Mercurial.
41 _supported = sys.version_info[0:2] >= (3, 6)
41 _supported = sys.version_info[0:2] >= (3, 6)
42
42
43
43
44 class _lazyloaderex(importlib.util.LazyLoader):
44 class _lazyloaderex(importlib.util.LazyLoader):
45 """This is a LazyLoader except it also follows the _deactivated global and
45 """This is a LazyLoader except it also follows the _deactivated global and
46 the ignore list.
46 the ignore list.
47 """
47 """
48
48
49 def exec_module(self, module):
49 def exec_module(self, module):
50 """Make the module load lazily."""
50 """Make the module load lazily."""
51 with tracing.log('demandimport %s', module):
51 with tracing.log('demandimport %s', module):
52 if _deactivated or module.__name__ in ignores:
52 if _deactivated or module.__name__ in ignores:
53 self.loader.exec_module(module)
53 self.loader.exec_module(module)
54 else:
54 else:
55 super().exec_module(module)
55 super().exec_module(module)
56
56
57
57
58 class LazyFinder(object):
58 class LazyFinder(object):
59 """A wrapper around a ``MetaPathFinder`` that makes loaders lazy.
59 """A wrapper around a ``MetaPathFinder`` that makes loaders lazy.
60
60
61 ``sys.meta_path`` finders have their ``find_spec()`` called to locate a
61 ``sys.meta_path`` finders have their ``find_spec()`` called to locate a
62 module. This returns a ``ModuleSpec`` if found or ``None``. The
62 module. This returns a ``ModuleSpec`` if found or ``None``. The
63 ``ModuleSpec`` has a ``loader`` attribute, which is called to actually
63 ``ModuleSpec`` has a ``loader`` attribute, which is called to actually
64 load a module.
64 load a module.
65
65
66 Our class wraps an existing finder and overloads its ``find_spec()`` to
66 Our class wraps an existing finder and overloads its ``find_spec()`` to
67 replace the ``loader`` with our lazy loader proxy.
67 replace the ``loader`` with our lazy loader proxy.
68
68
69 We have to use __getattribute__ to proxy the instance because some meta
69 We have to use __getattribute__ to proxy the instance because some meta
70 path finders don't support monkeypatching.
70 path finders don't support monkeypatching.
71 """
71 """
72
72
73 __slots__ = ("_finder",)
73 __slots__ = ("_finder",)
74
74
75 def __init__(self, finder):
75 def __init__(self, finder):
76 object.__setattr__(self, "_finder", finder)
76 object.__setattr__(self, "_finder", finder)
77
77
78 def __repr__(self):
78 def __repr__(self):
79 return "<LazyFinder for %r>" % object.__getattribute__(self, "_finder")
79 return "<LazyFinder for %r>" % object.__getattribute__(self, "_finder")
80
80
81 # __bool__ is canonical Python 3. But check-code insists on __nonzero__ being
81 # __bool__ is canonical Python 3. But check-code insists on __nonzero__ being
82 # defined via `def`.
82 # defined via `def`.
83 def __nonzero__(self):
83 def __nonzero__(self):
84 return bool(object.__getattribute__(self, "_finder"))
84 return bool(object.__getattribute__(self, "_finder"))
85
85
86 __bool__ = __nonzero__
86 __bool__ = __nonzero__
87
87
88 def __getattribute__(self, name):
88 def __getattribute__(self, name):
89 if name in ("_finder", "find_spec"):
89 if name in ("_finder", "find_spec"):
90 return object.__getattribute__(self, name)
90 return object.__getattribute__(self, name)
91
91
92 return getattr(object.__getattribute__(self, "_finder"), name)
92 return getattr(object.__getattribute__(self, "_finder"), name)
93
93
94 def __delattr__(self, name):
94 def __delattr__(self, name):
95 return delattr(object.__getattribute__(self, "_finder"))
95 return delattr(object.__getattribute__(self, "_finder"))
96
96
97 def __setattr__(self, name, value):
97 def __setattr__(self, name, value):
98 return setattr(object.__getattribute__(self, "_finder"), name, value)
98 return setattr(object.__getattribute__(self, "_finder"), name, value)
99
99
100 def find_spec(self, fullname, path, target=None):
100 def find_spec(self, fullname, path, target=None):
101 finder = object.__getattribute__(self, "_finder")
101 finder = object.__getattribute__(self, "_finder")
102 try:
102 try:
103 find_spec = finder.find_spec
103 find_spec = finder.find_spec
104 except AttributeError:
104 except AttributeError:
105 loader = finder.find_module(fullname, path)
105 loader = finder.find_module(fullname, path)
106 if loader is None:
106 if loader is None:
107 spec = None
107 spec = None
108 else:
108 else:
109 spec = importlib.util.spec_from_loader(fullname, loader)
109 spec = importlib.util.spec_from_loader(fullname, loader)
110 else:
110 else:
111 spec = find_spec(fullname, path, target)
111 spec = find_spec(fullname, path, target)
112
112
113 # Lazy loader requires exec_module().
113 # Lazy loader requires exec_module().
114 if (
114 if (
115 spec is not None
115 spec is not None
116 and spec.loader is not None
116 and spec.loader is not None
117 and getattr(spec.loader, "exec_module")
117 and getattr(spec.loader, "exec_module", None)
118 ):
118 ):
119 spec.loader = _lazyloaderex(spec.loader)
119 spec.loader = _lazyloaderex(spec.loader)
120
120
121 return spec
121 return spec
122
122
123
123
124 ignores = set()
124 ignores = set()
125
125
126
126
127 def init(ignoreset):
127 def init(ignoreset):
128 global ignores
128 global ignores
129 ignores = ignoreset
129 ignores = ignoreset
130
130
131
131
132 def isenabled():
132 def isenabled():
133 return not _deactivated and any(
133 return not _deactivated and any(
134 isinstance(finder, LazyFinder) for finder in sys.meta_path
134 isinstance(finder, LazyFinder) for finder in sys.meta_path
135 )
135 )
136
136
137
137
138 def disable():
138 def disable():
139 new_finders = []
139 new_finders = []
140 for finder in sys.meta_path:
140 for finder in sys.meta_path:
141 new_finders.append(
141 new_finders.append(
142 finder._finder if isinstance(finder, LazyFinder) else finder
142 finder._finder if isinstance(finder, LazyFinder) else finder
143 )
143 )
144 sys.meta_path[:] = new_finders
144 sys.meta_path[:] = new_finders
145
145
146
146
147 def enable():
147 def enable():
148 if not _supported:
148 if not _supported:
149 return
149 return
150
150
151 new_finders = []
151 new_finders = []
152 for finder in sys.meta_path:
152 for finder in sys.meta_path:
153 new_finders.append(
153 new_finders.append(
154 LazyFinder(finder) if not isinstance(finder, LazyFinder) else finder
154 LazyFinder(finder) if not isinstance(finder, LazyFinder) else finder
155 )
155 )
156 sys.meta_path[:] = new_finders
156 sys.meta_path[:] = new_finders
157
157
158
158
159 @contextlib.contextmanager
159 @contextlib.contextmanager
160 def deactivated():
160 def deactivated():
161 # This implementation is a bit different from Python 2's. Python 3
161 # This implementation is a bit different from Python 2's. Python 3
162 # maintains a per-package finder cache in sys.path_importer_cache (see
162 # maintains a per-package finder cache in sys.path_importer_cache (see
163 # PEP 302). This means that we can't just call disable + enable.
163 # PEP 302). This means that we can't just call disable + enable.
164 # If we do that, in situations like:
164 # If we do that, in situations like:
165 #
165 #
166 # demandimport.enable()
166 # demandimport.enable()
167 # ...
167 # ...
168 # from foo.bar import mod1
168 # from foo.bar import mod1
169 # with demandimport.deactivated():
169 # with demandimport.deactivated():
170 # from foo.bar import mod2
170 # from foo.bar import mod2
171 #
171 #
172 # mod2 will be imported lazily. (The converse also holds -- whatever finder
172 # mod2 will be imported lazily. (The converse also holds -- whatever finder
173 # first gets cached will be used.)
173 # first gets cached will be used.)
174 #
174 #
175 # Instead, have a global flag the LazyLoader can use.
175 # Instead, have a global flag the LazyLoader can use.
176 global _deactivated
176 global _deactivated
177 demandenabled = isenabled()
177 demandenabled = isenabled()
178 if demandenabled:
178 if demandenabled:
179 _deactivated = True
179 _deactivated = True
180 try:
180 try:
181 yield
181 yield
182 finally:
182 finally:
183 if demandenabled:
183 if demandenabled:
184 _deactivated = False
184 _deactivated = False
@@ -1,2793 +1,2796 b''
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 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 re
10 import re
11
11
12 from .i18n import _
12 from .i18n import _
13 from .pycompat import getattr
13 from .pycompat import getattr
14 from . import (
14 from . import (
15 dagop,
15 dagop,
16 destutil,
16 destutil,
17 diffutil,
17 diffutil,
18 encoding,
18 encoding,
19 error,
19 error,
20 grep as grepmod,
20 grep as grepmod,
21 hbisect,
21 hbisect,
22 match as matchmod,
22 match as matchmod,
23 node,
23 node,
24 obsolete as obsmod,
24 obsolete as obsmod,
25 obsutil,
25 obsutil,
26 pathutil,
26 pathutil,
27 phases,
27 phases,
28 pycompat,
28 pycompat,
29 registrar,
29 registrar,
30 repoview,
30 repoview,
31 revsetlang,
31 revsetlang,
32 scmutil,
32 scmutil,
33 smartset,
33 smartset,
34 stack as stackmod,
34 stack as stackmod,
35 util,
35 util,
36 )
36 )
37 from .utils import (
37 from .utils import (
38 dateutil,
38 dateutil,
39 stringutil,
39 stringutil,
40 )
40 )
41
41
42 # helpers for processing parsed tree
42 # helpers for processing parsed tree
43 getsymbol = revsetlang.getsymbol
43 getsymbol = revsetlang.getsymbol
44 getstring = revsetlang.getstring
44 getstring = revsetlang.getstring
45 getinteger = revsetlang.getinteger
45 getinteger = revsetlang.getinteger
46 getboolean = revsetlang.getboolean
46 getboolean = revsetlang.getboolean
47 getlist = revsetlang.getlist
47 getlist = revsetlang.getlist
48 getintrange = revsetlang.getintrange
48 getintrange = revsetlang.getintrange
49 getargs = revsetlang.getargs
49 getargs = revsetlang.getargs
50 getargsdict = revsetlang.getargsdict
50 getargsdict = revsetlang.getargsdict
51
51
52 baseset = smartset.baseset
52 baseset = smartset.baseset
53 generatorset = smartset.generatorset
53 generatorset = smartset.generatorset
54 spanset = smartset.spanset
54 spanset = smartset.spanset
55 fullreposet = smartset.fullreposet
55 fullreposet = smartset.fullreposet
56
56
57 # revisions not included in all(), but populated if specified
57 # revisions not included in all(), but populated if specified
58 _virtualrevs = (node.nullrev, node.wdirrev)
58 _virtualrevs = (node.nullrev, node.wdirrev)
59
59
60 # Constants for ordering requirement, used in getset():
60 # Constants for ordering requirement, used in getset():
61 #
61 #
62 # If 'define', any nested functions and operations MAY change the ordering of
62 # If 'define', any nested functions and operations MAY change the ordering of
63 # the entries in the set (but if changes the ordering, it MUST ALWAYS change
63 # the entries in the set (but if changes the ordering, it MUST ALWAYS change
64 # it). If 'follow', any nested functions and operations MUST take the ordering
64 # it). If 'follow', any nested functions and operations MUST take the ordering
65 # specified by the first operand to the '&' operator.
65 # specified by the first operand to the '&' operator.
66 #
66 #
67 # For instance,
67 # For instance,
68 #
68 #
69 # X & (Y | Z)
69 # X & (Y | Z)
70 # ^ ^^^^^^^
70 # ^ ^^^^^^^
71 # | follow
71 # | follow
72 # define
72 # define
73 #
73 #
74 # will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order
74 # will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order
75 # of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't.
75 # of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't.
76 #
76 #
77 # 'any' means the order doesn't matter. For instance,
77 # 'any' means the order doesn't matter. For instance,
78 #
78 #
79 # (X & !Y) | ancestors(Z)
79 # (X & !Y) | ancestors(Z)
80 # ^ ^
80 # ^ ^
81 # any any
81 # any any
82 #
82 #
83 # For 'X & !Y', 'X' decides the order and 'Y' is subtracted from 'X', so the
83 # For 'X & !Y', 'X' decides the order and 'Y' is subtracted from 'X', so the
84 # order of 'Y' does not matter. For 'ancestors(Z)', Z's order does not matter
84 # order of 'Y' does not matter. For 'ancestors(Z)', Z's order does not matter
85 # since 'ancestors' does not care about the order of its argument.
85 # since 'ancestors' does not care about the order of its argument.
86 #
86 #
87 # Currently, most revsets do not care about the order, so 'define' is
87 # Currently, most revsets do not care about the order, so 'define' is
88 # equivalent to 'follow' for them, and the resulting order is based on the
88 # equivalent to 'follow' for them, and the resulting order is based on the
89 # 'subset' parameter passed down to them:
89 # 'subset' parameter passed down to them:
90 #
90 #
91 # m = revset.match(...)
91 # m = revset.match(...)
92 # m(repo, subset, order=defineorder)
92 # m(repo, subset, order=defineorder)
93 # ^^^^^^
93 # ^^^^^^
94 # For most revsets, 'define' means using the order this subset provides
94 # For most revsets, 'define' means using the order this subset provides
95 #
95 #
96 # There are a few revsets that always redefine the order if 'define' is
96 # There are a few revsets that always redefine the order if 'define' is
97 # specified: 'sort(X)', 'reverse(X)', 'x:y'.
97 # specified: 'sort(X)', 'reverse(X)', 'x:y'.
98 anyorder = b'any' # don't care the order, could be even random-shuffled
98 anyorder = b'any' # don't care the order, could be even random-shuffled
99 defineorder = b'define' # ALWAYS redefine, or ALWAYS follow the current order
99 defineorder = b'define' # ALWAYS redefine, or ALWAYS follow the current order
100 followorder = b'follow' # MUST follow the current order
100 followorder = b'follow' # MUST follow the current order
101
101
102 # helpers
102 # helpers
103
103
104
104
105 def getset(repo, subset, x, order=defineorder):
105 def getset(repo, subset, x, order=defineorder):
106 if not x:
106 if not x:
107 raise error.ParseError(_(b"missing argument"))
107 raise error.ParseError(_(b"missing argument"))
108 return methods[x[0]](repo, subset, *x[1:], order=order)
108 return methods[x[0]](repo, subset, *x[1:], order=order)
109
109
110
110
111 def _getrevsource(repo, r):
111 def _getrevsource(repo, r):
112 extra = repo[r].extra()
112 extra = repo[r].extra()
113 for label in (b'source', b'transplant_source', b'rebase_source'):
113 for label in (b'source', b'transplant_source', b'rebase_source'):
114 if label in extra:
114 if label in extra:
115 try:
115 try:
116 return repo[extra[label]].rev()
116 return repo[extra[label]].rev()
117 except error.RepoLookupError:
117 except error.RepoLookupError:
118 pass
118 pass
119 return None
119 return None
120
120
121
121
122 def _sortedb(xs):
122 def _sortedb(xs):
123 return sorted(pycompat.rapply(pycompat.maybebytestr, xs))
123 return sorted(pycompat.rapply(pycompat.maybebytestr, xs))
124
124
125
125
126 # operator methods
126 # operator methods
127
127
128
128
129 def stringset(repo, subset, x, order):
129 def stringset(repo, subset, x, order):
130 if not x:
130 if not x:
131 raise error.ParseError(_(b"empty string is not a valid revision"))
131 raise error.ParseError(_(b"empty string is not a valid revision"))
132 x = scmutil.intrev(scmutil.revsymbol(repo, x))
132 x = scmutil.intrev(scmutil.revsymbol(repo, x))
133 if x in subset or x in _virtualrevs and isinstance(subset, fullreposet):
133 if x in subset or x in _virtualrevs and isinstance(subset, fullreposet):
134 return baseset([x])
134 return baseset([x])
135 return baseset()
135 return baseset()
136
136
137
137
138 def rawsmartset(repo, subset, x, order):
138 def rawsmartset(repo, subset, x, order):
139 """argument is already a smartset, use that directly"""
139 """argument is already a smartset, use that directly"""
140 if order == followorder:
140 if order == followorder:
141 return subset & x
141 return subset & x
142 else:
142 else:
143 return x & subset
143 return x & subset
144
144
145
145
146 def rangeset(repo, subset, x, y, order):
146 def rangeset(repo, subset, x, y, order):
147 m = getset(repo, fullreposet(repo), x)
147 m = getset(repo, fullreposet(repo), x)
148 n = getset(repo, fullreposet(repo), y)
148 n = getset(repo, fullreposet(repo), y)
149
149
150 if not m or not n:
150 if not m or not n:
151 return baseset()
151 return baseset()
152 return _makerangeset(repo, subset, m.first(), n.last(), order)
152 return _makerangeset(repo, subset, m.first(), n.last(), order)
153
153
154
154
155 def rangeall(repo, subset, x, order):
155 def rangeall(repo, subset, x, order):
156 assert x is None
156 assert x is None
157 return _makerangeset(repo, subset, 0, repo.changelog.tiprev(), order)
157 return _makerangeset(repo, subset, 0, repo.changelog.tiprev(), order)
158
158
159
159
160 def rangepre(repo, subset, y, order):
160 def rangepre(repo, subset, y, order):
161 # ':y' can't be rewritten to '0:y' since '0' may be hidden
161 # ':y' can't be rewritten to '0:y' since '0' may be hidden
162 n = getset(repo, fullreposet(repo), y)
162 n = getset(repo, fullreposet(repo), y)
163 if not n:
163 if not n:
164 return baseset()
164 return baseset()
165 return _makerangeset(repo, subset, 0, n.last(), order)
165 return _makerangeset(repo, subset, 0, n.last(), order)
166
166
167
167
168 def rangepost(repo, subset, x, order):
168 def rangepost(repo, subset, x, order):
169 m = getset(repo, fullreposet(repo), x)
169 m = getset(repo, fullreposet(repo), x)
170 if not m:
170 if not m:
171 return baseset()
171 return baseset()
172 return _makerangeset(
172 return _makerangeset(
173 repo, subset, m.first(), repo.changelog.tiprev(), order
173 repo, subset, m.first(), repo.changelog.tiprev(), order
174 )
174 )
175
175
176
176
177 def _makerangeset(repo, subset, m, n, order):
177 def _makerangeset(repo, subset, m, n, order):
178 if m == n:
178 if m == n:
179 r = baseset([m])
179 r = baseset([m])
180 elif n == node.wdirrev:
180 elif n == node.wdirrev:
181 r = spanset(repo, m, len(repo)) + baseset([n])
181 r = spanset(repo, m, len(repo)) + baseset([n])
182 elif m == node.wdirrev:
182 elif m == node.wdirrev:
183 r = baseset([m]) + spanset(repo, repo.changelog.tiprev(), n - 1)
183 r = baseset([m]) + spanset(repo, repo.changelog.tiprev(), n - 1)
184 elif m < n:
184 elif m < n:
185 r = spanset(repo, m, n + 1)
185 r = spanset(repo, m, n + 1)
186 else:
186 else:
187 r = spanset(repo, m, n - 1)
187 r = spanset(repo, m, n - 1)
188
188
189 if order == defineorder:
189 if order == defineorder:
190 return r & subset
190 return r & subset
191 else:
191 else:
192 # carrying the sorting over when possible would be more efficient
192 # carrying the sorting over when possible would be more efficient
193 return subset & r
193 return subset & r
194
194
195
195
196 def dagrange(repo, subset, x, y, order):
196 def dagrange(repo, subset, x, y, order):
197 r = fullreposet(repo)
197 r = fullreposet(repo)
198 xs = dagop.reachableroots(
198 xs = dagop.reachableroots(
199 repo, getset(repo, r, x), getset(repo, r, y), includepath=True
199 repo, getset(repo, r, x), getset(repo, r, y), includepath=True
200 )
200 )
201 return subset & xs
201 return subset & xs
202
202
203
203
204 def andset(repo, subset, x, y, order):
204 def andset(repo, subset, x, y, order):
205 if order == anyorder:
205 if order == anyorder:
206 yorder = anyorder
206 yorder = anyorder
207 else:
207 else:
208 yorder = followorder
208 yorder = followorder
209 return getset(repo, getset(repo, subset, x, order), y, yorder)
209 return getset(repo, getset(repo, subset, x, order), y, yorder)
210
210
211
211
212 def andsmallyset(repo, subset, x, y, order):
212 def andsmallyset(repo, subset, x, y, order):
213 # 'andsmally(x, y)' is equivalent to 'and(x, y)', but faster when y is small
213 # 'andsmally(x, y)' is equivalent to 'and(x, y)', but faster when y is small
214 if order == anyorder:
214 if order == anyorder:
215 yorder = anyorder
215 yorder = anyorder
216 else:
216 else:
217 yorder = followorder
217 yorder = followorder
218 return getset(repo, getset(repo, subset, y, yorder), x, order)
218 return getset(repo, getset(repo, subset, y, yorder), x, order)
219
219
220
220
221 def differenceset(repo, subset, x, y, order):
221 def differenceset(repo, subset, x, y, order):
222 return getset(repo, subset, x, order) - getset(repo, subset, y, anyorder)
222 return getset(repo, subset, x, order) - getset(repo, subset, y, anyorder)
223
223
224
224
225 def _orsetlist(repo, subset, xs, order):
225 def _orsetlist(repo, subset, xs, order):
226 assert xs
226 assert xs
227 if len(xs) == 1:
227 if len(xs) == 1:
228 return getset(repo, subset, xs[0], order)
228 return getset(repo, subset, xs[0], order)
229 p = len(xs) // 2
229 p = len(xs) // 2
230 a = _orsetlist(repo, subset, xs[:p], order)
230 a = _orsetlist(repo, subset, xs[:p], order)
231 b = _orsetlist(repo, subset, xs[p:], order)
231 b = _orsetlist(repo, subset, xs[p:], order)
232 return a + b
232 return a + b
233
233
234
234
235 def orset(repo, subset, x, order):
235 def orset(repo, subset, x, order):
236 xs = getlist(x)
236 xs = getlist(x)
237 if not xs:
237 if not xs:
238 return baseset()
238 return baseset()
239 if order == followorder:
239 if order == followorder:
240 # slow path to take the subset order
240 # slow path to take the subset order
241 return subset & _orsetlist(repo, fullreposet(repo), xs, anyorder)
241 return subset & _orsetlist(repo, fullreposet(repo), xs, anyorder)
242 else:
242 else:
243 return _orsetlist(repo, subset, xs, order)
243 return _orsetlist(repo, subset, xs, order)
244
244
245
245
246 def notset(repo, subset, x, order):
246 def notset(repo, subset, x, order):
247 return subset - getset(repo, subset, x, anyorder)
247 return subset - getset(repo, subset, x, anyorder)
248
248
249
249
250 def relationset(repo, subset, x, y, order):
250 def relationset(repo, subset, x, y, order):
251 # this is pretty basic implementation of 'x#y' operator, still
251 # this is pretty basic implementation of 'x#y' operator, still
252 # experimental so undocumented. see the wiki for further ideas.
252 # experimental so undocumented. see the wiki for further ideas.
253 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
253 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
254 rel = getsymbol(y)
254 rel = getsymbol(y)
255 if rel in relations:
255 if rel in relations:
256 return relations[rel](repo, subset, x, rel, order)
256 return relations[rel](repo, subset, x, rel, order)
257
257
258 relnames = [r for r in relations.keys() if len(r) > 1]
258 relnames = [r for r in relations.keys() if len(r) > 1]
259 raise error.UnknownIdentifier(rel, relnames)
259 raise error.UnknownIdentifier(rel, relnames)
260
260
261
261
262 def _splitrange(a, b):
262 def _splitrange(a, b):
263 """Split range with bounds a and b into two ranges at 0 and return two
263 """Split range with bounds a and b into two ranges at 0 and return two
264 tuples of numbers for use as startdepth and stopdepth arguments of
264 tuples of numbers for use as startdepth and stopdepth arguments of
265 revancestors and revdescendants.
265 revancestors and revdescendants.
266
266
267 >>> _splitrange(-10, -5) # [-10:-5]
267 >>> _splitrange(-10, -5) # [-10:-5]
268 ((5, 11), (None, None))
268 ((5, 11), (None, None))
269 >>> _splitrange(5, 10) # [5:10]
269 >>> _splitrange(5, 10) # [5:10]
270 ((None, None), (5, 11))
270 ((None, None), (5, 11))
271 >>> _splitrange(-10, 10) # [-10:10]
271 >>> _splitrange(-10, 10) # [-10:10]
272 ((0, 11), (0, 11))
272 ((0, 11), (0, 11))
273 >>> _splitrange(-10, 0) # [-10:0]
273 >>> _splitrange(-10, 0) # [-10:0]
274 ((0, 11), (None, None))
274 ((0, 11), (None, None))
275 >>> _splitrange(0, 10) # [0:10]
275 >>> _splitrange(0, 10) # [0:10]
276 ((None, None), (0, 11))
276 ((None, None), (0, 11))
277 >>> _splitrange(0, 0) # [0:0]
277 >>> _splitrange(0, 0) # [0:0]
278 ((0, 1), (None, None))
278 ((0, 1), (None, None))
279 >>> _splitrange(1, -1) # [1:-1]
279 >>> _splitrange(1, -1) # [1:-1]
280 ((None, None), (None, None))
280 ((None, None), (None, None))
281 """
281 """
282 ancdepths = (None, None)
282 ancdepths = (None, None)
283 descdepths = (None, None)
283 descdepths = (None, None)
284 if a == b == 0:
284 if a == b == 0:
285 ancdepths = (0, 1)
285 ancdepths = (0, 1)
286 if a < 0:
286 if a < 0:
287 ancdepths = (-min(b, 0), -a + 1)
287 ancdepths = (-min(b, 0), -a + 1)
288 if b > 0:
288 if b > 0:
289 descdepths = (max(a, 0), b + 1)
289 descdepths = (max(a, 0), b + 1)
290 return ancdepths, descdepths
290 return ancdepths, descdepths
291
291
292
292
293 def generationsrel(repo, subset, x, rel, order):
293 def generationsrel(repo, subset, x, rel, order):
294 z = (b'rangeall', None)
294 z = (b'rangeall', None)
295 return generationssubrel(repo, subset, x, rel, z, order)
295 return generationssubrel(repo, subset, x, rel, z, order)
296
296
297
297
298 def generationssubrel(repo, subset, x, rel, z, order):
298 def generationssubrel(repo, subset, x, rel, z, order):
299 # TODO: rewrite tests, and drop startdepth argument from ancestors() and
299 # TODO: rewrite tests, and drop startdepth argument from ancestors() and
300 # descendants() predicates
300 # descendants() predicates
301 a, b = getintrange(
301 a, b = getintrange(
302 z,
302 z,
303 _(b'relation subscript must be an integer or a range'),
303 _(b'relation subscript must be an integer or a range'),
304 _(b'relation subscript bounds must be integers'),
304 _(b'relation subscript bounds must be integers'),
305 deffirst=-(dagop.maxlogdepth - 1),
305 deffirst=-(dagop.maxlogdepth - 1),
306 deflast=+(dagop.maxlogdepth - 1),
306 deflast=+(dagop.maxlogdepth - 1),
307 )
307 )
308 (ancstart, ancstop), (descstart, descstop) = _splitrange(a, b)
308 (ancstart, ancstop), (descstart, descstop) = _splitrange(a, b)
309
309
310 if ancstart is None and descstart is None:
310 if ancstart is None and descstart is None:
311 return baseset()
311 return baseset()
312
312
313 revs = getset(repo, fullreposet(repo), x)
313 revs = getset(repo, fullreposet(repo), x)
314 if not revs:
314 if not revs:
315 return baseset()
315 return baseset()
316
316
317 if ancstart is not None and descstart is not None:
317 if ancstart is not None and descstart is not None:
318 s = dagop.revancestors(repo, revs, False, ancstart, ancstop)
318 s = dagop.revancestors(repo, revs, False, ancstart, ancstop)
319 s += dagop.revdescendants(repo, revs, False, descstart, descstop)
319 s += dagop.revdescendants(repo, revs, False, descstart, descstop)
320 elif ancstart is not None:
320 elif ancstart is not None:
321 s = dagop.revancestors(repo, revs, False, ancstart, ancstop)
321 s = dagop.revancestors(repo, revs, False, ancstart, ancstop)
322 elif descstart is not None:
322 elif descstart is not None:
323 s = dagop.revdescendants(repo, revs, False, descstart, descstop)
323 s = dagop.revdescendants(repo, revs, False, descstart, descstop)
324
324
325 return subset & s
325 return subset & s
326
326
327
327
328 def relsubscriptset(repo, subset, x, y, z, order):
328 def relsubscriptset(repo, subset, x, y, z, order):
329 # this is pretty basic implementation of 'x#y[z]' operator, still
329 # this is pretty basic implementation of 'x#y[z]' operator, still
330 # experimental so undocumented. see the wiki for further ideas.
330 # experimental so undocumented. see the wiki for further ideas.
331 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
331 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
332 rel = getsymbol(y)
332 rel = getsymbol(y)
333 if rel in subscriptrelations:
333 if rel in subscriptrelations:
334 return subscriptrelations[rel](repo, subset, x, rel, z, order)
334 return subscriptrelations[rel](repo, subset, x, rel, z, order)
335
335
336 relnames = [r for r in subscriptrelations.keys() if len(r) > 1]
336 relnames = [r for r in subscriptrelations.keys() if len(r) > 1]
337 raise error.UnknownIdentifier(rel, relnames)
337 raise error.UnknownIdentifier(rel, relnames)
338
338
339
339
340 def subscriptset(repo, subset, x, y, order):
340 def subscriptset(repo, subset, x, y, order):
341 raise error.ParseError(_(b"can't use a subscript in this context"))
341 raise error.ParseError(_(b"can't use a subscript in this context"))
342
342
343
343
344 def listset(repo, subset, *xs, **opts):
344 def listset(repo, subset, *xs, **opts):
345 raise error.ParseError(
345 raise error.ParseError(
346 _(b"can't use a list in this context"),
346 _(b"can't use a list in this context"),
347 hint=_(b'see \'hg help "revsets.x or y"\''),
347 hint=_(b'see \'hg help "revsets.x or y"\''),
348 )
348 )
349
349
350
350
351 def keyvaluepair(repo, subset, k, v, order):
351 def keyvaluepair(repo, subset, k, v, order):
352 raise error.ParseError(_(b"can't use a key-value pair in this context"))
352 raise error.ParseError(_(b"can't use a key-value pair in this context"))
353
353
354
354
355 def func(repo, subset, a, b, order):
355 def func(repo, subset, a, b, order):
356 f = getsymbol(a)
356 f = getsymbol(a)
357 if f in symbols:
357 if f in symbols:
358 func = symbols[f]
358 func = symbols[f]
359 if getattr(func, '_takeorder', False):
359 if getattr(func, '_takeorder', False):
360 return func(repo, subset, b, order)
360 return func(repo, subset, b, order)
361 return func(repo, subset, b)
361 return func(repo, subset, b)
362
362
363 keep = lambda fn: getattr(fn, '__doc__', None) is not None
363 keep = lambda fn: getattr(fn, '__doc__', None) is not None
364
364
365 syms = [s for (s, fn) in symbols.items() if keep(fn)]
365 syms = [s for (s, fn) in symbols.items() if keep(fn)]
366 raise error.UnknownIdentifier(f, syms)
366 raise error.UnknownIdentifier(f, syms)
367
367
368
368
369 # functions
369 # functions
370
370
371 # symbols are callables like:
371 # symbols are callables like:
372 # fn(repo, subset, x)
372 # fn(repo, subset, x)
373 # with:
373 # with:
374 # repo - current repository instance
374 # repo - current repository instance
375 # subset - of revisions to be examined
375 # subset - of revisions to be examined
376 # x - argument in tree form
376 # x - argument in tree form
377 symbols = revsetlang.symbols
377 symbols = revsetlang.symbols
378
378
379 # symbols which can't be used for a DoS attack for any given input
379 # symbols which can't be used for a DoS attack for any given input
380 # (e.g. those which accept regexes as plain strings shouldn't be included)
380 # (e.g. those which accept regexes as plain strings shouldn't be included)
381 # functions that just return a lot of changesets (like all) don't count here
381 # functions that just return a lot of changesets (like all) don't count here
382 safesymbols = set()
382 safesymbols = set()
383
383
384 predicate = registrar.revsetpredicate()
384 predicate = registrar.revsetpredicate()
385
385
386
386
387 @predicate(b'_destupdate')
387 @predicate(b'_destupdate')
388 def _destupdate(repo, subset, x):
388 def _destupdate(repo, subset, x):
389 # experimental revset for update destination
389 # experimental revset for update destination
390 args = getargsdict(x, b'limit', b'clean')
390 args = getargsdict(x, b'limit', b'clean')
391 return subset & baseset(
391 return subset & baseset(
392 [destutil.destupdate(repo, **pycompat.strkwargs(args))[0]]
392 [destutil.destupdate(repo, **pycompat.strkwargs(args))[0]]
393 )
393 )
394
394
395
395
396 @predicate(b'_destmerge')
396 @predicate(b'_destmerge')
397 def _destmerge(repo, subset, x):
397 def _destmerge(repo, subset, x):
398 # experimental revset for merge destination
398 # experimental revset for merge destination
399 sourceset = None
399 sourceset = None
400 if x is not None:
400 if x is not None:
401 sourceset = getset(repo, fullreposet(repo), x)
401 sourceset = getset(repo, fullreposet(repo), x)
402 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
402 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
403
403
404
404
405 @predicate(b'adds(pattern)', safe=True, weight=30)
405 @predicate(b'adds(pattern)', safe=True, weight=30)
406 def adds(repo, subset, x):
406 def adds(repo, subset, x):
407 """Changesets that add a file matching pattern.
407 """Changesets that add a file matching pattern.
408
408
409 The pattern without explicit kind like ``glob:`` is expected to be
409 The pattern without explicit kind like ``glob:`` is expected to be
410 relative to the current directory and match against a file or a
410 relative to the current directory and match against a file or a
411 directory.
411 directory.
412 """
412 """
413 # i18n: "adds" is a keyword
413 # i18n: "adds" is a keyword
414 pat = getstring(x, _(b"adds requires a pattern"))
414 pat = getstring(x, _(b"adds requires a pattern"))
415 return checkstatus(repo, subset, pat, 'added')
415 return checkstatus(repo, subset, pat, 'added')
416
416
417
417
418 @predicate(b'ancestor(*changeset)', safe=True, weight=0.5)
418 @predicate(b'ancestor(*changeset)', safe=True, weight=0.5)
419 def ancestor(repo, subset, x):
419 def ancestor(repo, subset, x):
420 """A greatest common ancestor of the changesets.
420 """A greatest common ancestor of the changesets.
421
421
422 Accepts 0 or more changesets.
422 Accepts 0 or more changesets.
423 Will return empty list when passed no args.
423 Will return empty list when passed no args.
424 Greatest common ancestor of a single changeset is that changeset.
424 Greatest common ancestor of a single changeset is that changeset.
425 """
425 """
426 reviter = iter(orset(repo, fullreposet(repo), x, order=anyorder))
426 reviter = iter(orset(repo, fullreposet(repo), x, order=anyorder))
427 try:
427 try:
428 anc = repo[next(reviter)]
428 anc = repo[next(reviter)]
429 except StopIteration:
429 except StopIteration:
430 return baseset()
430 return baseset()
431 for r in reviter:
431 for r in reviter:
432 anc = anc.ancestor(repo[r])
432 anc = anc.ancestor(repo[r])
433
433
434 r = scmutil.intrev(anc)
434 r = scmutil.intrev(anc)
435 if r in subset:
435 if r in subset:
436 return baseset([r])
436 return baseset([r])
437 return baseset()
437 return baseset()
438
438
439
439
440 def _ancestors(
440 def _ancestors(
441 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None
441 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None
442 ):
442 ):
443 heads = getset(repo, fullreposet(repo), x)
443 heads = getset(repo, fullreposet(repo), x)
444 if not heads:
444 if not heads:
445 return baseset()
445 return baseset()
446 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth)
446 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth)
447 return subset & s
447 return subset & s
448
448
449
449
450 @predicate(b'ancestors(set[, depth])', safe=True)
450 @predicate(b'ancestors(set[, depth])', safe=True)
451 def ancestors(repo, subset, x):
451 def ancestors(repo, subset, x):
452 """Changesets that are ancestors of changesets in set, including the
452 """Changesets that are ancestors of changesets in set, including the
453 given changesets themselves.
453 given changesets themselves.
454
454
455 If depth is specified, the result only includes changesets up to
455 If depth is specified, the result only includes changesets up to
456 the specified generation.
456 the specified generation.
457 """
457 """
458 # startdepth is for internal use only until we can decide the UI
458 # startdepth is for internal use only until we can decide the UI
459 args = getargsdict(x, b'ancestors', b'set depth startdepth')
459 args = getargsdict(x, b'ancestors', b'set depth startdepth')
460 if b'set' not in args:
460 if b'set' not in args:
461 # i18n: "ancestors" is a keyword
461 # i18n: "ancestors" is a keyword
462 raise error.ParseError(_(b'ancestors takes at least 1 argument'))
462 raise error.ParseError(_(b'ancestors takes at least 1 argument'))
463 startdepth = stopdepth = None
463 startdepth = stopdepth = None
464 if b'startdepth' in args:
464 if b'startdepth' in args:
465 n = getinteger(
465 n = getinteger(
466 args[b'startdepth'], b"ancestors expects an integer startdepth"
466 args[b'startdepth'], b"ancestors expects an integer startdepth"
467 )
467 )
468 if n < 0:
468 if n < 0:
469 raise error.ParseError(b"negative startdepth")
469 raise error.ParseError(b"negative startdepth")
470 startdepth = n
470 startdepth = n
471 if b'depth' in args:
471 if b'depth' in args:
472 # i18n: "ancestors" is a keyword
472 # i18n: "ancestors" is a keyword
473 n = getinteger(args[b'depth'], _(b"ancestors expects an integer depth"))
473 n = getinteger(args[b'depth'], _(b"ancestors expects an integer depth"))
474 if n < 0:
474 if n < 0:
475 raise error.ParseError(_(b"negative depth"))
475 raise error.ParseError(_(b"negative depth"))
476 stopdepth = n + 1
476 stopdepth = n + 1
477 return _ancestors(
477 return _ancestors(
478 repo, subset, args[b'set'], startdepth=startdepth, stopdepth=stopdepth
478 repo, subset, args[b'set'], startdepth=startdepth, stopdepth=stopdepth
479 )
479 )
480
480
481
481
482 @predicate(b'_firstancestors', safe=True)
482 @predicate(b'_firstancestors', safe=True)
483 def _firstancestors(repo, subset, x):
483 def _firstancestors(repo, subset, x):
484 # ``_firstancestors(set)``
484 # ``_firstancestors(set)``
485 # Like ``ancestors(set)`` but follows only the first parents.
485 # Like ``ancestors(set)`` but follows only the first parents.
486 return _ancestors(repo, subset, x, followfirst=True)
486 return _ancestors(repo, subset, x, followfirst=True)
487
487
488
488
489 def _childrenspec(repo, subset, x, n, order):
489 def _childrenspec(repo, subset, x, n, order):
490 """Changesets that are the Nth child of a changeset
490 """Changesets that are the Nth child of a changeset
491 in set.
491 in set.
492 """
492 """
493 cs = set()
493 cs = set()
494 for r in getset(repo, fullreposet(repo), x):
494 for r in getset(repo, fullreposet(repo), x):
495 for i in range(n):
495 for i in range(n):
496 c = repo[r].children()
496 c = repo[r].children()
497 if len(c) == 0:
497 if len(c) == 0:
498 break
498 break
499 if len(c) > 1:
499 if len(c) > 1:
500 raise error.RepoLookupError(
500 raise error.RepoLookupError(
501 _(b"revision in set has more than one child")
501 _(b"revision in set has more than one child")
502 )
502 )
503 r = c[0].rev()
503 r = c[0].rev()
504 else:
504 else:
505 cs.add(r)
505 cs.add(r)
506 return subset & cs
506 return subset & cs
507
507
508
508
509 def ancestorspec(repo, subset, x, n, order):
509 def ancestorspec(repo, subset, x, n, order):
510 """``set~n``
510 """``set~n``
511 Changesets that are the Nth ancestor (first parents only) of a changeset
511 Changesets that are the Nth ancestor (first parents only) of a changeset
512 in set.
512 in set.
513 """
513 """
514 n = getinteger(n, _(b"~ expects a number"))
514 n = getinteger(n, _(b"~ expects a number"))
515 if n < 0:
515 if n < 0:
516 # children lookup
516 # children lookup
517 return _childrenspec(repo, subset, x, -n, order)
517 return _childrenspec(repo, subset, x, -n, order)
518 ps = set()
518 ps = set()
519 cl = repo.changelog
519 cl = repo.changelog
520 for r in getset(repo, fullreposet(repo), x):
520 for r in getset(repo, fullreposet(repo), x):
521 for i in range(n):
521 for i in range(n):
522 try:
522 try:
523 r = cl.parentrevs(r)[0]
523 r = cl.parentrevs(r)[0]
524 except error.WdirUnsupported:
524 except error.WdirUnsupported:
525 r = repo[r].p1().rev()
525 r = repo[r].p1().rev()
526 ps.add(r)
526 ps.add(r)
527 return subset & ps
527 return subset & ps
528
528
529
529
530 @predicate(b'author(string)', safe=True, weight=10)
530 @predicate(b'author(string)', safe=True, weight=10)
531 def author(repo, subset, x):
531 def author(repo, subset, x):
532 """Alias for ``user(string)``.
532 """Alias for ``user(string)``.
533 """
533 """
534 # i18n: "author" is a keyword
534 # i18n: "author" is a keyword
535 n = getstring(x, _(b"author requires a string"))
535 n = getstring(x, _(b"author requires a string"))
536 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
536 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
537 return subset.filter(
537 return subset.filter(
538 lambda x: matcher(repo[x].user()), condrepr=(b'<user %r>', n)
538 lambda x: matcher(repo[x].user()), condrepr=(b'<user %r>', n)
539 )
539 )
540
540
541
541
542 @predicate(b'bisect(string)', safe=True)
542 @predicate(b'bisect(string)', safe=True)
543 def bisect(repo, subset, x):
543 def bisect(repo, subset, x):
544 """Changesets marked in the specified bisect status:
544 """Changesets marked in the specified bisect status:
545
545
546 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
546 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
547 - ``goods``, ``bads`` : csets topologically good/bad
547 - ``goods``, ``bads`` : csets topologically good/bad
548 - ``range`` : csets taking part in the bisection
548 - ``range`` : csets taking part in the bisection
549 - ``pruned`` : csets that are goods, bads or skipped
549 - ``pruned`` : csets that are goods, bads or skipped
550 - ``untested`` : csets whose fate is yet unknown
550 - ``untested`` : csets whose fate is yet unknown
551 - ``ignored`` : csets ignored due to DAG topology
551 - ``ignored`` : csets ignored due to DAG topology
552 - ``current`` : the cset currently being bisected
552 - ``current`` : the cset currently being bisected
553 """
553 """
554 # i18n: "bisect" is a keyword
554 # i18n: "bisect" is a keyword
555 status = getstring(x, _(b"bisect requires a string")).lower()
555 status = getstring(x, _(b"bisect requires a string")).lower()
556 state = set(hbisect.get(repo, status))
556 state = set(hbisect.get(repo, status))
557 return subset & state
557 return subset & state
558
558
559
559
560 # Backward-compatibility
560 # Backward-compatibility
561 # - no help entry so that we do not advertise it any more
561 # - no help entry so that we do not advertise it any more
562 @predicate(b'bisected', safe=True)
562 @predicate(b'bisected', safe=True)
563 def bisected(repo, subset, x):
563 def bisected(repo, subset, x):
564 return bisect(repo, subset, x)
564 return bisect(repo, subset, x)
565
565
566
566
567 @predicate(b'bookmark([name])', safe=True)
567 @predicate(b'bookmark([name])', safe=True)
568 def bookmark(repo, subset, x):
568 def bookmark(repo, subset, x):
569 """The named bookmark or all bookmarks.
569 """The named bookmark or all bookmarks.
570
570
571 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
571 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
572 """
572 """
573 # i18n: "bookmark" is a keyword
573 # i18n: "bookmark" is a keyword
574 args = getargs(x, 0, 1, _(b'bookmark takes one or no arguments'))
574 args = getargs(x, 0, 1, _(b'bookmark takes one or no arguments'))
575 if args:
575 if args:
576 bm = getstring(
576 bm = getstring(
577 args[0],
577 args[0],
578 # i18n: "bookmark" is a keyword
578 # i18n: "bookmark" is a keyword
579 _(b'the argument to bookmark must be a string'),
579 _(b'the argument to bookmark must be a string'),
580 )
580 )
581 kind, pattern, matcher = stringutil.stringmatcher(bm)
581 kind, pattern, matcher = stringutil.stringmatcher(bm)
582 bms = set()
582 bms = set()
583 if kind == b'literal':
583 if kind == b'literal':
584 if bm == pattern:
584 if bm == pattern:
585 pattern = repo._bookmarks.expandname(pattern)
585 pattern = repo._bookmarks.expandname(pattern)
586 bmrev = repo._bookmarks.get(pattern, None)
586 bmrev = repo._bookmarks.get(pattern, None)
587 if not bmrev:
587 if not bmrev:
588 raise error.RepoLookupError(
588 raise error.RepoLookupError(
589 _(b"bookmark '%s' does not exist") % pattern
589 _(b"bookmark '%s' does not exist") % pattern
590 )
590 )
591 bms.add(repo[bmrev].rev())
591 bms.add(repo[bmrev].rev())
592 else:
592 else:
593 matchrevs = set()
593 matchrevs = set()
594 for name, bmrev in pycompat.iteritems(repo._bookmarks):
594 for name, bmrev in pycompat.iteritems(repo._bookmarks):
595 if matcher(name):
595 if matcher(name):
596 matchrevs.add(bmrev)
596 matchrevs.add(bmrev)
597 for bmrev in matchrevs:
597 for bmrev in matchrevs:
598 bms.add(repo[bmrev].rev())
598 bms.add(repo[bmrev].rev())
599 else:
599 else:
600 bms = {repo[r].rev() for r in repo._bookmarks.values()}
600 bms = {repo[r].rev() for r in repo._bookmarks.values()}
601 bms -= {node.nullrev}
601 bms -= {node.nullrev}
602 return subset & bms
602 return subset & bms
603
603
604
604
605 @predicate(b'branch(string or set)', safe=True, weight=10)
605 @predicate(b'branch(string or set)', safe=True, weight=10)
606 def branch(repo, subset, x):
606 def branch(repo, subset, x):
607 """
607 """
608 All changesets belonging to the given branch or the branches of the given
608 All changesets belonging to the given branch or the branches of the given
609 changesets.
609 changesets.
610
610
611 Pattern matching is supported for `string`. See
611 Pattern matching is supported for `string`. See
612 :hg:`help revisions.patterns`.
612 :hg:`help revisions.patterns`.
613 """
613 """
614 getbi = repo.revbranchcache().branchinfo
614 getbi = repo.revbranchcache().branchinfo
615
615
616 def getbranch(r):
616 def getbranch(r):
617 try:
617 try:
618 return getbi(r)[0]
618 return getbi(r)[0]
619 except error.WdirUnsupported:
619 except error.WdirUnsupported:
620 return repo[r].branch()
620 return repo[r].branch()
621
621
622 try:
622 try:
623 b = getstring(x, b'')
623 b = getstring(x, b'')
624 except error.ParseError:
624 except error.ParseError:
625 # not a string, but another revspec, e.g. tip()
625 # not a string, but another revspec, e.g. tip()
626 pass
626 pass
627 else:
627 else:
628 kind, pattern, matcher = stringutil.stringmatcher(b)
628 kind, pattern, matcher = stringutil.stringmatcher(b)
629 if kind == b'literal':
629 if kind == b'literal':
630 # note: falls through to the revspec case if no branch with
630 # note: falls through to the revspec case if no branch with
631 # this name exists and pattern kind is not specified explicitly
631 # this name exists and pattern kind is not specified explicitly
632 if repo.branchmap().hasbranch(pattern):
632 if repo.branchmap().hasbranch(pattern):
633 return subset.filter(
633 return subset.filter(
634 lambda r: matcher(getbranch(r)),
634 lambda r: matcher(getbranch(r)),
635 condrepr=(b'<branch %r>', b),
635 condrepr=(b'<branch %r>', b),
636 )
636 )
637 if b.startswith(b'literal:'):
637 if b.startswith(b'literal:'):
638 raise error.RepoLookupError(
638 raise error.RepoLookupError(
639 _(b"branch '%s' does not exist") % pattern
639 _(b"branch '%s' does not exist") % pattern
640 )
640 )
641 else:
641 else:
642 return subset.filter(
642 return subset.filter(
643 lambda r: matcher(getbranch(r)), condrepr=(b'<branch %r>', b)
643 lambda r: matcher(getbranch(r)), condrepr=(b'<branch %r>', b)
644 )
644 )
645
645
646 s = getset(repo, fullreposet(repo), x)
646 s = getset(repo, fullreposet(repo), x)
647 b = set()
647 b = set()
648 for r in s:
648 for r in s:
649 b.add(getbranch(r))
649 b.add(getbranch(r))
650 c = s.__contains__
650 c = s.__contains__
651 return subset.filter(
651 return subset.filter(
652 lambda r: c(r) or getbranch(r) in b,
652 lambda r: c(r) or getbranch(r) in b,
653 condrepr=lambda: b'<branch %r>' % _sortedb(b),
653 condrepr=lambda: b'<branch %r>' % _sortedb(b),
654 )
654 )
655
655
656
656
657 @predicate(b'phasedivergent()', safe=True)
657 @predicate(b'phasedivergent()', safe=True)
658 def phasedivergent(repo, subset, x):
658 def phasedivergent(repo, subset, x):
659 """Mutable changesets marked as successors of public changesets.
659 """Mutable changesets marked as successors of public changesets.
660
660
661 Only non-public and non-obsolete changesets can be `phasedivergent`.
661 Only non-public and non-obsolete changesets can be `phasedivergent`.
662 (EXPERIMENTAL)
662 (EXPERIMENTAL)
663 """
663 """
664 # i18n: "phasedivergent" is a keyword
664 # i18n: "phasedivergent" is a keyword
665 getargs(x, 0, 0, _(b"phasedivergent takes no arguments"))
665 getargs(x, 0, 0, _(b"phasedivergent takes no arguments"))
666 phasedivergent = obsmod.getrevs(repo, b'phasedivergent')
666 phasedivergent = obsmod.getrevs(repo, b'phasedivergent')
667 return subset & phasedivergent
667 return subset & phasedivergent
668
668
669
669
670 @predicate(b'bundle()', safe=True)
670 @predicate(b'bundle()', safe=True)
671 def bundle(repo, subset, x):
671 def bundle(repo, subset, x):
672 """Changesets in the bundle.
672 """Changesets in the bundle.
673
673
674 Bundle must be specified by the -R option."""
674 Bundle must be specified by the -R option."""
675
675
676 try:
676 try:
677 bundlerevs = repo.changelog.bundlerevs
677 bundlerevs = repo.changelog.bundlerevs
678 except AttributeError:
678 except AttributeError:
679 raise error.Abort(_(b"no bundle provided - specify with -R"))
679 raise error.Abort(_(b"no bundle provided - specify with -R"))
680 return subset & bundlerevs
680 return subset & bundlerevs
681
681
682
682
683 def checkstatus(repo, subset, pat, field):
683 def checkstatus(repo, subset, pat, field):
684 """Helper for status-related revsets (adds, removes, modifies).
684 """Helper for status-related revsets (adds, removes, modifies).
685 The field parameter says which kind is desired.
685 The field parameter says which kind is desired.
686 """
686 """
687 hasset = matchmod.patkind(pat) == b'set'
687 hasset = matchmod.patkind(pat) == b'set'
688
688
689 mcache = [None]
689 mcache = [None]
690
690
691 def matches(x):
691 def matches(x):
692 c = repo[x]
692 c = repo[x]
693 if not mcache[0] or hasset:
693 if not mcache[0] or hasset:
694 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
694 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
695 m = mcache[0]
695 m = mcache[0]
696 fname = None
696 fname = None
697
697
698 assert m is not None # help pytype
698 assert m is not None # help pytype
699 if not m.anypats() and len(m.files()) == 1:
699 if not m.anypats() and len(m.files()) == 1:
700 fname = m.files()[0]
700 fname = m.files()[0]
701 if fname is not None:
701 if fname is not None:
702 if fname not in c.files():
702 if fname not in c.files():
703 return False
703 return False
704 else:
704 else:
705 if not any(m(f) for f in c.files()):
705 if not any(m(f) for f in c.files()):
706 return False
706 return False
707 files = getattr(repo.status(c.p1().node(), c.node()), field)
707 files = getattr(repo.status(c.p1().node(), c.node()), field)
708 if fname is not None:
708 if fname is not None:
709 if fname in files:
709 if fname in files:
710 return True
710 return True
711 else:
711 else:
712 if any(m(f) for f in files):
712 if any(m(f) for f in files):
713 return True
713 return True
714
714
715 return subset.filter(
715 return subset.filter(
716 matches, condrepr=(b'<status.%s %r>', pycompat.sysbytes(field), pat)
716 matches, condrepr=(b'<status.%s %r>', pycompat.sysbytes(field), pat)
717 )
717 )
718
718
719
719
720 def _children(repo, subset, parentset):
720 def _children(repo, subset, parentset):
721 if not parentset:
721 if not parentset:
722 return baseset()
722 return baseset()
723 cs = set()
723 cs = set()
724 pr = repo.changelog.parentrevs
724 pr = repo.changelog.parentrevs
725 minrev = parentset.min()
725 minrev = parentset.min()
726 nullrev = node.nullrev
726 nullrev = node.nullrev
727 for r in subset:
727 for r in subset:
728 if r <= minrev:
728 if r <= minrev:
729 continue
729 continue
730 p1, p2 = pr(r)
730 p1, p2 = pr(r)
731 if p1 in parentset:
731 if p1 in parentset:
732 cs.add(r)
732 cs.add(r)
733 if p2 != nullrev and p2 in parentset:
733 if p2 != nullrev and p2 in parentset:
734 cs.add(r)
734 cs.add(r)
735 return baseset(cs)
735 return baseset(cs)
736
736
737
737
738 @predicate(b'children(set)', safe=True)
738 @predicate(b'children(set)', safe=True)
739 def children(repo, subset, x):
739 def children(repo, subset, x):
740 """Child changesets of changesets in set.
740 """Child changesets of changesets in set.
741 """
741 """
742 s = getset(repo, fullreposet(repo), x)
742 s = getset(repo, fullreposet(repo), x)
743 cs = _children(repo, subset, s)
743 cs = _children(repo, subset, s)
744 return subset & cs
744 return subset & cs
745
745
746
746
747 @predicate(b'closed()', safe=True, weight=10)
747 @predicate(b'closed()', safe=True, weight=10)
748 def closed(repo, subset, x):
748 def closed(repo, subset, x):
749 """Changeset is closed.
749 """Changeset is closed.
750 """
750 """
751 # i18n: "closed" is a keyword
751 # i18n: "closed" is a keyword
752 getargs(x, 0, 0, _(b"closed takes no arguments"))
752 getargs(x, 0, 0, _(b"closed takes no arguments"))
753 return subset.filter(
753 return subset.filter(
754 lambda r: repo[r].closesbranch(), condrepr=b'<branch closed>'
754 lambda r: repo[r].closesbranch(), condrepr=b'<branch closed>'
755 )
755 )
756
756
757
757
758 # for internal use
758 # for internal use
759 @predicate(b'_commonancestorheads(set)', safe=True)
759 @predicate(b'_commonancestorheads(set)', safe=True)
760 def _commonancestorheads(repo, subset, x):
760 def _commonancestorheads(repo, subset, x):
761 # This is an internal method is for quickly calculating "heads(::x and
761 # This is an internal method is for quickly calculating "heads(::x and
762 # ::y)"
762 # ::y)"
763
763
764 # These greatest common ancestors are the same ones that the consensus bid
764 # These greatest common ancestors are the same ones that the consensus bid
765 # merge will find.
765 # merge will find.
766 startrevs = getset(repo, fullreposet(repo), x, order=anyorder)
766 startrevs = getset(repo, fullreposet(repo), x, order=anyorder)
767
767
768 ancs = repo.changelog._commonancestorsheads(*list(startrevs))
768 ancs = repo.changelog._commonancestorsheads(*list(startrevs))
769 return subset & baseset(ancs)
769 return subset & baseset(ancs)
770
770
771
771
772 @predicate(b'commonancestors(set)', safe=True)
772 @predicate(b'commonancestors(set)', safe=True)
773 def commonancestors(repo, subset, x):
773 def commonancestors(repo, subset, x):
774 """Changesets that are ancestors of every changeset in set.
774 """Changesets that are ancestors of every changeset in set.
775 """
775 """
776 startrevs = getset(repo, fullreposet(repo), x, order=anyorder)
776 startrevs = getset(repo, fullreposet(repo), x, order=anyorder)
777 if not startrevs:
777 if not startrevs:
778 return baseset()
778 return baseset()
779 for r in startrevs:
779 for r in startrevs:
780 subset &= dagop.revancestors(repo, baseset([r]))
780 subset &= dagop.revancestors(repo, baseset([r]))
781 return subset
781 return subset
782
782
783
783
784 @predicate(b'conflictlocal()', safe=True)
784 @predicate(b'conflictlocal()', safe=True)
785 def conflictlocal(repo, subset, x):
785 def conflictlocal(repo, subset, x):
786 """The local side of the merge, if currently in an unresolved merge.
786 """The local side of the merge, if currently in an unresolved merge.
787
787
788 "merge" here includes merge conflicts from e.g. 'hg rebase' or 'hg graft'.
788 "merge" here includes merge conflicts from e.g. 'hg rebase' or 'hg graft'.
789 """
789 """
790 getargs(x, 0, 0, _(b"conflictlocal takes no arguments"))
790 getargs(x, 0, 0, _(b"conflictlocal takes no arguments"))
791 from . import mergestate as mergestatemod
791 from . import mergestate as mergestatemod
792
792
793 mergestate = mergestatemod.mergestate.read(repo)
793 mergestate = mergestatemod.mergestate.read(repo)
794 if mergestate.active() and repo.changelog.hasnode(mergestate.local):
794 if mergestate.active() and repo.changelog.hasnode(mergestate.local):
795 return subset & {repo.changelog.rev(mergestate.local)}
795 return subset & {repo.changelog.rev(mergestate.local)}
796
796
797 return baseset()
797 return baseset()
798
798
799
799
800 @predicate(b'conflictother()', safe=True)
800 @predicate(b'conflictother()', safe=True)
801 def conflictother(repo, subset, x):
801 def conflictother(repo, subset, x):
802 """The other side of the merge, if currently in an unresolved merge.
802 """The other side of the merge, if currently in an unresolved merge.
803
803
804 "merge" here includes merge conflicts from e.g. 'hg rebase' or 'hg graft'.
804 "merge" here includes merge conflicts from e.g. 'hg rebase' or 'hg graft'.
805 """
805 """
806 getargs(x, 0, 0, _(b"conflictother takes no arguments"))
806 getargs(x, 0, 0, _(b"conflictother takes no arguments"))
807 from . import mergestate as mergestatemod
807 from . import mergestate as mergestatemod
808
808
809 mergestate = mergestatemod.mergestate.read(repo)
809 mergestate = mergestatemod.mergestate.read(repo)
810 if mergestate.active() and repo.changelog.hasnode(mergestate.other):
810 if mergestate.active() and repo.changelog.hasnode(mergestate.other):
811 return subset & {repo.changelog.rev(mergestate.other)}
811 return subset & {repo.changelog.rev(mergestate.other)}
812
812
813 return baseset()
813 return baseset()
814
814
815
815
816 @predicate(b'contains(pattern)', weight=100)
816 @predicate(b'contains(pattern)', weight=100)
817 def contains(repo, subset, x):
817 def contains(repo, subset, x):
818 """The revision's manifest contains a file matching pattern (but might not
818 """The revision's manifest contains a file matching pattern (but might not
819 modify it). See :hg:`help patterns` for information about file patterns.
819 modify it). See :hg:`help patterns` for information about file patterns.
820
820
821 The pattern without explicit kind like ``glob:`` is expected to be
821 The pattern without explicit kind like ``glob:`` is expected to be
822 relative to the current directory and match against a file exactly
822 relative to the current directory and match against a file exactly
823 for efficiency.
823 for efficiency.
824 """
824 """
825 # i18n: "contains" is a keyword
825 # i18n: "contains" is a keyword
826 pat = getstring(x, _(b"contains requires a pattern"))
826 pat = getstring(x, _(b"contains requires a pattern"))
827
827
828 def matches(x):
828 def matches(x):
829 if not matchmod.patkind(pat):
829 if not matchmod.patkind(pat):
830 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
830 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
831 if pats in repo[x]:
831 if pats in repo[x]:
832 return True
832 return True
833 else:
833 else:
834 c = repo[x]
834 c = repo[x]
835 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
835 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
836 for f in c.manifest():
836 for f in c.manifest():
837 if m(f):
837 if m(f):
838 return True
838 return True
839 return False
839 return False
840
840
841 return subset.filter(matches, condrepr=(b'<contains %r>', pat))
841 return subset.filter(matches, condrepr=(b'<contains %r>', pat))
842
842
843
843
844 @predicate(b'converted([id])', safe=True)
844 @predicate(b'converted([id])', safe=True)
845 def converted(repo, subset, x):
845 def converted(repo, subset, x):
846 """Changesets converted from the given identifier in the old repository if
846 """Changesets converted from the given identifier in the old repository if
847 present, or all converted changesets if no identifier is specified.
847 present, or all converted changesets if no identifier is specified.
848 """
848 """
849
849
850 # There is exactly no chance of resolving the revision, so do a simple
850 # There is exactly no chance of resolving the revision, so do a simple
851 # string compare and hope for the best
851 # string compare and hope for the best
852
852
853 rev = None
853 rev = None
854 # i18n: "converted" is a keyword
854 # i18n: "converted" is a keyword
855 l = getargs(x, 0, 1, _(b'converted takes one or no arguments'))
855 l = getargs(x, 0, 1, _(b'converted takes one or no arguments'))
856 if l:
856 if l:
857 # i18n: "converted" is a keyword
857 # i18n: "converted" is a keyword
858 rev = getstring(l[0], _(b'converted requires a revision'))
858 rev = getstring(l[0], _(b'converted requires a revision'))
859
859
860 def _matchvalue(r):
860 def _matchvalue(r):
861 source = repo[r].extra().get(b'convert_revision', None)
861 source = repo[r].extra().get(b'convert_revision', None)
862 return source is not None and (rev is None or source.startswith(rev))
862 return source is not None and (rev is None or source.startswith(rev))
863
863
864 return subset.filter(
864 return subset.filter(
865 lambda r: _matchvalue(r), condrepr=(b'<converted %r>', rev)
865 lambda r: _matchvalue(r), condrepr=(b'<converted %r>', rev)
866 )
866 )
867
867
868
868
869 @predicate(b'date(interval)', safe=True, weight=10)
869 @predicate(b'date(interval)', safe=True, weight=10)
870 def date(repo, subset, x):
870 def date(repo, subset, x):
871 """Changesets within the interval, see :hg:`help dates`.
871 """Changesets within the interval, see :hg:`help dates`.
872 """
872 """
873 # i18n: "date" is a keyword
873 # i18n: "date" is a keyword
874 ds = getstring(x, _(b"date requires a string"))
874 ds = getstring(x, _(b"date requires a string"))
875 dm = dateutil.matchdate(ds)
875 dm = dateutil.matchdate(ds)
876 return subset.filter(
876 return subset.filter(
877 lambda x: dm(repo[x].date()[0]), condrepr=(b'<date %r>', ds)
877 lambda x: dm(repo[x].date()[0]), condrepr=(b'<date %r>', ds)
878 )
878 )
879
879
880
880
881 @predicate(b'desc(string)', safe=True, weight=10)
881 @predicate(b'desc(string)', safe=True, weight=10)
882 def desc(repo, subset, x):
882 def desc(repo, subset, x):
883 """Search commit message for string. The match is case-insensitive.
883 """Search commit message for string. The match is case-insensitive.
884
884
885 Pattern matching is supported for `string`. See
885 Pattern matching is supported for `string`. See
886 :hg:`help revisions.patterns`.
886 :hg:`help revisions.patterns`.
887 """
887 """
888 # i18n: "desc" is a keyword
888 # i18n: "desc" is a keyword
889 ds = getstring(x, _(b"desc requires a string"))
889 ds = getstring(x, _(b"desc requires a string"))
890
890
891 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
891 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
892
892
893 return subset.filter(
893 return subset.filter(
894 lambda r: matcher(repo[r].description()), condrepr=(b'<desc %r>', ds)
894 lambda r: matcher(repo[r].description()), condrepr=(b'<desc %r>', ds)
895 )
895 )
896
896
897
897
898 def _descendants(
898 def _descendants(
899 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None
899 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None
900 ):
900 ):
901 roots = getset(repo, fullreposet(repo), x)
901 roots = getset(repo, fullreposet(repo), x)
902 if not roots:
902 if not roots:
903 return baseset()
903 return baseset()
904 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth)
904 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth)
905 return subset & s
905 return subset & s
906
906
907
907
908 @predicate(b'descendants(set[, depth])', safe=True)
908 @predicate(b'descendants(set[, depth])', safe=True)
909 def descendants(repo, subset, x):
909 def descendants(repo, subset, x):
910 """Changesets which are descendants of changesets in set, including the
910 """Changesets which are descendants of changesets in set, including the
911 given changesets themselves.
911 given changesets themselves.
912
912
913 If depth is specified, the result only includes changesets up to
913 If depth is specified, the result only includes changesets up to
914 the specified generation.
914 the specified generation.
915 """
915 """
916 # startdepth is for internal use only until we can decide the UI
916 # startdepth is for internal use only until we can decide the UI
917 args = getargsdict(x, b'descendants', b'set depth startdepth')
917 args = getargsdict(x, b'descendants', b'set depth startdepth')
918 if b'set' not in args:
918 if b'set' not in args:
919 # i18n: "descendants" is a keyword
919 # i18n: "descendants" is a keyword
920 raise error.ParseError(_(b'descendants takes at least 1 argument'))
920 raise error.ParseError(_(b'descendants takes at least 1 argument'))
921 startdepth = stopdepth = None
921 startdepth = stopdepth = None
922 if b'startdepth' in args:
922 if b'startdepth' in args:
923 n = getinteger(
923 n = getinteger(
924 args[b'startdepth'], b"descendants expects an integer startdepth"
924 args[b'startdepth'], b"descendants expects an integer startdepth"
925 )
925 )
926 if n < 0:
926 if n < 0:
927 raise error.ParseError(b"negative startdepth")
927 raise error.ParseError(b"negative startdepth")
928 startdepth = n
928 startdepth = n
929 if b'depth' in args:
929 if b'depth' in args:
930 # i18n: "descendants" is a keyword
930 # i18n: "descendants" is a keyword
931 n = getinteger(
931 n = getinteger(
932 args[b'depth'], _(b"descendants expects an integer depth")
932 args[b'depth'], _(b"descendants expects an integer depth")
933 )
933 )
934 if n < 0:
934 if n < 0:
935 raise error.ParseError(_(b"negative depth"))
935 raise error.ParseError(_(b"negative depth"))
936 stopdepth = n + 1
936 stopdepth = n + 1
937 return _descendants(
937 return _descendants(
938 repo, subset, args[b'set'], startdepth=startdepth, stopdepth=stopdepth
938 repo, subset, args[b'set'], startdepth=startdepth, stopdepth=stopdepth
939 )
939 )
940
940
941
941
942 @predicate(b'_firstdescendants', safe=True)
942 @predicate(b'_firstdescendants', safe=True)
943 def _firstdescendants(repo, subset, x):
943 def _firstdescendants(repo, subset, x):
944 # ``_firstdescendants(set)``
944 # ``_firstdescendants(set)``
945 # Like ``descendants(set)`` but follows only the first parents.
945 # Like ``descendants(set)`` but follows only the first parents.
946 return _descendants(repo, subset, x, followfirst=True)
946 return _descendants(repo, subset, x, followfirst=True)
947
947
948
948
949 @predicate(b'destination([set])', safe=True, weight=10)
949 @predicate(b'destination([set])', safe=True, weight=10)
950 def destination(repo, subset, x):
950 def destination(repo, subset, x):
951 """Changesets that were created by a graft, transplant or rebase operation,
951 """Changesets that were created by a graft, transplant or rebase operation,
952 with the given revisions specified as the source. Omitting the optional set
952 with the given revisions specified as the source. Omitting the optional set
953 is the same as passing all().
953 is the same as passing all().
954 """
954 """
955 if x is not None:
955 if x is not None:
956 sources = getset(repo, fullreposet(repo), x)
956 sources = getset(repo, fullreposet(repo), x)
957 else:
957 else:
958 sources = fullreposet(repo)
958 sources = fullreposet(repo)
959
959
960 dests = set()
960 dests = set()
961
961
962 # subset contains all of the possible destinations that can be returned, so
962 # subset contains all of the possible destinations that can be returned, so
963 # iterate over them and see if their source(s) were provided in the arg set.
963 # iterate over them and see if their source(s) were provided in the arg set.
964 # Even if the immediate src of r is not in the arg set, src's source (or
964 # Even if the immediate src of r is not in the arg set, src's source (or
965 # further back) may be. Scanning back further than the immediate src allows
965 # further back) may be. Scanning back further than the immediate src allows
966 # transitive transplants and rebases to yield the same results as transitive
966 # transitive transplants and rebases to yield the same results as transitive
967 # grafts.
967 # grafts.
968 for r in subset:
968 for r in subset:
969 src = _getrevsource(repo, r)
969 src = _getrevsource(repo, r)
970 lineage = None
970 lineage = None
971
971
972 while src is not None:
972 while src is not None:
973 if lineage is None:
973 if lineage is None:
974 lineage = list()
974 lineage = list()
975
975
976 lineage.append(r)
976 lineage.append(r)
977
977
978 # The visited lineage is a match if the current source is in the arg
978 # The visited lineage is a match if the current source is in the arg
979 # set. Since every candidate dest is visited by way of iterating
979 # set. Since every candidate dest is visited by way of iterating
980 # subset, any dests further back in the lineage will be tested by a
980 # subset, any dests further back in the lineage will be tested by a
981 # different iteration over subset. Likewise, if the src was already
981 # different iteration over subset. Likewise, if the src was already
982 # selected, the current lineage can be selected without going back
982 # selected, the current lineage can be selected without going back
983 # further.
983 # further.
984 if src in sources or src in dests:
984 if src in sources or src in dests:
985 dests.update(lineage)
985 dests.update(lineage)
986 break
986 break
987
987
988 r = src
988 r = src
989 src = _getrevsource(repo, r)
989 src = _getrevsource(repo, r)
990
990
991 return subset.filter(
991 return subset.filter(
992 dests.__contains__,
992 dests.__contains__,
993 condrepr=lambda: b'<destination %r>' % _sortedb(dests),
993 condrepr=lambda: b'<destination %r>' % _sortedb(dests),
994 )
994 )
995
995
996
996
997 @predicate(b'diff(pattern)', weight=110)
997 @predicate(b'diffcontains(pattern)', weight=110)
998 def diff(repo, subset, x):
998 def diffcontains(repo, subset, x):
999 """Search revision differences for when the pattern was added or removed.
999 """Search revision differences for when the pattern was added or removed.
1000
1000
1001 The pattern may be a substring literal or a regular expression. See
1001 The pattern may be a substring literal or a regular expression. See
1002 :hg:`help revisions.patterns`.
1002 :hg:`help revisions.patterns`.
1003 """
1003 """
1004 args = getargsdict(x, b'diff', b'pattern')
1004 args = getargsdict(x, b'diffcontains', b'pattern')
1005 if b'pattern' not in args:
1005 if b'pattern' not in args:
1006 # i18n: "diff" is a keyword
1006 # i18n: "diffcontains" is a keyword
1007 raise error.ParseError(_(b'diff takes at least 1 argument'))
1007 raise error.ParseError(_(b'diffcontains takes at least 1 argument'))
1008
1008
1009 pattern = getstring(args[b'pattern'], _(b'diff requires a string pattern'))
1009 pattern = getstring(
1010 args[b'pattern'], _(b'diffcontains requires a string pattern')
1011 )
1010 regexp = stringutil.substringregexp(pattern, re.M)
1012 regexp = stringutil.substringregexp(pattern, re.M)
1011
1013
1012 # TODO: add support for file pattern and --follow. For example,
1014 # TODO: add support for file pattern and --follow. For example,
1013 # diff(pattern[, set]) where set may be file(pattern) or follow(pattern),
1015 # diffcontains(pattern[, set]) where set may be file(pattern) or
1014 # and we'll eventually add a support for narrowing files by revset?
1016 # follow(pattern), and we'll eventually add a support for narrowing
1017 # files by revset?
1015 fmatch = matchmod.always()
1018 fmatch = matchmod.always()
1016
1019
1017 def makefilematcher(ctx):
1020 def makefilematcher(ctx):
1018 return fmatch
1021 return fmatch
1019
1022
1020 # TODO: search in a windowed way
1023 # TODO: search in a windowed way
1021 searcher = grepmod.grepsearcher(repo.ui, repo, regexp, diff=True)
1024 searcher = grepmod.grepsearcher(repo.ui, repo, regexp, diff=True)
1022
1025
1023 def testdiff(rev):
1026 def testdiff(rev):
1024 # consume the generator to discard revfiles/matches cache
1027 # consume the generator to discard revfiles/matches cache
1025 found = False
1028 found = False
1026 for fn, ctx, pstates, states in searcher.searchfiles(
1029 for fn, ctx, pstates, states in searcher.searchfiles(
1027 baseset([rev]), makefilematcher
1030 baseset([rev]), makefilematcher
1028 ):
1031 ):
1029 if next(grepmod.difflinestates(pstates, states), None):
1032 if next(grepmod.difflinestates(pstates, states), None):
1030 found = True
1033 found = True
1031 return found
1034 return found
1032
1035
1033 return subset.filter(testdiff, condrepr=(b'<diff %r>', pattern))
1036 return subset.filter(testdiff, condrepr=(b'<diffcontains %r>', pattern))
1034
1037
1035
1038
1036 @predicate(b'contentdivergent()', safe=True)
1039 @predicate(b'contentdivergent()', safe=True)
1037 def contentdivergent(repo, subset, x):
1040 def contentdivergent(repo, subset, x):
1038 """
1041 """
1039 Final successors of changesets with an alternative set of final
1042 Final successors of changesets with an alternative set of final
1040 successors. (EXPERIMENTAL)
1043 successors. (EXPERIMENTAL)
1041 """
1044 """
1042 # i18n: "contentdivergent" is a keyword
1045 # i18n: "contentdivergent" is a keyword
1043 getargs(x, 0, 0, _(b"contentdivergent takes no arguments"))
1046 getargs(x, 0, 0, _(b"contentdivergent takes no arguments"))
1044 contentdivergent = obsmod.getrevs(repo, b'contentdivergent')
1047 contentdivergent = obsmod.getrevs(repo, b'contentdivergent')
1045 return subset & contentdivergent
1048 return subset & contentdivergent
1046
1049
1047
1050
1048 @predicate(b'expectsize(set[, size])', safe=True, takeorder=True)
1051 @predicate(b'expectsize(set[, size])', safe=True, takeorder=True)
1049 def expectsize(repo, subset, x, order):
1052 def expectsize(repo, subset, x, order):
1050 """Return the given revset if size matches the revset size.
1053 """Return the given revset if size matches the revset size.
1051 Abort if the revset doesn't expect given size.
1054 Abort if the revset doesn't expect given size.
1052 size can either be an integer range or an integer.
1055 size can either be an integer range or an integer.
1053
1056
1054 For example, ``expectsize(0:1, 3:5)`` will abort as revset size is 2 and
1057 For example, ``expectsize(0:1, 3:5)`` will abort as revset size is 2 and
1055 2 is not between 3 and 5 inclusive."""
1058 2 is not between 3 and 5 inclusive."""
1056
1059
1057 args = getargsdict(x, b'expectsize', b'set size')
1060 args = getargsdict(x, b'expectsize', b'set size')
1058 minsize = 0
1061 minsize = 0
1059 maxsize = len(repo) + 1
1062 maxsize = len(repo) + 1
1060 err = b''
1063 err = b''
1061 if b'size' not in args or b'set' not in args:
1064 if b'size' not in args or b'set' not in args:
1062 raise error.ParseError(_(b'invalid set of arguments'))
1065 raise error.ParseError(_(b'invalid set of arguments'))
1063 minsize, maxsize = getintrange(
1066 minsize, maxsize = getintrange(
1064 args[b'size'],
1067 args[b'size'],
1065 _(b'expectsize requires a size range or a positive integer'),
1068 _(b'expectsize requires a size range or a positive integer'),
1066 _(b'size range bounds must be integers'),
1069 _(b'size range bounds must be integers'),
1067 minsize,
1070 minsize,
1068 maxsize,
1071 maxsize,
1069 )
1072 )
1070 if minsize < 0 or maxsize < 0:
1073 if minsize < 0 or maxsize < 0:
1071 raise error.ParseError(_(b'negative size'))
1074 raise error.ParseError(_(b'negative size'))
1072 rev = getset(repo, fullreposet(repo), args[b'set'], order=order)
1075 rev = getset(repo, fullreposet(repo), args[b'set'], order=order)
1073 if minsize != maxsize and (len(rev) < minsize or len(rev) > maxsize):
1076 if minsize != maxsize and (len(rev) < minsize or len(rev) > maxsize):
1074 err = _(b'revset size mismatch. expected between %d and %d, got %d') % (
1077 err = _(b'revset size mismatch. expected between %d and %d, got %d') % (
1075 minsize,
1078 minsize,
1076 maxsize,
1079 maxsize,
1077 len(rev),
1080 len(rev),
1078 )
1081 )
1079 elif minsize == maxsize and len(rev) != minsize:
1082 elif minsize == maxsize and len(rev) != minsize:
1080 err = _(b'revset size mismatch. expected %d, got %d') % (
1083 err = _(b'revset size mismatch. expected %d, got %d') % (
1081 minsize,
1084 minsize,
1082 len(rev),
1085 len(rev),
1083 )
1086 )
1084 if err:
1087 if err:
1085 raise error.RepoLookupError(err)
1088 raise error.RepoLookupError(err)
1086 if order == followorder:
1089 if order == followorder:
1087 return subset & rev
1090 return subset & rev
1088 else:
1091 else:
1089 return rev & subset
1092 return rev & subset
1090
1093
1091
1094
1092 @predicate(b'extdata(source)', safe=False, weight=100)
1095 @predicate(b'extdata(source)', safe=False, weight=100)
1093 def extdata(repo, subset, x):
1096 def extdata(repo, subset, x):
1094 """Changesets in the specified extdata source. (EXPERIMENTAL)"""
1097 """Changesets in the specified extdata source. (EXPERIMENTAL)"""
1095 # i18n: "extdata" is a keyword
1098 # i18n: "extdata" is a keyword
1096 args = getargsdict(x, b'extdata', b'source')
1099 args = getargsdict(x, b'extdata', b'source')
1097 source = getstring(
1100 source = getstring(
1098 args.get(b'source'),
1101 args.get(b'source'),
1099 # i18n: "extdata" is a keyword
1102 # i18n: "extdata" is a keyword
1100 _(b'extdata takes at least 1 string argument'),
1103 _(b'extdata takes at least 1 string argument'),
1101 )
1104 )
1102 data = scmutil.extdatasource(repo, source)
1105 data = scmutil.extdatasource(repo, source)
1103 return subset & baseset(data)
1106 return subset & baseset(data)
1104
1107
1105
1108
1106 @predicate(b'extinct()', safe=True)
1109 @predicate(b'extinct()', safe=True)
1107 def extinct(repo, subset, x):
1110 def extinct(repo, subset, x):
1108 """Obsolete changesets with obsolete descendants only. (EXPERIMENTAL)
1111 """Obsolete changesets with obsolete descendants only. (EXPERIMENTAL)
1109 """
1112 """
1110 # i18n: "extinct" is a keyword
1113 # i18n: "extinct" is a keyword
1111 getargs(x, 0, 0, _(b"extinct takes no arguments"))
1114 getargs(x, 0, 0, _(b"extinct takes no arguments"))
1112 extincts = obsmod.getrevs(repo, b'extinct')
1115 extincts = obsmod.getrevs(repo, b'extinct')
1113 return subset & extincts
1116 return subset & extincts
1114
1117
1115
1118
1116 @predicate(b'extra(label, [value])', safe=True)
1119 @predicate(b'extra(label, [value])', safe=True)
1117 def extra(repo, subset, x):
1120 def extra(repo, subset, x):
1118 """Changesets with the given label in the extra metadata, with the given
1121 """Changesets with the given label in the extra metadata, with the given
1119 optional value.
1122 optional value.
1120
1123
1121 Pattern matching is supported for `value`. See
1124 Pattern matching is supported for `value`. See
1122 :hg:`help revisions.patterns`.
1125 :hg:`help revisions.patterns`.
1123 """
1126 """
1124 args = getargsdict(x, b'extra', b'label value')
1127 args = getargsdict(x, b'extra', b'label value')
1125 if b'label' not in args:
1128 if b'label' not in args:
1126 # i18n: "extra" is a keyword
1129 # i18n: "extra" is a keyword
1127 raise error.ParseError(_(b'extra takes at least 1 argument'))
1130 raise error.ParseError(_(b'extra takes at least 1 argument'))
1128 # i18n: "extra" is a keyword
1131 # i18n: "extra" is a keyword
1129 label = getstring(
1132 label = getstring(
1130 args[b'label'], _(b'first argument to extra must be a string')
1133 args[b'label'], _(b'first argument to extra must be a string')
1131 )
1134 )
1132 value = None
1135 value = None
1133
1136
1134 if b'value' in args:
1137 if b'value' in args:
1135 # i18n: "extra" is a keyword
1138 # i18n: "extra" is a keyword
1136 value = getstring(
1139 value = getstring(
1137 args[b'value'], _(b'second argument to extra must be a string')
1140 args[b'value'], _(b'second argument to extra must be a string')
1138 )
1141 )
1139 kind, value, matcher = stringutil.stringmatcher(value)
1142 kind, value, matcher = stringutil.stringmatcher(value)
1140
1143
1141 def _matchvalue(r):
1144 def _matchvalue(r):
1142 extra = repo[r].extra()
1145 extra = repo[r].extra()
1143 return label in extra and (value is None or matcher(extra[label]))
1146 return label in extra and (value is None or matcher(extra[label]))
1144
1147
1145 return subset.filter(
1148 return subset.filter(
1146 lambda r: _matchvalue(r), condrepr=(b'<extra[%r] %r>', label, value)
1149 lambda r: _matchvalue(r), condrepr=(b'<extra[%r] %r>', label, value)
1147 )
1150 )
1148
1151
1149
1152
1150 @predicate(b'filelog(pattern)', safe=True)
1153 @predicate(b'filelog(pattern)', safe=True)
1151 def filelog(repo, subset, x):
1154 def filelog(repo, subset, x):
1152 """Changesets connected to the specified filelog.
1155 """Changesets connected to the specified filelog.
1153
1156
1154 For performance reasons, visits only revisions mentioned in the file-level
1157 For performance reasons, visits only revisions mentioned in the file-level
1155 filelog, rather than filtering through all changesets (much faster, but
1158 filelog, rather than filtering through all changesets (much faster, but
1156 doesn't include deletes or duplicate changes). For a slower, more accurate
1159 doesn't include deletes or duplicate changes). For a slower, more accurate
1157 result, use ``file()``.
1160 result, use ``file()``.
1158
1161
1159 The pattern without explicit kind like ``glob:`` is expected to be
1162 The pattern without explicit kind like ``glob:`` is expected to be
1160 relative to the current directory and match against a file exactly
1163 relative to the current directory and match against a file exactly
1161 for efficiency.
1164 for efficiency.
1162 """
1165 """
1163
1166
1164 # i18n: "filelog" is a keyword
1167 # i18n: "filelog" is a keyword
1165 pat = getstring(x, _(b"filelog requires a pattern"))
1168 pat = getstring(x, _(b"filelog requires a pattern"))
1166 s = set()
1169 s = set()
1167 cl = repo.changelog
1170 cl = repo.changelog
1168
1171
1169 if not matchmod.patkind(pat):
1172 if not matchmod.patkind(pat):
1170 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
1173 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
1171 files = [f]
1174 files = [f]
1172 else:
1175 else:
1173 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
1176 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
1174 files = (f for f in repo[None] if m(f))
1177 files = (f for f in repo[None] if m(f))
1175
1178
1176 for f in files:
1179 for f in files:
1177 fl = repo.file(f)
1180 fl = repo.file(f)
1178 known = {}
1181 known = {}
1179 scanpos = 0
1182 scanpos = 0
1180 for fr in list(fl):
1183 for fr in list(fl):
1181 fn = fl.node(fr)
1184 fn = fl.node(fr)
1182 if fn in known:
1185 if fn in known:
1183 s.add(known[fn])
1186 s.add(known[fn])
1184 continue
1187 continue
1185
1188
1186 lr = fl.linkrev(fr)
1189 lr = fl.linkrev(fr)
1187 if lr in cl:
1190 if lr in cl:
1188 s.add(lr)
1191 s.add(lr)
1189 elif scanpos is not None:
1192 elif scanpos is not None:
1190 # lowest matching changeset is filtered, scan further
1193 # lowest matching changeset is filtered, scan further
1191 # ahead in changelog
1194 # ahead in changelog
1192 start = max(lr, scanpos) + 1
1195 start = max(lr, scanpos) + 1
1193 scanpos = None
1196 scanpos = None
1194 for r in cl.revs(start):
1197 for r in cl.revs(start):
1195 # minimize parsing of non-matching entries
1198 # minimize parsing of non-matching entries
1196 if f in cl.revision(r) and f in cl.readfiles(r):
1199 if f in cl.revision(r) and f in cl.readfiles(r):
1197 try:
1200 try:
1198 # try to use manifest delta fastpath
1201 # try to use manifest delta fastpath
1199 n = repo[r].filenode(f)
1202 n = repo[r].filenode(f)
1200 if n not in known:
1203 if n not in known:
1201 if n == fn:
1204 if n == fn:
1202 s.add(r)
1205 s.add(r)
1203 scanpos = r
1206 scanpos = r
1204 break
1207 break
1205 else:
1208 else:
1206 known[n] = r
1209 known[n] = r
1207 except error.ManifestLookupError:
1210 except error.ManifestLookupError:
1208 # deletion in changelog
1211 # deletion in changelog
1209 continue
1212 continue
1210
1213
1211 return subset & s
1214 return subset & s
1212
1215
1213
1216
1214 @predicate(b'first(set, [n])', safe=True, takeorder=True, weight=0)
1217 @predicate(b'first(set, [n])', safe=True, takeorder=True, weight=0)
1215 def first(repo, subset, x, order):
1218 def first(repo, subset, x, order):
1216 """An alias for limit().
1219 """An alias for limit().
1217 """
1220 """
1218 return limit(repo, subset, x, order)
1221 return limit(repo, subset, x, order)
1219
1222
1220
1223
1221 def _follow(repo, subset, x, name, followfirst=False):
1224 def _follow(repo, subset, x, name, followfirst=False):
1222 args = getargsdict(x, name, b'file startrev')
1225 args = getargsdict(x, name, b'file startrev')
1223 revs = None
1226 revs = None
1224 if b'startrev' in args:
1227 if b'startrev' in args:
1225 revs = getset(repo, fullreposet(repo), args[b'startrev'])
1228 revs = getset(repo, fullreposet(repo), args[b'startrev'])
1226 if b'file' in args:
1229 if b'file' in args:
1227 x = getstring(args[b'file'], _(b"%s expected a pattern") % name)
1230 x = getstring(args[b'file'], _(b"%s expected a pattern") % name)
1228 if revs is None:
1231 if revs is None:
1229 revs = [None]
1232 revs = [None]
1230 fctxs = []
1233 fctxs = []
1231 for r in revs:
1234 for r in revs:
1232 ctx = mctx = repo[r]
1235 ctx = mctx = repo[r]
1233 if r is None:
1236 if r is None:
1234 ctx = repo[b'.']
1237 ctx = repo[b'.']
1235 m = matchmod.match(
1238 m = matchmod.match(
1236 repo.root, repo.getcwd(), [x], ctx=mctx, default=b'path'
1239 repo.root, repo.getcwd(), [x], ctx=mctx, default=b'path'
1237 )
1240 )
1238 fctxs.extend(ctx[f].introfilectx() for f in ctx.manifest().walk(m))
1241 fctxs.extend(ctx[f].introfilectx() for f in ctx.manifest().walk(m))
1239 s = dagop.filerevancestors(fctxs, followfirst)
1242 s = dagop.filerevancestors(fctxs, followfirst)
1240 else:
1243 else:
1241 if revs is None:
1244 if revs is None:
1242 revs = baseset([repo[b'.'].rev()])
1245 revs = baseset([repo[b'.'].rev()])
1243 s = dagop.revancestors(repo, revs, followfirst)
1246 s = dagop.revancestors(repo, revs, followfirst)
1244
1247
1245 return subset & s
1248 return subset & s
1246
1249
1247
1250
1248 @predicate(b'follow([file[, startrev]])', safe=True)
1251 @predicate(b'follow([file[, startrev]])', safe=True)
1249 def follow(repo, subset, x):
1252 def follow(repo, subset, x):
1250 """
1253 """
1251 An alias for ``::.`` (ancestors of the working directory's first parent).
1254 An alias for ``::.`` (ancestors of the working directory's first parent).
1252 If file pattern is specified, the histories of files matching given
1255 If file pattern is specified, the histories of files matching given
1253 pattern in the revision given by startrev are followed, including copies.
1256 pattern in the revision given by startrev are followed, including copies.
1254 """
1257 """
1255 return _follow(repo, subset, x, b'follow')
1258 return _follow(repo, subset, x, b'follow')
1256
1259
1257
1260
1258 @predicate(b'_followfirst', safe=True)
1261 @predicate(b'_followfirst', safe=True)
1259 def _followfirst(repo, subset, x):
1262 def _followfirst(repo, subset, x):
1260 # ``followfirst([file[, startrev]])``
1263 # ``followfirst([file[, startrev]])``
1261 # Like ``follow([file[, startrev]])`` but follows only the first parent
1264 # Like ``follow([file[, startrev]])`` but follows only the first parent
1262 # of every revisions or files revisions.
1265 # of every revisions or files revisions.
1263 return _follow(repo, subset, x, b'_followfirst', followfirst=True)
1266 return _follow(repo, subset, x, b'_followfirst', followfirst=True)
1264
1267
1265
1268
1266 @predicate(
1269 @predicate(
1267 b'followlines(file, fromline:toline[, startrev=., descend=False])',
1270 b'followlines(file, fromline:toline[, startrev=., descend=False])',
1268 safe=True,
1271 safe=True,
1269 )
1272 )
1270 def followlines(repo, subset, x):
1273 def followlines(repo, subset, x):
1271 """Changesets modifying `file` in line range ('fromline', 'toline').
1274 """Changesets modifying `file` in line range ('fromline', 'toline').
1272
1275
1273 Line range corresponds to 'file' content at 'startrev' and should hence be
1276 Line range corresponds to 'file' content at 'startrev' and should hence be
1274 consistent with file size. If startrev is not specified, working directory's
1277 consistent with file size. If startrev is not specified, working directory's
1275 parent is used.
1278 parent is used.
1276
1279
1277 By default, ancestors of 'startrev' are returned. If 'descend' is True,
1280 By default, ancestors of 'startrev' are returned. If 'descend' is True,
1278 descendants of 'startrev' are returned though renames are (currently) not
1281 descendants of 'startrev' are returned though renames are (currently) not
1279 followed in this direction.
1282 followed in this direction.
1280 """
1283 """
1281 args = getargsdict(x, b'followlines', b'file *lines startrev descend')
1284 args = getargsdict(x, b'followlines', b'file *lines startrev descend')
1282 if len(args[b'lines']) != 1:
1285 if len(args[b'lines']) != 1:
1283 raise error.ParseError(_(b"followlines requires a line range"))
1286 raise error.ParseError(_(b"followlines requires a line range"))
1284
1287
1285 rev = b'.'
1288 rev = b'.'
1286 if b'startrev' in args:
1289 if b'startrev' in args:
1287 revs = getset(repo, fullreposet(repo), args[b'startrev'])
1290 revs = getset(repo, fullreposet(repo), args[b'startrev'])
1288 if len(revs) != 1:
1291 if len(revs) != 1:
1289 raise error.ParseError(
1292 raise error.ParseError(
1290 # i18n: "followlines" is a keyword
1293 # i18n: "followlines" is a keyword
1291 _(b"followlines expects exactly one revision")
1294 _(b"followlines expects exactly one revision")
1292 )
1295 )
1293 rev = revs.last()
1296 rev = revs.last()
1294
1297
1295 pat = getstring(args[b'file'], _(b"followlines requires a pattern"))
1298 pat = getstring(args[b'file'], _(b"followlines requires a pattern"))
1296 # i18n: "followlines" is a keyword
1299 # i18n: "followlines" is a keyword
1297 msg = _(b"followlines expects exactly one file")
1300 msg = _(b"followlines expects exactly one file")
1298 fname = scmutil.parsefollowlinespattern(repo, rev, pat, msg)
1301 fname = scmutil.parsefollowlinespattern(repo, rev, pat, msg)
1299 fromline, toline = util.processlinerange(
1302 fromline, toline = util.processlinerange(
1300 *getintrange(
1303 *getintrange(
1301 args[b'lines'][0],
1304 args[b'lines'][0],
1302 # i18n: "followlines" is a keyword
1305 # i18n: "followlines" is a keyword
1303 _(b"followlines expects a line number or a range"),
1306 _(b"followlines expects a line number or a range"),
1304 _(b"line range bounds must be integers"),
1307 _(b"line range bounds must be integers"),
1305 )
1308 )
1306 )
1309 )
1307
1310
1308 fctx = repo[rev].filectx(fname)
1311 fctx = repo[rev].filectx(fname)
1309 descend = False
1312 descend = False
1310 if b'descend' in args:
1313 if b'descend' in args:
1311 descend = getboolean(
1314 descend = getboolean(
1312 args[b'descend'],
1315 args[b'descend'],
1313 # i18n: "descend" is a keyword
1316 # i18n: "descend" is a keyword
1314 _(b"descend argument must be a boolean"),
1317 _(b"descend argument must be a boolean"),
1315 )
1318 )
1316 if descend:
1319 if descend:
1317 rs = generatorset(
1320 rs = generatorset(
1318 (
1321 (
1319 c.rev()
1322 c.rev()
1320 for c, _linerange in dagop.blockdescendants(
1323 for c, _linerange in dagop.blockdescendants(
1321 fctx, fromline, toline
1324 fctx, fromline, toline
1322 )
1325 )
1323 ),
1326 ),
1324 iterasc=True,
1327 iterasc=True,
1325 )
1328 )
1326 else:
1329 else:
1327 rs = generatorset(
1330 rs = generatorset(
1328 (
1331 (
1329 c.rev()
1332 c.rev()
1330 for c, _linerange in dagop.blockancestors(
1333 for c, _linerange in dagop.blockancestors(
1331 fctx, fromline, toline
1334 fctx, fromline, toline
1332 )
1335 )
1333 ),
1336 ),
1334 iterasc=False,
1337 iterasc=False,
1335 )
1338 )
1336 return subset & rs
1339 return subset & rs
1337
1340
1338
1341
1339 @predicate(b'all()', safe=True)
1342 @predicate(b'all()', safe=True)
1340 def getall(repo, subset, x):
1343 def getall(repo, subset, x):
1341 """All changesets, the same as ``0:tip``.
1344 """All changesets, the same as ``0:tip``.
1342 """
1345 """
1343 # i18n: "all" is a keyword
1346 # i18n: "all" is a keyword
1344 getargs(x, 0, 0, _(b"all takes no arguments"))
1347 getargs(x, 0, 0, _(b"all takes no arguments"))
1345 return subset & spanset(repo) # drop "null" if any
1348 return subset & spanset(repo) # drop "null" if any
1346
1349
1347
1350
1348 @predicate(b'grep(regex)', weight=10)
1351 @predicate(b'grep(regex)', weight=10)
1349 def grep(repo, subset, x):
1352 def grep(repo, subset, x):
1350 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1353 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1351 to ensure special escape characters are handled correctly. Unlike
1354 to ensure special escape characters are handled correctly. Unlike
1352 ``keyword(string)``, the match is case-sensitive.
1355 ``keyword(string)``, the match is case-sensitive.
1353 """
1356 """
1354 try:
1357 try:
1355 # i18n: "grep" is a keyword
1358 # i18n: "grep" is a keyword
1356 gr = re.compile(getstring(x, _(b"grep requires a string")))
1359 gr = re.compile(getstring(x, _(b"grep requires a string")))
1357 except re.error as e:
1360 except re.error as e:
1358 raise error.ParseError(
1361 raise error.ParseError(
1359 _(b'invalid match pattern: %s') % stringutil.forcebytestr(e)
1362 _(b'invalid match pattern: %s') % stringutil.forcebytestr(e)
1360 )
1363 )
1361
1364
1362 def matches(x):
1365 def matches(x):
1363 c = repo[x]
1366 c = repo[x]
1364 for e in c.files() + [c.user(), c.description()]:
1367 for e in c.files() + [c.user(), c.description()]:
1365 if gr.search(e):
1368 if gr.search(e):
1366 return True
1369 return True
1367 return False
1370 return False
1368
1371
1369 return subset.filter(matches, condrepr=(b'<grep %r>', gr.pattern))
1372 return subset.filter(matches, condrepr=(b'<grep %r>', gr.pattern))
1370
1373
1371
1374
1372 @predicate(b'_matchfiles', safe=True)
1375 @predicate(b'_matchfiles', safe=True)
1373 def _matchfiles(repo, subset, x):
1376 def _matchfiles(repo, subset, x):
1374 # _matchfiles takes a revset list of prefixed arguments:
1377 # _matchfiles takes a revset list of prefixed arguments:
1375 #
1378 #
1376 # [p:foo, i:bar, x:baz]
1379 # [p:foo, i:bar, x:baz]
1377 #
1380 #
1378 # builds a match object from them and filters subset. Allowed
1381 # builds a match object from them and filters subset. Allowed
1379 # prefixes are 'p:' for regular patterns, 'i:' for include
1382 # prefixes are 'p:' for regular patterns, 'i:' for include
1380 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1383 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1381 # a revision identifier, or the empty string to reference the
1384 # a revision identifier, or the empty string to reference the
1382 # working directory, from which the match object is
1385 # working directory, from which the match object is
1383 # initialized. Use 'd:' to set the default matching mode, default
1386 # initialized. Use 'd:' to set the default matching mode, default
1384 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1387 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1385
1388
1386 l = getargs(x, 1, -1, b"_matchfiles requires at least one argument")
1389 l = getargs(x, 1, -1, b"_matchfiles requires at least one argument")
1387 pats, inc, exc = [], [], []
1390 pats, inc, exc = [], [], []
1388 rev, default = None, None
1391 rev, default = None, None
1389 for arg in l:
1392 for arg in l:
1390 s = getstring(arg, b"_matchfiles requires string arguments")
1393 s = getstring(arg, b"_matchfiles requires string arguments")
1391 prefix, value = s[:2], s[2:]
1394 prefix, value = s[:2], s[2:]
1392 if prefix == b'p:':
1395 if prefix == b'p:':
1393 pats.append(value)
1396 pats.append(value)
1394 elif prefix == b'i:':
1397 elif prefix == b'i:':
1395 inc.append(value)
1398 inc.append(value)
1396 elif prefix == b'x:':
1399 elif prefix == b'x:':
1397 exc.append(value)
1400 exc.append(value)
1398 elif prefix == b'r:':
1401 elif prefix == b'r:':
1399 if rev is not None:
1402 if rev is not None:
1400 raise error.ParseError(
1403 raise error.ParseError(
1401 b'_matchfiles expected at most one revision'
1404 b'_matchfiles expected at most one revision'
1402 )
1405 )
1403 if value == b'': # empty means working directory
1406 if value == b'': # empty means working directory
1404 rev = node.wdirrev
1407 rev = node.wdirrev
1405 else:
1408 else:
1406 rev = value
1409 rev = value
1407 elif prefix == b'd:':
1410 elif prefix == b'd:':
1408 if default is not None:
1411 if default is not None:
1409 raise error.ParseError(
1412 raise error.ParseError(
1410 b'_matchfiles expected at most one default mode'
1413 b'_matchfiles expected at most one default mode'
1411 )
1414 )
1412 default = value
1415 default = value
1413 else:
1416 else:
1414 raise error.ParseError(b'invalid _matchfiles prefix: %s' % prefix)
1417 raise error.ParseError(b'invalid _matchfiles prefix: %s' % prefix)
1415 if not default:
1418 if not default:
1416 default = b'glob'
1419 default = b'glob'
1417 hasset = any(matchmod.patkind(p) == b'set' for p in pats + inc + exc)
1420 hasset = any(matchmod.patkind(p) == b'set' for p in pats + inc + exc)
1418
1421
1419 mcache = [None]
1422 mcache = [None]
1420
1423
1421 # This directly read the changelog data as creating changectx for all
1424 # This directly read the changelog data as creating changectx for all
1422 # revisions is quite expensive.
1425 # revisions is quite expensive.
1423 getfiles = repo.changelog.readfiles
1426 getfiles = repo.changelog.readfiles
1424 wdirrev = node.wdirrev
1427 wdirrev = node.wdirrev
1425
1428
1426 def matches(x):
1429 def matches(x):
1427 if x == wdirrev:
1430 if x == wdirrev:
1428 files = repo[x].files()
1431 files = repo[x].files()
1429 else:
1432 else:
1430 files = getfiles(x)
1433 files = getfiles(x)
1431
1434
1432 if not mcache[0] or (hasset and rev is None):
1435 if not mcache[0] or (hasset and rev is None):
1433 r = x if rev is None else rev
1436 r = x if rev is None else rev
1434 mcache[0] = matchmod.match(
1437 mcache[0] = matchmod.match(
1435 repo.root,
1438 repo.root,
1436 repo.getcwd(),
1439 repo.getcwd(),
1437 pats,
1440 pats,
1438 include=inc,
1441 include=inc,
1439 exclude=exc,
1442 exclude=exc,
1440 ctx=repo[r],
1443 ctx=repo[r],
1441 default=default,
1444 default=default,
1442 )
1445 )
1443 m = mcache[0]
1446 m = mcache[0]
1444
1447
1445 for f in files:
1448 for f in files:
1446 if m(f):
1449 if m(f):
1447 return True
1450 return True
1448 return False
1451 return False
1449
1452
1450 return subset.filter(
1453 return subset.filter(
1451 matches,
1454 matches,
1452 condrepr=(
1455 condrepr=(
1453 b'<matchfiles patterns=%r, include=%r '
1456 b'<matchfiles patterns=%r, include=%r '
1454 b'exclude=%r, default=%r, rev=%r>',
1457 b'exclude=%r, default=%r, rev=%r>',
1455 pats,
1458 pats,
1456 inc,
1459 inc,
1457 exc,
1460 exc,
1458 default,
1461 default,
1459 rev,
1462 rev,
1460 ),
1463 ),
1461 )
1464 )
1462
1465
1463
1466
1464 @predicate(b'file(pattern)', safe=True, weight=10)
1467 @predicate(b'file(pattern)', safe=True, weight=10)
1465 def hasfile(repo, subset, x):
1468 def hasfile(repo, subset, x):
1466 """Changesets affecting files matched by pattern.
1469 """Changesets affecting files matched by pattern.
1467
1470
1468 For a faster but less accurate result, consider using ``filelog()``
1471 For a faster but less accurate result, consider using ``filelog()``
1469 instead.
1472 instead.
1470
1473
1471 This predicate uses ``glob:`` as the default kind of pattern.
1474 This predicate uses ``glob:`` as the default kind of pattern.
1472 """
1475 """
1473 # i18n: "file" is a keyword
1476 # i18n: "file" is a keyword
1474 pat = getstring(x, _(b"file requires a pattern"))
1477 pat = getstring(x, _(b"file requires a pattern"))
1475 return _matchfiles(repo, subset, (b'string', b'p:' + pat))
1478 return _matchfiles(repo, subset, (b'string', b'p:' + pat))
1476
1479
1477
1480
1478 @predicate(b'head()', safe=True)
1481 @predicate(b'head()', safe=True)
1479 def head(repo, subset, x):
1482 def head(repo, subset, x):
1480 """Changeset is a named branch head.
1483 """Changeset is a named branch head.
1481 """
1484 """
1482 # i18n: "head" is a keyword
1485 # i18n: "head" is a keyword
1483 getargs(x, 0, 0, _(b"head takes no arguments"))
1486 getargs(x, 0, 0, _(b"head takes no arguments"))
1484 hs = set()
1487 hs = set()
1485 cl = repo.changelog
1488 cl = repo.changelog
1486 for ls in repo.branchmap().iterheads():
1489 for ls in repo.branchmap().iterheads():
1487 hs.update(cl.rev(h) for h in ls)
1490 hs.update(cl.rev(h) for h in ls)
1488 return subset & baseset(hs)
1491 return subset & baseset(hs)
1489
1492
1490
1493
1491 @predicate(b'heads(set)', safe=True, takeorder=True)
1494 @predicate(b'heads(set)', safe=True, takeorder=True)
1492 def heads(repo, subset, x, order):
1495 def heads(repo, subset, x, order):
1493 """Members of set with no children in set.
1496 """Members of set with no children in set.
1494 """
1497 """
1495 # argument set should never define order
1498 # argument set should never define order
1496 if order == defineorder:
1499 if order == defineorder:
1497 order = followorder
1500 order = followorder
1498 inputset = getset(repo, fullreposet(repo), x, order=order)
1501 inputset = getset(repo, fullreposet(repo), x, order=order)
1499 wdirparents = None
1502 wdirparents = None
1500 if node.wdirrev in inputset:
1503 if node.wdirrev in inputset:
1501 # a bit slower, but not common so good enough for now
1504 # a bit slower, but not common so good enough for now
1502 wdirparents = [p.rev() for p in repo[None].parents()]
1505 wdirparents = [p.rev() for p in repo[None].parents()]
1503 inputset = set(inputset)
1506 inputset = set(inputset)
1504 inputset.discard(node.wdirrev)
1507 inputset.discard(node.wdirrev)
1505 heads = repo.changelog.headrevs(inputset)
1508 heads = repo.changelog.headrevs(inputset)
1506 if wdirparents is not None:
1509 if wdirparents is not None:
1507 heads.difference_update(wdirparents)
1510 heads.difference_update(wdirparents)
1508 heads.add(node.wdirrev)
1511 heads.add(node.wdirrev)
1509 heads = baseset(heads)
1512 heads = baseset(heads)
1510 return subset & heads
1513 return subset & heads
1511
1514
1512
1515
1513 @predicate(b'hidden()', safe=True)
1516 @predicate(b'hidden()', safe=True)
1514 def hidden(repo, subset, x):
1517 def hidden(repo, subset, x):
1515 """Hidden changesets.
1518 """Hidden changesets.
1516 """
1519 """
1517 # i18n: "hidden" is a keyword
1520 # i18n: "hidden" is a keyword
1518 getargs(x, 0, 0, _(b"hidden takes no arguments"))
1521 getargs(x, 0, 0, _(b"hidden takes no arguments"))
1519 hiddenrevs = repoview.filterrevs(repo, b'visible')
1522 hiddenrevs = repoview.filterrevs(repo, b'visible')
1520 return subset & hiddenrevs
1523 return subset & hiddenrevs
1521
1524
1522
1525
1523 @predicate(b'keyword(string)', safe=True, weight=10)
1526 @predicate(b'keyword(string)', safe=True, weight=10)
1524 def keyword(repo, subset, x):
1527 def keyword(repo, subset, x):
1525 """Search commit message, user name, and names of changed files for
1528 """Search commit message, user name, and names of changed files for
1526 string. The match is case-insensitive.
1529 string. The match is case-insensitive.
1527
1530
1528 For a regular expression or case sensitive search of these fields, use
1531 For a regular expression or case sensitive search of these fields, use
1529 ``grep(regex)``.
1532 ``grep(regex)``.
1530 """
1533 """
1531 # i18n: "keyword" is a keyword
1534 # i18n: "keyword" is a keyword
1532 kw = encoding.lower(getstring(x, _(b"keyword requires a string")))
1535 kw = encoding.lower(getstring(x, _(b"keyword requires a string")))
1533
1536
1534 def matches(r):
1537 def matches(r):
1535 c = repo[r]
1538 c = repo[r]
1536 return any(
1539 return any(
1537 kw in encoding.lower(t)
1540 kw in encoding.lower(t)
1538 for t in c.files() + [c.user(), c.description()]
1541 for t in c.files() + [c.user(), c.description()]
1539 )
1542 )
1540
1543
1541 return subset.filter(matches, condrepr=(b'<keyword %r>', kw))
1544 return subset.filter(matches, condrepr=(b'<keyword %r>', kw))
1542
1545
1543
1546
1544 @predicate(b'limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0)
1547 @predicate(b'limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0)
1545 def limit(repo, subset, x, order):
1548 def limit(repo, subset, x, order):
1546 """First n members of set, defaulting to 1, starting from offset.
1549 """First n members of set, defaulting to 1, starting from offset.
1547 """
1550 """
1548 args = getargsdict(x, b'limit', b'set n offset')
1551 args = getargsdict(x, b'limit', b'set n offset')
1549 if b'set' not in args:
1552 if b'set' not in args:
1550 # i18n: "limit" is a keyword
1553 # i18n: "limit" is a keyword
1551 raise error.ParseError(_(b"limit requires one to three arguments"))
1554 raise error.ParseError(_(b"limit requires one to three arguments"))
1552 # i18n: "limit" is a keyword
1555 # i18n: "limit" is a keyword
1553 lim = getinteger(args.get(b'n'), _(b"limit expects a number"), default=1)
1556 lim = getinteger(args.get(b'n'), _(b"limit expects a number"), default=1)
1554 if lim < 0:
1557 if lim < 0:
1555 raise error.ParseError(_(b"negative number to select"))
1558 raise error.ParseError(_(b"negative number to select"))
1556 # i18n: "limit" is a keyword
1559 # i18n: "limit" is a keyword
1557 ofs = getinteger(
1560 ofs = getinteger(
1558 args.get(b'offset'), _(b"limit expects a number"), default=0
1561 args.get(b'offset'), _(b"limit expects a number"), default=0
1559 )
1562 )
1560 if ofs < 0:
1563 if ofs < 0:
1561 raise error.ParseError(_(b"negative offset"))
1564 raise error.ParseError(_(b"negative offset"))
1562 os = getset(repo, fullreposet(repo), args[b'set'])
1565 os = getset(repo, fullreposet(repo), args[b'set'])
1563 ls = os.slice(ofs, ofs + lim)
1566 ls = os.slice(ofs, ofs + lim)
1564 if order == followorder and lim > 1:
1567 if order == followorder and lim > 1:
1565 return subset & ls
1568 return subset & ls
1566 return ls & subset
1569 return ls & subset
1567
1570
1568
1571
1569 @predicate(b'last(set, [n])', safe=True, takeorder=True)
1572 @predicate(b'last(set, [n])', safe=True, takeorder=True)
1570 def last(repo, subset, x, order):
1573 def last(repo, subset, x, order):
1571 """Last n members of set, defaulting to 1.
1574 """Last n members of set, defaulting to 1.
1572 """
1575 """
1573 # i18n: "last" is a keyword
1576 # i18n: "last" is a keyword
1574 l = getargs(x, 1, 2, _(b"last requires one or two arguments"))
1577 l = getargs(x, 1, 2, _(b"last requires one or two arguments"))
1575 lim = 1
1578 lim = 1
1576 if len(l) == 2:
1579 if len(l) == 2:
1577 # i18n: "last" is a keyword
1580 # i18n: "last" is a keyword
1578 lim = getinteger(l[1], _(b"last expects a number"))
1581 lim = getinteger(l[1], _(b"last expects a number"))
1579 if lim < 0:
1582 if lim < 0:
1580 raise error.ParseError(_(b"negative number to select"))
1583 raise error.ParseError(_(b"negative number to select"))
1581 os = getset(repo, fullreposet(repo), l[0])
1584 os = getset(repo, fullreposet(repo), l[0])
1582 os.reverse()
1585 os.reverse()
1583 ls = os.slice(0, lim)
1586 ls = os.slice(0, lim)
1584 if order == followorder and lim > 1:
1587 if order == followorder and lim > 1:
1585 return subset & ls
1588 return subset & ls
1586 ls.reverse()
1589 ls.reverse()
1587 return ls & subset
1590 return ls & subset
1588
1591
1589
1592
1590 @predicate(b'max(set)', safe=True)
1593 @predicate(b'max(set)', safe=True)
1591 def maxrev(repo, subset, x):
1594 def maxrev(repo, subset, x):
1592 """Changeset with highest revision number in set.
1595 """Changeset with highest revision number in set.
1593 """
1596 """
1594 os = getset(repo, fullreposet(repo), x)
1597 os = getset(repo, fullreposet(repo), x)
1595 try:
1598 try:
1596 m = os.max()
1599 m = os.max()
1597 if m in subset:
1600 if m in subset:
1598 return baseset([m], datarepr=(b'<max %r, %r>', subset, os))
1601 return baseset([m], datarepr=(b'<max %r, %r>', subset, os))
1599 except ValueError:
1602 except ValueError:
1600 # os.max() throws a ValueError when the collection is empty.
1603 # os.max() throws a ValueError when the collection is empty.
1601 # Same as python's max().
1604 # Same as python's max().
1602 pass
1605 pass
1603 return baseset(datarepr=(b'<max %r, %r>', subset, os))
1606 return baseset(datarepr=(b'<max %r, %r>', subset, os))
1604
1607
1605
1608
1606 @predicate(b'merge()', safe=True)
1609 @predicate(b'merge()', safe=True)
1607 def merge(repo, subset, x):
1610 def merge(repo, subset, x):
1608 """Changeset is a merge changeset.
1611 """Changeset is a merge changeset.
1609 """
1612 """
1610 # i18n: "merge" is a keyword
1613 # i18n: "merge" is a keyword
1611 getargs(x, 0, 0, _(b"merge takes no arguments"))
1614 getargs(x, 0, 0, _(b"merge takes no arguments"))
1612 cl = repo.changelog
1615 cl = repo.changelog
1613 nullrev = node.nullrev
1616 nullrev = node.nullrev
1614
1617
1615 def ismerge(r):
1618 def ismerge(r):
1616 try:
1619 try:
1617 return cl.parentrevs(r)[1] != nullrev
1620 return cl.parentrevs(r)[1] != nullrev
1618 except error.WdirUnsupported:
1621 except error.WdirUnsupported:
1619 return bool(repo[r].p2())
1622 return bool(repo[r].p2())
1620
1623
1621 return subset.filter(ismerge, condrepr=b'<merge>')
1624 return subset.filter(ismerge, condrepr=b'<merge>')
1622
1625
1623
1626
1624 @predicate(b'branchpoint()', safe=True)
1627 @predicate(b'branchpoint()', safe=True)
1625 def branchpoint(repo, subset, x):
1628 def branchpoint(repo, subset, x):
1626 """Changesets with more than one child.
1629 """Changesets with more than one child.
1627 """
1630 """
1628 # i18n: "branchpoint" is a keyword
1631 # i18n: "branchpoint" is a keyword
1629 getargs(x, 0, 0, _(b"branchpoint takes no arguments"))
1632 getargs(x, 0, 0, _(b"branchpoint takes no arguments"))
1630 cl = repo.changelog
1633 cl = repo.changelog
1631 if not subset:
1634 if not subset:
1632 return baseset()
1635 return baseset()
1633 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1636 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1634 # (and if it is not, it should.)
1637 # (and if it is not, it should.)
1635 baserev = min(subset)
1638 baserev = min(subset)
1636 parentscount = [0] * (len(repo) - baserev)
1639 parentscount = [0] * (len(repo) - baserev)
1637 for r in cl.revs(start=baserev + 1):
1640 for r in cl.revs(start=baserev + 1):
1638 for p in cl.parentrevs(r):
1641 for p in cl.parentrevs(r):
1639 if p >= baserev:
1642 if p >= baserev:
1640 parentscount[p - baserev] += 1
1643 parentscount[p - baserev] += 1
1641 return subset.filter(
1644 return subset.filter(
1642 lambda r: parentscount[r - baserev] > 1, condrepr=b'<branchpoint>'
1645 lambda r: parentscount[r - baserev] > 1, condrepr=b'<branchpoint>'
1643 )
1646 )
1644
1647
1645
1648
1646 @predicate(b'min(set)', safe=True)
1649 @predicate(b'min(set)', safe=True)
1647 def minrev(repo, subset, x):
1650 def minrev(repo, subset, x):
1648 """Changeset with lowest revision number in set.
1651 """Changeset with lowest revision number in set.
1649 """
1652 """
1650 os = getset(repo, fullreposet(repo), x)
1653 os = getset(repo, fullreposet(repo), x)
1651 try:
1654 try:
1652 m = os.min()
1655 m = os.min()
1653 if m in subset:
1656 if m in subset:
1654 return baseset([m], datarepr=(b'<min %r, %r>', subset, os))
1657 return baseset([m], datarepr=(b'<min %r, %r>', subset, os))
1655 except ValueError:
1658 except ValueError:
1656 # os.min() throws a ValueError when the collection is empty.
1659 # os.min() throws a ValueError when the collection is empty.
1657 # Same as python's min().
1660 # Same as python's min().
1658 pass
1661 pass
1659 return baseset(datarepr=(b'<min %r, %r>', subset, os))
1662 return baseset(datarepr=(b'<min %r, %r>', subset, os))
1660
1663
1661
1664
1662 @predicate(b'modifies(pattern)', safe=True, weight=30)
1665 @predicate(b'modifies(pattern)', safe=True, weight=30)
1663 def modifies(repo, subset, x):
1666 def modifies(repo, subset, x):
1664 """Changesets modifying files matched by pattern.
1667 """Changesets modifying files matched by pattern.
1665
1668
1666 The pattern without explicit kind like ``glob:`` is expected to be
1669 The pattern without explicit kind like ``glob:`` is expected to be
1667 relative to the current directory and match against a file or a
1670 relative to the current directory and match against a file or a
1668 directory.
1671 directory.
1669 """
1672 """
1670 # i18n: "modifies" is a keyword
1673 # i18n: "modifies" is a keyword
1671 pat = getstring(x, _(b"modifies requires a pattern"))
1674 pat = getstring(x, _(b"modifies requires a pattern"))
1672 return checkstatus(repo, subset, pat, 'modified')
1675 return checkstatus(repo, subset, pat, 'modified')
1673
1676
1674
1677
1675 @predicate(b'named(namespace)')
1678 @predicate(b'named(namespace)')
1676 def named(repo, subset, x):
1679 def named(repo, subset, x):
1677 """The changesets in a given namespace.
1680 """The changesets in a given namespace.
1678
1681
1679 Pattern matching is supported for `namespace`. See
1682 Pattern matching is supported for `namespace`. See
1680 :hg:`help revisions.patterns`.
1683 :hg:`help revisions.patterns`.
1681 """
1684 """
1682 # i18n: "named" is a keyword
1685 # i18n: "named" is a keyword
1683 args = getargs(x, 1, 1, _(b'named requires a namespace argument'))
1686 args = getargs(x, 1, 1, _(b'named requires a namespace argument'))
1684
1687
1685 ns = getstring(
1688 ns = getstring(
1686 args[0],
1689 args[0],
1687 # i18n: "named" is a keyword
1690 # i18n: "named" is a keyword
1688 _(b'the argument to named must be a string'),
1691 _(b'the argument to named must be a string'),
1689 )
1692 )
1690 kind, pattern, matcher = stringutil.stringmatcher(ns)
1693 kind, pattern, matcher = stringutil.stringmatcher(ns)
1691 namespaces = set()
1694 namespaces = set()
1692 if kind == b'literal':
1695 if kind == b'literal':
1693 if pattern not in repo.names:
1696 if pattern not in repo.names:
1694 raise error.RepoLookupError(
1697 raise error.RepoLookupError(
1695 _(b"namespace '%s' does not exist") % ns
1698 _(b"namespace '%s' does not exist") % ns
1696 )
1699 )
1697 namespaces.add(repo.names[pattern])
1700 namespaces.add(repo.names[pattern])
1698 else:
1701 else:
1699 for name, ns in pycompat.iteritems(repo.names):
1702 for name, ns in pycompat.iteritems(repo.names):
1700 if matcher(name):
1703 if matcher(name):
1701 namespaces.add(ns)
1704 namespaces.add(ns)
1702
1705
1703 names = set()
1706 names = set()
1704 for ns in namespaces:
1707 for ns in namespaces:
1705 for name in ns.listnames(repo):
1708 for name in ns.listnames(repo):
1706 if name not in ns.deprecated:
1709 if name not in ns.deprecated:
1707 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1710 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1708
1711
1709 names -= {node.nullrev}
1712 names -= {node.nullrev}
1710 return subset & names
1713 return subset & names
1711
1714
1712
1715
1713 @predicate(b'id(string)', safe=True)
1716 @predicate(b'id(string)', safe=True)
1714 def node_(repo, subset, x):
1717 def node_(repo, subset, x):
1715 """Revision non-ambiguously specified by the given hex string prefix.
1718 """Revision non-ambiguously specified by the given hex string prefix.
1716 """
1719 """
1717 # i18n: "id" is a keyword
1720 # i18n: "id" is a keyword
1718 l = getargs(x, 1, 1, _(b"id requires one argument"))
1721 l = getargs(x, 1, 1, _(b"id requires one argument"))
1719 # i18n: "id" is a keyword
1722 # i18n: "id" is a keyword
1720 n = getstring(l[0], _(b"id requires a string"))
1723 n = getstring(l[0], _(b"id requires a string"))
1721 if len(n) == 40:
1724 if len(n) == 40:
1722 try:
1725 try:
1723 rn = repo.changelog.rev(node.bin(n))
1726 rn = repo.changelog.rev(node.bin(n))
1724 except error.WdirUnsupported:
1727 except error.WdirUnsupported:
1725 rn = node.wdirrev
1728 rn = node.wdirrev
1726 except (LookupError, TypeError):
1729 except (LookupError, TypeError):
1727 rn = None
1730 rn = None
1728 else:
1731 else:
1729 rn = None
1732 rn = None
1730 try:
1733 try:
1731 pm = scmutil.resolvehexnodeidprefix(repo, n)
1734 pm = scmutil.resolvehexnodeidprefix(repo, n)
1732 if pm is not None:
1735 if pm is not None:
1733 rn = repo.changelog.rev(pm)
1736 rn = repo.changelog.rev(pm)
1734 except LookupError:
1737 except LookupError:
1735 pass
1738 pass
1736 except error.WdirUnsupported:
1739 except error.WdirUnsupported:
1737 rn = node.wdirrev
1740 rn = node.wdirrev
1738
1741
1739 if rn is None:
1742 if rn is None:
1740 return baseset()
1743 return baseset()
1741 result = baseset([rn])
1744 result = baseset([rn])
1742 return result & subset
1745 return result & subset
1743
1746
1744
1747
1745 @predicate(b'none()', safe=True)
1748 @predicate(b'none()', safe=True)
1746 def none(repo, subset, x):
1749 def none(repo, subset, x):
1747 """No changesets.
1750 """No changesets.
1748 """
1751 """
1749 # i18n: "none" is a keyword
1752 # i18n: "none" is a keyword
1750 getargs(x, 0, 0, _(b"none takes no arguments"))
1753 getargs(x, 0, 0, _(b"none takes no arguments"))
1751 return baseset()
1754 return baseset()
1752
1755
1753
1756
1754 @predicate(b'obsolete()', safe=True)
1757 @predicate(b'obsolete()', safe=True)
1755 def obsolete(repo, subset, x):
1758 def obsolete(repo, subset, x):
1756 """Mutable changeset with a newer version. (EXPERIMENTAL)"""
1759 """Mutable changeset with a newer version. (EXPERIMENTAL)"""
1757 # i18n: "obsolete" is a keyword
1760 # i18n: "obsolete" is a keyword
1758 getargs(x, 0, 0, _(b"obsolete takes no arguments"))
1761 getargs(x, 0, 0, _(b"obsolete takes no arguments"))
1759 obsoletes = obsmod.getrevs(repo, b'obsolete')
1762 obsoletes = obsmod.getrevs(repo, b'obsolete')
1760 return subset & obsoletes
1763 return subset & obsoletes
1761
1764
1762
1765
1763 @predicate(b'only(set, [set])', safe=True)
1766 @predicate(b'only(set, [set])', safe=True)
1764 def only(repo, subset, x):
1767 def only(repo, subset, x):
1765 """Changesets that are ancestors of the first set that are not ancestors
1768 """Changesets that are ancestors of the first set that are not ancestors
1766 of any other head in the repo. If a second set is specified, the result
1769 of any other head in the repo. If a second set is specified, the result
1767 is ancestors of the first set that are not ancestors of the second set
1770 is ancestors of the first set that are not ancestors of the second set
1768 (i.e. ::<set1> - ::<set2>).
1771 (i.e. ::<set1> - ::<set2>).
1769 """
1772 """
1770 cl = repo.changelog
1773 cl = repo.changelog
1771 # i18n: "only" is a keyword
1774 # i18n: "only" is a keyword
1772 args = getargs(x, 1, 2, _(b'only takes one or two arguments'))
1775 args = getargs(x, 1, 2, _(b'only takes one or two arguments'))
1773 include = getset(repo, fullreposet(repo), args[0])
1776 include = getset(repo, fullreposet(repo), args[0])
1774 if len(args) == 1:
1777 if len(args) == 1:
1775 if not include:
1778 if not include:
1776 return baseset()
1779 return baseset()
1777
1780
1778 descendants = set(dagop.revdescendants(repo, include, False))
1781 descendants = set(dagop.revdescendants(repo, include, False))
1779 exclude = [
1782 exclude = [
1780 rev
1783 rev
1781 for rev in cl.headrevs()
1784 for rev in cl.headrevs()
1782 if not rev in descendants and not rev in include
1785 if not rev in descendants and not rev in include
1783 ]
1786 ]
1784 else:
1787 else:
1785 exclude = getset(repo, fullreposet(repo), args[1])
1788 exclude = getset(repo, fullreposet(repo), args[1])
1786
1789
1787 results = set(cl.findmissingrevs(common=exclude, heads=include))
1790 results = set(cl.findmissingrevs(common=exclude, heads=include))
1788 # XXX we should turn this into a baseset instead of a set, smartset may do
1791 # XXX we should turn this into a baseset instead of a set, smartset may do
1789 # some optimizations from the fact this is a baseset.
1792 # some optimizations from the fact this is a baseset.
1790 return subset & results
1793 return subset & results
1791
1794
1792
1795
1793 @predicate(b'origin([set])', safe=True)
1796 @predicate(b'origin([set])', safe=True)
1794 def origin(repo, subset, x):
1797 def origin(repo, subset, x):
1795 """
1798 """
1796 Changesets that were specified as a source for the grafts, transplants or
1799 Changesets that were specified as a source for the grafts, transplants or
1797 rebases that created the given revisions. Omitting the optional set is the
1800 rebases that created the given revisions. Omitting the optional set is the
1798 same as passing all(). If a changeset created by these operations is itself
1801 same as passing all(). If a changeset created by these operations is itself
1799 specified as a source for one of these operations, only the source changeset
1802 specified as a source for one of these operations, only the source changeset
1800 for the first operation is selected.
1803 for the first operation is selected.
1801 """
1804 """
1802 if x is not None:
1805 if x is not None:
1803 dests = getset(repo, fullreposet(repo), x)
1806 dests = getset(repo, fullreposet(repo), x)
1804 else:
1807 else:
1805 dests = fullreposet(repo)
1808 dests = fullreposet(repo)
1806
1809
1807 def _firstsrc(rev):
1810 def _firstsrc(rev):
1808 src = _getrevsource(repo, rev)
1811 src = _getrevsource(repo, rev)
1809 if src is None:
1812 if src is None:
1810 return None
1813 return None
1811
1814
1812 while True:
1815 while True:
1813 prev = _getrevsource(repo, src)
1816 prev = _getrevsource(repo, src)
1814
1817
1815 if prev is None:
1818 if prev is None:
1816 return src
1819 return src
1817 src = prev
1820 src = prev
1818
1821
1819 o = {_firstsrc(r) for r in dests}
1822 o = {_firstsrc(r) for r in dests}
1820 o -= {None}
1823 o -= {None}
1821 # XXX we should turn this into a baseset instead of a set, smartset may do
1824 # XXX we should turn this into a baseset instead of a set, smartset may do
1822 # some optimizations from the fact this is a baseset.
1825 # some optimizations from the fact this is a baseset.
1823 return subset & o
1826 return subset & o
1824
1827
1825
1828
1826 @predicate(b'outgoing([path])', safe=False, weight=10)
1829 @predicate(b'outgoing([path])', safe=False, weight=10)
1827 def outgoing(repo, subset, x):
1830 def outgoing(repo, subset, x):
1828 """Changesets not found in the specified destination repository, or the
1831 """Changesets not found in the specified destination repository, or the
1829 default push location.
1832 default push location.
1830 """
1833 """
1831 # Avoid cycles.
1834 # Avoid cycles.
1832 from . import (
1835 from . import (
1833 discovery,
1836 discovery,
1834 hg,
1837 hg,
1835 )
1838 )
1836
1839
1837 # i18n: "outgoing" is a keyword
1840 # i18n: "outgoing" is a keyword
1838 l = getargs(x, 0, 1, _(b"outgoing takes one or no arguments"))
1841 l = getargs(x, 0, 1, _(b"outgoing takes one or no arguments"))
1839 # i18n: "outgoing" is a keyword
1842 # i18n: "outgoing" is a keyword
1840 dest = (
1843 dest = (
1841 l and getstring(l[0], _(b"outgoing requires a repository path")) or b''
1844 l and getstring(l[0], _(b"outgoing requires a repository path")) or b''
1842 )
1845 )
1843 if not dest:
1846 if not dest:
1844 # ui.paths.getpath() explicitly tests for None, not just a boolean
1847 # ui.paths.getpath() explicitly tests for None, not just a boolean
1845 dest = None
1848 dest = None
1846 path = repo.ui.paths.getpath(dest, default=(b'default-push', b'default'))
1849 path = repo.ui.paths.getpath(dest, default=(b'default-push', b'default'))
1847 if not path:
1850 if not path:
1848 raise error.Abort(
1851 raise error.Abort(
1849 _(b'default repository not configured!'),
1852 _(b'default repository not configured!'),
1850 hint=_(b"see 'hg help config.paths'"),
1853 hint=_(b"see 'hg help config.paths'"),
1851 )
1854 )
1852 dest = path.pushloc or path.loc
1855 dest = path.pushloc or path.loc
1853 branches = path.branch, []
1856 branches = path.branch, []
1854
1857
1855 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1858 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1856 if revs:
1859 if revs:
1857 revs = [repo.lookup(rev) for rev in revs]
1860 revs = [repo.lookup(rev) for rev in revs]
1858 other = hg.peer(repo, {}, dest)
1861 other = hg.peer(repo, {}, dest)
1859 repo.ui.pushbuffer()
1862 repo.ui.pushbuffer()
1860 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1863 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1861 repo.ui.popbuffer()
1864 repo.ui.popbuffer()
1862 cl = repo.changelog
1865 cl = repo.changelog
1863 o = {cl.rev(r) for r in outgoing.missing}
1866 o = {cl.rev(r) for r in outgoing.missing}
1864 return subset & o
1867 return subset & o
1865
1868
1866
1869
1867 @predicate(b'p1([set])', safe=True)
1870 @predicate(b'p1([set])', safe=True)
1868 def p1(repo, subset, x):
1871 def p1(repo, subset, x):
1869 """First parent of changesets in set, or the working directory.
1872 """First parent of changesets in set, or the working directory.
1870 """
1873 """
1871 if x is None:
1874 if x is None:
1872 p = repo[x].p1().rev()
1875 p = repo[x].p1().rev()
1873 if p >= 0:
1876 if p >= 0:
1874 return subset & baseset([p])
1877 return subset & baseset([p])
1875 return baseset()
1878 return baseset()
1876
1879
1877 ps = set()
1880 ps = set()
1878 cl = repo.changelog
1881 cl = repo.changelog
1879 for r in getset(repo, fullreposet(repo), x):
1882 for r in getset(repo, fullreposet(repo), x):
1880 try:
1883 try:
1881 ps.add(cl.parentrevs(r)[0])
1884 ps.add(cl.parentrevs(r)[0])
1882 except error.WdirUnsupported:
1885 except error.WdirUnsupported:
1883 ps.add(repo[r].p1().rev())
1886 ps.add(repo[r].p1().rev())
1884 ps -= {node.nullrev}
1887 ps -= {node.nullrev}
1885 # XXX we should turn this into a baseset instead of a set, smartset may do
1888 # XXX we should turn this into a baseset instead of a set, smartset may do
1886 # some optimizations from the fact this is a baseset.
1889 # some optimizations from the fact this is a baseset.
1887 return subset & ps
1890 return subset & ps
1888
1891
1889
1892
1890 @predicate(b'p2([set])', safe=True)
1893 @predicate(b'p2([set])', safe=True)
1891 def p2(repo, subset, x):
1894 def p2(repo, subset, x):
1892 """Second parent of changesets in set, or the working directory.
1895 """Second parent of changesets in set, or the working directory.
1893 """
1896 """
1894 if x is None:
1897 if x is None:
1895 ps = repo[x].parents()
1898 ps = repo[x].parents()
1896 try:
1899 try:
1897 p = ps[1].rev()
1900 p = ps[1].rev()
1898 if p >= 0:
1901 if p >= 0:
1899 return subset & baseset([p])
1902 return subset & baseset([p])
1900 return baseset()
1903 return baseset()
1901 except IndexError:
1904 except IndexError:
1902 return baseset()
1905 return baseset()
1903
1906
1904 ps = set()
1907 ps = set()
1905 cl = repo.changelog
1908 cl = repo.changelog
1906 for r in getset(repo, fullreposet(repo), x):
1909 for r in getset(repo, fullreposet(repo), x):
1907 try:
1910 try:
1908 ps.add(cl.parentrevs(r)[1])
1911 ps.add(cl.parentrevs(r)[1])
1909 except error.WdirUnsupported:
1912 except error.WdirUnsupported:
1910 parents = repo[r].parents()
1913 parents = repo[r].parents()
1911 if len(parents) == 2:
1914 if len(parents) == 2:
1912 ps.add(parents[1])
1915 ps.add(parents[1])
1913 ps -= {node.nullrev}
1916 ps -= {node.nullrev}
1914 # XXX we should turn this into a baseset instead of a set, smartset may do
1917 # XXX we should turn this into a baseset instead of a set, smartset may do
1915 # some optimizations from the fact this is a baseset.
1918 # some optimizations from the fact this is a baseset.
1916 return subset & ps
1919 return subset & ps
1917
1920
1918
1921
1919 def parentpost(repo, subset, x, order):
1922 def parentpost(repo, subset, x, order):
1920 return p1(repo, subset, x)
1923 return p1(repo, subset, x)
1921
1924
1922
1925
1923 @predicate(b'parents([set])', safe=True)
1926 @predicate(b'parents([set])', safe=True)
1924 def parents(repo, subset, x):
1927 def parents(repo, subset, x):
1925 """
1928 """
1926 The set of all parents for all changesets in set, or the working directory.
1929 The set of all parents for all changesets in set, or the working directory.
1927 """
1930 """
1928 if x is None:
1931 if x is None:
1929 ps = {p.rev() for p in repo[x].parents()}
1932 ps = {p.rev() for p in repo[x].parents()}
1930 else:
1933 else:
1931 ps = set()
1934 ps = set()
1932 cl = repo.changelog
1935 cl = repo.changelog
1933 up = ps.update
1936 up = ps.update
1934 parentrevs = cl.parentrevs
1937 parentrevs = cl.parentrevs
1935 for r in getset(repo, fullreposet(repo), x):
1938 for r in getset(repo, fullreposet(repo), x):
1936 try:
1939 try:
1937 up(parentrevs(r))
1940 up(parentrevs(r))
1938 except error.WdirUnsupported:
1941 except error.WdirUnsupported:
1939 up(p.rev() for p in repo[r].parents())
1942 up(p.rev() for p in repo[r].parents())
1940 ps -= {node.nullrev}
1943 ps -= {node.nullrev}
1941 return subset & ps
1944 return subset & ps
1942
1945
1943
1946
1944 def _phase(repo, subset, *targets):
1947 def _phase(repo, subset, *targets):
1945 """helper to select all rev in <targets> phases"""
1948 """helper to select all rev in <targets> phases"""
1946 return repo._phasecache.getrevset(repo, targets, subset)
1949 return repo._phasecache.getrevset(repo, targets, subset)
1947
1950
1948
1951
1949 @predicate(b'_phase(idx)', safe=True)
1952 @predicate(b'_phase(idx)', safe=True)
1950 def phase(repo, subset, x):
1953 def phase(repo, subset, x):
1951 l = getargs(x, 1, 1, b"_phase requires one argument")
1954 l = getargs(x, 1, 1, b"_phase requires one argument")
1952 target = getinteger(l[0], b"_phase expects a number")
1955 target = getinteger(l[0], b"_phase expects a number")
1953 return _phase(repo, subset, target)
1956 return _phase(repo, subset, target)
1954
1957
1955
1958
1956 @predicate(b'draft()', safe=True)
1959 @predicate(b'draft()', safe=True)
1957 def draft(repo, subset, x):
1960 def draft(repo, subset, x):
1958 """Changeset in draft phase."""
1961 """Changeset in draft phase."""
1959 # i18n: "draft" is a keyword
1962 # i18n: "draft" is a keyword
1960 getargs(x, 0, 0, _(b"draft takes no arguments"))
1963 getargs(x, 0, 0, _(b"draft takes no arguments"))
1961 target = phases.draft
1964 target = phases.draft
1962 return _phase(repo, subset, target)
1965 return _phase(repo, subset, target)
1963
1966
1964
1967
1965 @predicate(b'secret()', safe=True)
1968 @predicate(b'secret()', safe=True)
1966 def secret(repo, subset, x):
1969 def secret(repo, subset, x):
1967 """Changeset in secret phase."""
1970 """Changeset in secret phase."""
1968 # i18n: "secret" is a keyword
1971 # i18n: "secret" is a keyword
1969 getargs(x, 0, 0, _(b"secret takes no arguments"))
1972 getargs(x, 0, 0, _(b"secret takes no arguments"))
1970 target = phases.secret
1973 target = phases.secret
1971 return _phase(repo, subset, target)
1974 return _phase(repo, subset, target)
1972
1975
1973
1976
1974 @predicate(b'stack([revs])', safe=True)
1977 @predicate(b'stack([revs])', safe=True)
1975 def stack(repo, subset, x):
1978 def stack(repo, subset, x):
1976 """Experimental revset for the stack of changesets or working directory
1979 """Experimental revset for the stack of changesets or working directory
1977 parent. (EXPERIMENTAL)
1980 parent. (EXPERIMENTAL)
1978 """
1981 """
1979 if x is None:
1982 if x is None:
1980 stacks = stackmod.getstack(repo)
1983 stacks = stackmod.getstack(repo)
1981 else:
1984 else:
1982 stacks = smartset.baseset([])
1985 stacks = smartset.baseset([])
1983 for revision in getset(repo, fullreposet(repo), x):
1986 for revision in getset(repo, fullreposet(repo), x):
1984 currentstack = stackmod.getstack(repo, revision)
1987 currentstack = stackmod.getstack(repo, revision)
1985 stacks = stacks + currentstack
1988 stacks = stacks + currentstack
1986
1989
1987 return subset & stacks
1990 return subset & stacks
1988
1991
1989
1992
1990 def parentspec(repo, subset, x, n, order):
1993 def parentspec(repo, subset, x, n, order):
1991 """``set^0``
1994 """``set^0``
1992 The set.
1995 The set.
1993 ``set^1`` (or ``set^``), ``set^2``
1996 ``set^1`` (or ``set^``), ``set^2``
1994 First or second parent, respectively, of all changesets in set.
1997 First or second parent, respectively, of all changesets in set.
1995 """
1998 """
1996 try:
1999 try:
1997 n = int(n[1])
2000 n = int(n[1])
1998 if n not in (0, 1, 2):
2001 if n not in (0, 1, 2):
1999 raise ValueError
2002 raise ValueError
2000 except (TypeError, ValueError):
2003 except (TypeError, ValueError):
2001 raise error.ParseError(_(b"^ expects a number 0, 1, or 2"))
2004 raise error.ParseError(_(b"^ expects a number 0, 1, or 2"))
2002 ps = set()
2005 ps = set()
2003 cl = repo.changelog
2006 cl = repo.changelog
2004 for r in getset(repo, fullreposet(repo), x):
2007 for r in getset(repo, fullreposet(repo), x):
2005 if n == 0:
2008 if n == 0:
2006 ps.add(r)
2009 ps.add(r)
2007 elif n == 1:
2010 elif n == 1:
2008 try:
2011 try:
2009 ps.add(cl.parentrevs(r)[0])
2012 ps.add(cl.parentrevs(r)[0])
2010 except error.WdirUnsupported:
2013 except error.WdirUnsupported:
2011 ps.add(repo[r].p1().rev())
2014 ps.add(repo[r].p1().rev())
2012 else:
2015 else:
2013 try:
2016 try:
2014 parents = cl.parentrevs(r)
2017 parents = cl.parentrevs(r)
2015 if parents[1] != node.nullrev:
2018 if parents[1] != node.nullrev:
2016 ps.add(parents[1])
2019 ps.add(parents[1])
2017 except error.WdirUnsupported:
2020 except error.WdirUnsupported:
2018 parents = repo[r].parents()
2021 parents = repo[r].parents()
2019 if len(parents) == 2:
2022 if len(parents) == 2:
2020 ps.add(parents[1].rev())
2023 ps.add(parents[1].rev())
2021 return subset & ps
2024 return subset & ps
2022
2025
2023
2026
2024 @predicate(b'present(set)', safe=True, takeorder=True)
2027 @predicate(b'present(set)', safe=True, takeorder=True)
2025 def present(repo, subset, x, order):
2028 def present(repo, subset, x, order):
2026 """An empty set, if any revision in set isn't found; otherwise,
2029 """An empty set, if any revision in set isn't found; otherwise,
2027 all revisions in set.
2030 all revisions in set.
2028
2031
2029 If any of specified revisions is not present in the local repository,
2032 If any of specified revisions is not present in the local repository,
2030 the query is normally aborted. But this predicate allows the query
2033 the query is normally aborted. But this predicate allows the query
2031 to continue even in such cases.
2034 to continue even in such cases.
2032 """
2035 """
2033 try:
2036 try:
2034 return getset(repo, subset, x, order)
2037 return getset(repo, subset, x, order)
2035 except error.RepoLookupError:
2038 except error.RepoLookupError:
2036 return baseset()
2039 return baseset()
2037
2040
2038
2041
2039 # for internal use
2042 # for internal use
2040 @predicate(b'_notpublic', safe=True)
2043 @predicate(b'_notpublic', safe=True)
2041 def _notpublic(repo, subset, x):
2044 def _notpublic(repo, subset, x):
2042 getargs(x, 0, 0, b"_notpublic takes no arguments")
2045 getargs(x, 0, 0, b"_notpublic takes no arguments")
2043 return _phase(repo, subset, phases.draft, phases.secret)
2046 return _phase(repo, subset, phases.draft, phases.secret)
2044
2047
2045
2048
2046 # for internal use
2049 # for internal use
2047 @predicate(b'_phaseandancestors(phasename, set)', safe=True)
2050 @predicate(b'_phaseandancestors(phasename, set)', safe=True)
2048 def _phaseandancestors(repo, subset, x):
2051 def _phaseandancestors(repo, subset, x):
2049 # equivalent to (phasename() & ancestors(set)) but more efficient
2052 # equivalent to (phasename() & ancestors(set)) but more efficient
2050 # phasename could be one of 'draft', 'secret', or '_notpublic'
2053 # phasename could be one of 'draft', 'secret', or '_notpublic'
2051 args = getargs(x, 2, 2, b"_phaseandancestors requires two arguments")
2054 args = getargs(x, 2, 2, b"_phaseandancestors requires two arguments")
2052 phasename = getsymbol(args[0])
2055 phasename = getsymbol(args[0])
2053 s = getset(repo, fullreposet(repo), args[1])
2056 s = getset(repo, fullreposet(repo), args[1])
2054
2057
2055 draft = phases.draft
2058 draft = phases.draft
2056 secret = phases.secret
2059 secret = phases.secret
2057 phasenamemap = {
2060 phasenamemap = {
2058 b'_notpublic': draft,
2061 b'_notpublic': draft,
2059 b'draft': draft, # follow secret's ancestors
2062 b'draft': draft, # follow secret's ancestors
2060 b'secret': secret,
2063 b'secret': secret,
2061 }
2064 }
2062 if phasename not in phasenamemap:
2065 if phasename not in phasenamemap:
2063 raise error.ParseError(b'%r is not a valid phasename' % phasename)
2066 raise error.ParseError(b'%r is not a valid phasename' % phasename)
2064
2067
2065 minimalphase = phasenamemap[phasename]
2068 minimalphase = phasenamemap[phasename]
2066 getphase = repo._phasecache.phase
2069 getphase = repo._phasecache.phase
2067
2070
2068 def cutfunc(rev):
2071 def cutfunc(rev):
2069 return getphase(repo, rev) < minimalphase
2072 return getphase(repo, rev) < minimalphase
2070
2073
2071 revs = dagop.revancestors(repo, s, cutfunc=cutfunc)
2074 revs = dagop.revancestors(repo, s, cutfunc=cutfunc)
2072
2075
2073 if phasename == b'draft': # need to remove secret changesets
2076 if phasename == b'draft': # need to remove secret changesets
2074 revs = revs.filter(lambda r: getphase(repo, r) == draft)
2077 revs = revs.filter(lambda r: getphase(repo, r) == draft)
2075 return subset & revs
2078 return subset & revs
2076
2079
2077
2080
2078 @predicate(b'public()', safe=True)
2081 @predicate(b'public()', safe=True)
2079 def public(repo, subset, x):
2082 def public(repo, subset, x):
2080 """Changeset in public phase."""
2083 """Changeset in public phase."""
2081 # i18n: "public" is a keyword
2084 # i18n: "public" is a keyword
2082 getargs(x, 0, 0, _(b"public takes no arguments"))
2085 getargs(x, 0, 0, _(b"public takes no arguments"))
2083 return _phase(repo, subset, phases.public)
2086 return _phase(repo, subset, phases.public)
2084
2087
2085
2088
2086 @predicate(b'remote([id [,path]])', safe=False)
2089 @predicate(b'remote([id [,path]])', safe=False)
2087 def remote(repo, subset, x):
2090 def remote(repo, subset, x):
2088 """Local revision that corresponds to the given identifier in a
2091 """Local revision that corresponds to the given identifier in a
2089 remote repository, if present. Here, the '.' identifier is a
2092 remote repository, if present. Here, the '.' identifier is a
2090 synonym for the current local branch.
2093 synonym for the current local branch.
2091 """
2094 """
2092
2095
2093 from . import hg # avoid start-up nasties
2096 from . import hg # avoid start-up nasties
2094
2097
2095 # i18n: "remote" is a keyword
2098 # i18n: "remote" is a keyword
2096 l = getargs(x, 0, 2, _(b"remote takes zero, one, or two arguments"))
2099 l = getargs(x, 0, 2, _(b"remote takes zero, one, or two arguments"))
2097
2100
2098 q = b'.'
2101 q = b'.'
2099 if len(l) > 0:
2102 if len(l) > 0:
2100 # i18n: "remote" is a keyword
2103 # i18n: "remote" is a keyword
2101 q = getstring(l[0], _(b"remote requires a string id"))
2104 q = getstring(l[0], _(b"remote requires a string id"))
2102 if q == b'.':
2105 if q == b'.':
2103 q = repo[b'.'].branch()
2106 q = repo[b'.'].branch()
2104
2107
2105 dest = b''
2108 dest = b''
2106 if len(l) > 1:
2109 if len(l) > 1:
2107 # i18n: "remote" is a keyword
2110 # i18n: "remote" is a keyword
2108 dest = getstring(l[1], _(b"remote requires a repository path"))
2111 dest = getstring(l[1], _(b"remote requires a repository path"))
2109 dest = repo.ui.expandpath(dest or b'default')
2112 dest = repo.ui.expandpath(dest or b'default')
2110 dest, branches = hg.parseurl(dest)
2113 dest, branches = hg.parseurl(dest)
2111
2114
2112 other = hg.peer(repo, {}, dest)
2115 other = hg.peer(repo, {}, dest)
2113 n = other.lookup(q)
2116 n = other.lookup(q)
2114 if n in repo:
2117 if n in repo:
2115 r = repo[n].rev()
2118 r = repo[n].rev()
2116 if r in subset:
2119 if r in subset:
2117 return baseset([r])
2120 return baseset([r])
2118 return baseset()
2121 return baseset()
2119
2122
2120
2123
2121 @predicate(b'removes(pattern)', safe=True, weight=30)
2124 @predicate(b'removes(pattern)', safe=True, weight=30)
2122 def removes(repo, subset, x):
2125 def removes(repo, subset, x):
2123 """Changesets which remove files matching pattern.
2126 """Changesets which remove files matching pattern.
2124
2127
2125 The pattern without explicit kind like ``glob:`` is expected to be
2128 The pattern without explicit kind like ``glob:`` is expected to be
2126 relative to the current directory and match against a file or a
2129 relative to the current directory and match against a file or a
2127 directory.
2130 directory.
2128 """
2131 """
2129 # i18n: "removes" is a keyword
2132 # i18n: "removes" is a keyword
2130 pat = getstring(x, _(b"removes requires a pattern"))
2133 pat = getstring(x, _(b"removes requires a pattern"))
2131 return checkstatus(repo, subset, pat, 'removed')
2134 return checkstatus(repo, subset, pat, 'removed')
2132
2135
2133
2136
2134 @predicate(b'rev(number)', safe=True)
2137 @predicate(b'rev(number)', safe=True)
2135 def rev(repo, subset, x):
2138 def rev(repo, subset, x):
2136 """Revision with the given numeric identifier."""
2139 """Revision with the given numeric identifier."""
2137 try:
2140 try:
2138 return _rev(repo, subset, x)
2141 return _rev(repo, subset, x)
2139 except error.RepoLookupError:
2142 except error.RepoLookupError:
2140 return baseset()
2143 return baseset()
2141
2144
2142
2145
2143 @predicate(b'_rev(number)', safe=True)
2146 @predicate(b'_rev(number)', safe=True)
2144 def _rev(repo, subset, x):
2147 def _rev(repo, subset, x):
2145 # internal version of "rev(x)" that raise error if "x" is invalid
2148 # internal version of "rev(x)" that raise error if "x" is invalid
2146 # i18n: "rev" is a keyword
2149 # i18n: "rev" is a keyword
2147 l = getargs(x, 1, 1, _(b"rev requires one argument"))
2150 l = getargs(x, 1, 1, _(b"rev requires one argument"))
2148 try:
2151 try:
2149 # i18n: "rev" is a keyword
2152 # i18n: "rev" is a keyword
2150 l = int(getstring(l[0], _(b"rev requires a number")))
2153 l = int(getstring(l[0], _(b"rev requires a number")))
2151 except (TypeError, ValueError):
2154 except (TypeError, ValueError):
2152 # i18n: "rev" is a keyword
2155 # i18n: "rev" is a keyword
2153 raise error.ParseError(_(b"rev expects a number"))
2156 raise error.ParseError(_(b"rev expects a number"))
2154 if l not in _virtualrevs:
2157 if l not in _virtualrevs:
2155 try:
2158 try:
2156 repo.changelog.node(l) # check that the rev exists
2159 repo.changelog.node(l) # check that the rev exists
2157 except IndexError:
2160 except IndexError:
2158 raise error.RepoLookupError(_(b"unknown revision '%d'") % l)
2161 raise error.RepoLookupError(_(b"unknown revision '%d'") % l)
2159 return subset & baseset([l])
2162 return subset & baseset([l])
2160
2163
2161
2164
2162 @predicate(b'revset(set)', safe=True, takeorder=True)
2165 @predicate(b'revset(set)', safe=True, takeorder=True)
2163 def revsetpredicate(repo, subset, x, order):
2166 def revsetpredicate(repo, subset, x, order):
2164 """Strictly interpret the content as a revset.
2167 """Strictly interpret the content as a revset.
2165
2168
2166 The content of this special predicate will be strictly interpreted as a
2169 The content of this special predicate will be strictly interpreted as a
2167 revset. For example, ``revset(id(0))`` will be interpreted as "id(0)"
2170 revset. For example, ``revset(id(0))`` will be interpreted as "id(0)"
2168 without possible ambiguity with a "id(0)" bookmark or tag.
2171 without possible ambiguity with a "id(0)" bookmark or tag.
2169 """
2172 """
2170 return getset(repo, subset, x, order)
2173 return getset(repo, subset, x, order)
2171
2174
2172
2175
2173 @predicate(b'matching(revision [, field])', safe=True)
2176 @predicate(b'matching(revision [, field])', safe=True)
2174 def matching(repo, subset, x):
2177 def matching(repo, subset, x):
2175 """Changesets in which a given set of fields match the set of fields in the
2178 """Changesets in which a given set of fields match the set of fields in the
2176 selected revision or set.
2179 selected revision or set.
2177
2180
2178 To match more than one field pass the list of fields to match separated
2181 To match more than one field pass the list of fields to match separated
2179 by spaces (e.g. ``author description``).
2182 by spaces (e.g. ``author description``).
2180
2183
2181 Valid fields are most regular revision fields and some special fields.
2184 Valid fields are most regular revision fields and some special fields.
2182
2185
2183 Regular revision fields are ``description``, ``author``, ``branch``,
2186 Regular revision fields are ``description``, ``author``, ``branch``,
2184 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
2187 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
2185 and ``diff``.
2188 and ``diff``.
2186 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
2189 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
2187 contents of the revision. Two revisions matching their ``diff`` will
2190 contents of the revision. Two revisions matching their ``diff`` will
2188 also match their ``files``.
2191 also match their ``files``.
2189
2192
2190 Special fields are ``summary`` and ``metadata``:
2193 Special fields are ``summary`` and ``metadata``:
2191 ``summary`` matches the first line of the description.
2194 ``summary`` matches the first line of the description.
2192 ``metadata`` is equivalent to matching ``description user date``
2195 ``metadata`` is equivalent to matching ``description user date``
2193 (i.e. it matches the main metadata fields).
2196 (i.e. it matches the main metadata fields).
2194
2197
2195 ``metadata`` is the default field which is used when no fields are
2198 ``metadata`` is the default field which is used when no fields are
2196 specified. You can match more than one field at a time.
2199 specified. You can match more than one field at a time.
2197 """
2200 """
2198 # i18n: "matching" is a keyword
2201 # i18n: "matching" is a keyword
2199 l = getargs(x, 1, 2, _(b"matching takes 1 or 2 arguments"))
2202 l = getargs(x, 1, 2, _(b"matching takes 1 or 2 arguments"))
2200
2203
2201 revs = getset(repo, fullreposet(repo), l[0])
2204 revs = getset(repo, fullreposet(repo), l[0])
2202
2205
2203 fieldlist = [b'metadata']
2206 fieldlist = [b'metadata']
2204 if len(l) > 1:
2207 if len(l) > 1:
2205 fieldlist = getstring(
2208 fieldlist = getstring(
2206 l[1],
2209 l[1],
2207 # i18n: "matching" is a keyword
2210 # i18n: "matching" is a keyword
2208 _(b"matching requires a string as its second argument"),
2211 _(b"matching requires a string as its second argument"),
2209 ).split()
2212 ).split()
2210
2213
2211 # Make sure that there are no repeated fields,
2214 # Make sure that there are no repeated fields,
2212 # expand the 'special' 'metadata' field type
2215 # expand the 'special' 'metadata' field type
2213 # and check the 'files' whenever we check the 'diff'
2216 # and check the 'files' whenever we check the 'diff'
2214 fields = []
2217 fields = []
2215 for field in fieldlist:
2218 for field in fieldlist:
2216 if field == b'metadata':
2219 if field == b'metadata':
2217 fields += [b'user', b'description', b'date']
2220 fields += [b'user', b'description', b'date']
2218 elif field == b'diff':
2221 elif field == b'diff':
2219 # a revision matching the diff must also match the files
2222 # a revision matching the diff must also match the files
2220 # since matching the diff is very costly, make sure to
2223 # since matching the diff is very costly, make sure to
2221 # also match the files first
2224 # also match the files first
2222 fields += [b'files', b'diff']
2225 fields += [b'files', b'diff']
2223 else:
2226 else:
2224 if field == b'author':
2227 if field == b'author':
2225 field = b'user'
2228 field = b'user'
2226 fields.append(field)
2229 fields.append(field)
2227 fields = set(fields)
2230 fields = set(fields)
2228 if b'summary' in fields and b'description' in fields:
2231 if b'summary' in fields and b'description' in fields:
2229 # If a revision matches its description it also matches its summary
2232 # If a revision matches its description it also matches its summary
2230 fields.discard(b'summary')
2233 fields.discard(b'summary')
2231
2234
2232 # We may want to match more than one field
2235 # We may want to match more than one field
2233 # Not all fields take the same amount of time to be matched
2236 # Not all fields take the same amount of time to be matched
2234 # Sort the selected fields in order of increasing matching cost
2237 # Sort the selected fields in order of increasing matching cost
2235 fieldorder = [
2238 fieldorder = [
2236 b'phase',
2239 b'phase',
2237 b'parents',
2240 b'parents',
2238 b'user',
2241 b'user',
2239 b'date',
2242 b'date',
2240 b'branch',
2243 b'branch',
2241 b'summary',
2244 b'summary',
2242 b'files',
2245 b'files',
2243 b'description',
2246 b'description',
2244 b'substate',
2247 b'substate',
2245 b'diff',
2248 b'diff',
2246 ]
2249 ]
2247
2250
2248 def fieldkeyfunc(f):
2251 def fieldkeyfunc(f):
2249 try:
2252 try:
2250 return fieldorder.index(f)
2253 return fieldorder.index(f)
2251 except ValueError:
2254 except ValueError:
2252 # assume an unknown field is very costly
2255 # assume an unknown field is very costly
2253 return len(fieldorder)
2256 return len(fieldorder)
2254
2257
2255 fields = list(fields)
2258 fields = list(fields)
2256 fields.sort(key=fieldkeyfunc)
2259 fields.sort(key=fieldkeyfunc)
2257
2260
2258 # Each field will be matched with its own "getfield" function
2261 # Each field will be matched with its own "getfield" function
2259 # which will be added to the getfieldfuncs array of functions
2262 # which will be added to the getfieldfuncs array of functions
2260 getfieldfuncs = []
2263 getfieldfuncs = []
2261 _funcs = {
2264 _funcs = {
2262 b'user': lambda r: repo[r].user(),
2265 b'user': lambda r: repo[r].user(),
2263 b'branch': lambda r: repo[r].branch(),
2266 b'branch': lambda r: repo[r].branch(),
2264 b'date': lambda r: repo[r].date(),
2267 b'date': lambda r: repo[r].date(),
2265 b'description': lambda r: repo[r].description(),
2268 b'description': lambda r: repo[r].description(),
2266 b'files': lambda r: repo[r].files(),
2269 b'files': lambda r: repo[r].files(),
2267 b'parents': lambda r: repo[r].parents(),
2270 b'parents': lambda r: repo[r].parents(),
2268 b'phase': lambda r: repo[r].phase(),
2271 b'phase': lambda r: repo[r].phase(),
2269 b'substate': lambda r: repo[r].substate,
2272 b'substate': lambda r: repo[r].substate,
2270 b'summary': lambda r: repo[r].description().splitlines()[0],
2273 b'summary': lambda r: repo[r].description().splitlines()[0],
2271 b'diff': lambda r: list(
2274 b'diff': lambda r: list(
2272 repo[r].diff(opts=diffutil.diffallopts(repo.ui, {b'git': True}))
2275 repo[r].diff(opts=diffutil.diffallopts(repo.ui, {b'git': True}))
2273 ),
2276 ),
2274 }
2277 }
2275 for info in fields:
2278 for info in fields:
2276 getfield = _funcs.get(info, None)
2279 getfield = _funcs.get(info, None)
2277 if getfield is None:
2280 if getfield is None:
2278 raise error.ParseError(
2281 raise error.ParseError(
2279 # i18n: "matching" is a keyword
2282 # i18n: "matching" is a keyword
2280 _(b"unexpected field name passed to matching: %s")
2283 _(b"unexpected field name passed to matching: %s")
2281 % info
2284 % info
2282 )
2285 )
2283 getfieldfuncs.append(getfield)
2286 getfieldfuncs.append(getfield)
2284 # convert the getfield array of functions into a "getinfo" function
2287 # convert the getfield array of functions into a "getinfo" function
2285 # which returns an array of field values (or a single value if there
2288 # which returns an array of field values (or a single value if there
2286 # is only one field to match)
2289 # is only one field to match)
2287 getinfo = lambda r: [f(r) for f in getfieldfuncs]
2290 getinfo = lambda r: [f(r) for f in getfieldfuncs]
2288
2291
2289 def matches(x):
2292 def matches(x):
2290 for rev in revs:
2293 for rev in revs:
2291 target = getinfo(rev)
2294 target = getinfo(rev)
2292 match = True
2295 match = True
2293 for n, f in enumerate(getfieldfuncs):
2296 for n, f in enumerate(getfieldfuncs):
2294 if target[n] != f(x):
2297 if target[n] != f(x):
2295 match = False
2298 match = False
2296 if match:
2299 if match:
2297 return True
2300 return True
2298 return False
2301 return False
2299
2302
2300 return subset.filter(matches, condrepr=(b'<matching%r %r>', fields, revs))
2303 return subset.filter(matches, condrepr=(b'<matching%r %r>', fields, revs))
2301
2304
2302
2305
2303 @predicate(b'reverse(set)', safe=True, takeorder=True, weight=0)
2306 @predicate(b'reverse(set)', safe=True, takeorder=True, weight=0)
2304 def reverse(repo, subset, x, order):
2307 def reverse(repo, subset, x, order):
2305 """Reverse order of set.
2308 """Reverse order of set.
2306 """
2309 """
2307 l = getset(repo, subset, x, order)
2310 l = getset(repo, subset, x, order)
2308 if order == defineorder:
2311 if order == defineorder:
2309 l.reverse()
2312 l.reverse()
2310 return l
2313 return l
2311
2314
2312
2315
2313 @predicate(b'roots(set)', safe=True)
2316 @predicate(b'roots(set)', safe=True)
2314 def roots(repo, subset, x):
2317 def roots(repo, subset, x):
2315 """Changesets in set with no parent changeset in set.
2318 """Changesets in set with no parent changeset in set.
2316 """
2319 """
2317 s = getset(repo, fullreposet(repo), x)
2320 s = getset(repo, fullreposet(repo), x)
2318 parents = repo.changelog.parentrevs
2321 parents = repo.changelog.parentrevs
2319
2322
2320 def filter(r):
2323 def filter(r):
2321 for p in parents(r):
2324 for p in parents(r):
2322 if 0 <= p and p in s:
2325 if 0 <= p and p in s:
2323 return False
2326 return False
2324 return True
2327 return True
2325
2328
2326 return subset & s.filter(filter, condrepr=b'<roots>')
2329 return subset & s.filter(filter, condrepr=b'<roots>')
2327
2330
2328
2331
2329 _sortkeyfuncs = {
2332 _sortkeyfuncs = {
2330 b'rev': scmutil.intrev,
2333 b'rev': scmutil.intrev,
2331 b'branch': lambda c: c.branch(),
2334 b'branch': lambda c: c.branch(),
2332 b'desc': lambda c: c.description(),
2335 b'desc': lambda c: c.description(),
2333 b'user': lambda c: c.user(),
2336 b'user': lambda c: c.user(),
2334 b'author': lambda c: c.user(),
2337 b'author': lambda c: c.user(),
2335 b'date': lambda c: c.date()[0],
2338 b'date': lambda c: c.date()[0],
2336 b'node': scmutil.binnode,
2339 b'node': scmutil.binnode,
2337 }
2340 }
2338
2341
2339
2342
2340 def _getsortargs(x):
2343 def _getsortargs(x):
2341 """Parse sort options into (set, [(key, reverse)], opts)"""
2344 """Parse sort options into (set, [(key, reverse)], opts)"""
2342 args = getargsdict(x, b'sort', b'set keys topo.firstbranch')
2345 args = getargsdict(x, b'sort', b'set keys topo.firstbranch')
2343 if b'set' not in args:
2346 if b'set' not in args:
2344 # i18n: "sort" is a keyword
2347 # i18n: "sort" is a keyword
2345 raise error.ParseError(_(b'sort requires one or two arguments'))
2348 raise error.ParseError(_(b'sort requires one or two arguments'))
2346 keys = b"rev"
2349 keys = b"rev"
2347 if b'keys' in args:
2350 if b'keys' in args:
2348 # i18n: "sort" is a keyword
2351 # i18n: "sort" is a keyword
2349 keys = getstring(args[b'keys'], _(b"sort spec must be a string"))
2352 keys = getstring(args[b'keys'], _(b"sort spec must be a string"))
2350
2353
2351 keyflags = []
2354 keyflags = []
2352 for k in keys.split():
2355 for k in keys.split():
2353 fk = k
2356 fk = k
2354 reverse = k.startswith(b'-')
2357 reverse = k.startswith(b'-')
2355 if reverse:
2358 if reverse:
2356 k = k[1:]
2359 k = k[1:]
2357 if k not in _sortkeyfuncs and k != b'topo':
2360 if k not in _sortkeyfuncs and k != b'topo':
2358 raise error.ParseError(
2361 raise error.ParseError(
2359 _(b"unknown sort key %r") % pycompat.bytestr(fk)
2362 _(b"unknown sort key %r") % pycompat.bytestr(fk)
2360 )
2363 )
2361 keyflags.append((k, reverse))
2364 keyflags.append((k, reverse))
2362
2365
2363 if len(keyflags) > 1 and any(k == b'topo' for k, reverse in keyflags):
2366 if len(keyflags) > 1 and any(k == b'topo' for k, reverse in keyflags):
2364 # i18n: "topo" is a keyword
2367 # i18n: "topo" is a keyword
2365 raise error.ParseError(
2368 raise error.ParseError(
2366 _(b'topo sort order cannot be combined with other sort keys')
2369 _(b'topo sort order cannot be combined with other sort keys')
2367 )
2370 )
2368
2371
2369 opts = {}
2372 opts = {}
2370 if b'topo.firstbranch' in args:
2373 if b'topo.firstbranch' in args:
2371 if any(k == b'topo' for k, reverse in keyflags):
2374 if any(k == b'topo' for k, reverse in keyflags):
2372 opts[b'topo.firstbranch'] = args[b'topo.firstbranch']
2375 opts[b'topo.firstbranch'] = args[b'topo.firstbranch']
2373 else:
2376 else:
2374 # i18n: "topo" and "topo.firstbranch" are keywords
2377 # i18n: "topo" and "topo.firstbranch" are keywords
2375 raise error.ParseError(
2378 raise error.ParseError(
2376 _(
2379 _(
2377 b'topo.firstbranch can only be used '
2380 b'topo.firstbranch can only be used '
2378 b'when using the topo sort key'
2381 b'when using the topo sort key'
2379 )
2382 )
2380 )
2383 )
2381
2384
2382 return args[b'set'], keyflags, opts
2385 return args[b'set'], keyflags, opts
2383
2386
2384
2387
2385 @predicate(
2388 @predicate(
2386 b'sort(set[, [-]key... [, ...]])', safe=True, takeorder=True, weight=10
2389 b'sort(set[, [-]key... [, ...]])', safe=True, takeorder=True, weight=10
2387 )
2390 )
2388 def sort(repo, subset, x, order):
2391 def sort(repo, subset, x, order):
2389 """Sort set by keys. The default sort order is ascending, specify a key
2392 """Sort set by keys. The default sort order is ascending, specify a key
2390 as ``-key`` to sort in descending order.
2393 as ``-key`` to sort in descending order.
2391
2394
2392 The keys can be:
2395 The keys can be:
2393
2396
2394 - ``rev`` for the revision number,
2397 - ``rev`` for the revision number,
2395 - ``branch`` for the branch name,
2398 - ``branch`` for the branch name,
2396 - ``desc`` for the commit message (description),
2399 - ``desc`` for the commit message (description),
2397 - ``user`` for user name (``author`` can be used as an alias),
2400 - ``user`` for user name (``author`` can be used as an alias),
2398 - ``date`` for the commit date
2401 - ``date`` for the commit date
2399 - ``topo`` for a reverse topographical sort
2402 - ``topo`` for a reverse topographical sort
2400 - ``node`` the nodeid of the revision
2403 - ``node`` the nodeid of the revision
2401
2404
2402 The ``topo`` sort order cannot be combined with other sort keys. This sort
2405 The ``topo`` sort order cannot be combined with other sort keys. This sort
2403 takes one optional argument, ``topo.firstbranch``, which takes a revset that
2406 takes one optional argument, ``topo.firstbranch``, which takes a revset that
2404 specifies what topographical branches to prioritize in the sort.
2407 specifies what topographical branches to prioritize in the sort.
2405
2408
2406 """
2409 """
2407 s, keyflags, opts = _getsortargs(x)
2410 s, keyflags, opts = _getsortargs(x)
2408 revs = getset(repo, subset, s, order)
2411 revs = getset(repo, subset, s, order)
2409
2412
2410 if not keyflags or order != defineorder:
2413 if not keyflags or order != defineorder:
2411 return revs
2414 return revs
2412 if len(keyflags) == 1 and keyflags[0][0] == b"rev":
2415 if len(keyflags) == 1 and keyflags[0][0] == b"rev":
2413 revs.sort(reverse=keyflags[0][1])
2416 revs.sort(reverse=keyflags[0][1])
2414 return revs
2417 return revs
2415 elif keyflags[0][0] == b"topo":
2418 elif keyflags[0][0] == b"topo":
2416 firstbranch = ()
2419 firstbranch = ()
2417 if b'topo.firstbranch' in opts:
2420 if b'topo.firstbranch' in opts:
2418 firstbranch = getset(repo, subset, opts[b'topo.firstbranch'])
2421 firstbranch = getset(repo, subset, opts[b'topo.firstbranch'])
2419 revs = baseset(
2422 revs = baseset(
2420 dagop.toposort(revs, repo.changelog.parentrevs, firstbranch),
2423 dagop.toposort(revs, repo.changelog.parentrevs, firstbranch),
2421 istopo=True,
2424 istopo=True,
2422 )
2425 )
2423 if keyflags[0][1]:
2426 if keyflags[0][1]:
2424 revs.reverse()
2427 revs.reverse()
2425 return revs
2428 return revs
2426
2429
2427 # sort() is guaranteed to be stable
2430 # sort() is guaranteed to be stable
2428 ctxs = [repo[r] for r in revs]
2431 ctxs = [repo[r] for r in revs]
2429 for k, reverse in reversed(keyflags):
2432 for k, reverse in reversed(keyflags):
2430 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
2433 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
2431 return baseset([c.rev() for c in ctxs])
2434 return baseset([c.rev() for c in ctxs])
2432
2435
2433
2436
2434 @predicate(b'subrepo([pattern])')
2437 @predicate(b'subrepo([pattern])')
2435 def subrepo(repo, subset, x):
2438 def subrepo(repo, subset, x):
2436 """Changesets that add, modify or remove the given subrepo. If no subrepo
2439 """Changesets that add, modify or remove the given subrepo. If no subrepo
2437 pattern is named, any subrepo changes are returned.
2440 pattern is named, any subrepo changes are returned.
2438 """
2441 """
2439 # i18n: "subrepo" is a keyword
2442 # i18n: "subrepo" is a keyword
2440 args = getargs(x, 0, 1, _(b'subrepo takes at most one argument'))
2443 args = getargs(x, 0, 1, _(b'subrepo takes at most one argument'))
2441 pat = None
2444 pat = None
2442 if len(args) != 0:
2445 if len(args) != 0:
2443 pat = getstring(args[0], _(b"subrepo requires a pattern"))
2446 pat = getstring(args[0], _(b"subrepo requires a pattern"))
2444
2447
2445 m = matchmod.exact([b'.hgsubstate'])
2448 m = matchmod.exact([b'.hgsubstate'])
2446
2449
2447 def submatches(names):
2450 def submatches(names):
2448 k, p, m = stringutil.stringmatcher(pat)
2451 k, p, m = stringutil.stringmatcher(pat)
2449 for name in names:
2452 for name in names:
2450 if m(name):
2453 if m(name):
2451 yield name
2454 yield name
2452
2455
2453 def matches(x):
2456 def matches(x):
2454 c = repo[x]
2457 c = repo[x]
2455 s = repo.status(c.p1().node(), c.node(), match=m)
2458 s = repo.status(c.p1().node(), c.node(), match=m)
2456
2459
2457 if pat is None:
2460 if pat is None:
2458 return s.added or s.modified or s.removed
2461 return s.added or s.modified or s.removed
2459
2462
2460 if s.added:
2463 if s.added:
2461 return any(submatches(c.substate.keys()))
2464 return any(submatches(c.substate.keys()))
2462
2465
2463 if s.modified:
2466 if s.modified:
2464 subs = set(c.p1().substate.keys())
2467 subs = set(c.p1().substate.keys())
2465 subs.update(c.substate.keys())
2468 subs.update(c.substate.keys())
2466
2469
2467 for path in submatches(subs):
2470 for path in submatches(subs):
2468 if c.p1().substate.get(path) != c.substate.get(path):
2471 if c.p1().substate.get(path) != c.substate.get(path):
2469 return True
2472 return True
2470
2473
2471 if s.removed:
2474 if s.removed:
2472 return any(submatches(c.p1().substate.keys()))
2475 return any(submatches(c.p1().substate.keys()))
2473
2476
2474 return False
2477 return False
2475
2478
2476 return subset.filter(matches, condrepr=(b'<subrepo %r>', pat))
2479 return subset.filter(matches, condrepr=(b'<subrepo %r>', pat))
2477
2480
2478
2481
2479 def _mapbynodefunc(repo, s, f):
2482 def _mapbynodefunc(repo, s, f):
2480 """(repo, smartset, [node] -> [node]) -> smartset
2483 """(repo, smartset, [node] -> [node]) -> smartset
2481
2484
2482 Helper method to map a smartset to another smartset given a function only
2485 Helper method to map a smartset to another smartset given a function only
2483 talking about nodes. Handles converting between rev numbers and nodes, and
2486 talking about nodes. Handles converting between rev numbers and nodes, and
2484 filtering.
2487 filtering.
2485 """
2488 """
2486 cl = repo.unfiltered().changelog
2489 cl = repo.unfiltered().changelog
2487 torev = cl.index.get_rev
2490 torev = cl.index.get_rev
2488 tonode = cl.node
2491 tonode = cl.node
2489 result = {torev(n) for n in f(tonode(r) for r in s)}
2492 result = {torev(n) for n in f(tonode(r) for r in s)}
2490 result.discard(None)
2493 result.discard(None)
2491 return smartset.baseset(result - repo.changelog.filteredrevs)
2494 return smartset.baseset(result - repo.changelog.filteredrevs)
2492
2495
2493
2496
2494 @predicate(b'successors(set)', safe=True)
2497 @predicate(b'successors(set)', safe=True)
2495 def successors(repo, subset, x):
2498 def successors(repo, subset, x):
2496 """All successors for set, including the given set themselves.
2499 """All successors for set, including the given set themselves.
2497 (EXPERIMENTAL)"""
2500 (EXPERIMENTAL)"""
2498 s = getset(repo, fullreposet(repo), x)
2501 s = getset(repo, fullreposet(repo), x)
2499 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes)
2502 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes)
2500 d = _mapbynodefunc(repo, s, f)
2503 d = _mapbynodefunc(repo, s, f)
2501 return subset & d
2504 return subset & d
2502
2505
2503
2506
2504 def _substringmatcher(pattern, casesensitive=True):
2507 def _substringmatcher(pattern, casesensitive=True):
2505 kind, pattern, matcher = stringutil.stringmatcher(
2508 kind, pattern, matcher = stringutil.stringmatcher(
2506 pattern, casesensitive=casesensitive
2509 pattern, casesensitive=casesensitive
2507 )
2510 )
2508 if kind == b'literal':
2511 if kind == b'literal':
2509 if not casesensitive:
2512 if not casesensitive:
2510 pattern = encoding.lower(pattern)
2513 pattern = encoding.lower(pattern)
2511 matcher = lambda s: pattern in encoding.lower(s)
2514 matcher = lambda s: pattern in encoding.lower(s)
2512 else:
2515 else:
2513 matcher = lambda s: pattern in s
2516 matcher = lambda s: pattern in s
2514 return kind, pattern, matcher
2517 return kind, pattern, matcher
2515
2518
2516
2519
2517 @predicate(b'tag([name])', safe=True)
2520 @predicate(b'tag([name])', safe=True)
2518 def tag(repo, subset, x):
2521 def tag(repo, subset, x):
2519 """The specified tag by name, or all tagged revisions if no name is given.
2522 """The specified tag by name, or all tagged revisions if no name is given.
2520
2523
2521 Pattern matching is supported for `name`. See
2524 Pattern matching is supported for `name`. See
2522 :hg:`help revisions.patterns`.
2525 :hg:`help revisions.patterns`.
2523 """
2526 """
2524 # i18n: "tag" is a keyword
2527 # i18n: "tag" is a keyword
2525 args = getargs(x, 0, 1, _(b"tag takes one or no arguments"))
2528 args = getargs(x, 0, 1, _(b"tag takes one or no arguments"))
2526 cl = repo.changelog
2529 cl = repo.changelog
2527 if args:
2530 if args:
2528 pattern = getstring(
2531 pattern = getstring(
2529 args[0],
2532 args[0],
2530 # i18n: "tag" is a keyword
2533 # i18n: "tag" is a keyword
2531 _(b'the argument to tag must be a string'),
2534 _(b'the argument to tag must be a string'),
2532 )
2535 )
2533 kind, pattern, matcher = stringutil.stringmatcher(pattern)
2536 kind, pattern, matcher = stringutil.stringmatcher(pattern)
2534 if kind == b'literal':
2537 if kind == b'literal':
2535 # avoid resolving all tags
2538 # avoid resolving all tags
2536 tn = repo._tagscache.tags.get(pattern, None)
2539 tn = repo._tagscache.tags.get(pattern, None)
2537 if tn is None:
2540 if tn is None:
2538 raise error.RepoLookupError(
2541 raise error.RepoLookupError(
2539 _(b"tag '%s' does not exist") % pattern
2542 _(b"tag '%s' does not exist") % pattern
2540 )
2543 )
2541 s = {repo[tn].rev()}
2544 s = {repo[tn].rev()}
2542 else:
2545 else:
2543 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2546 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2544 else:
2547 else:
2545 s = {cl.rev(n) for t, n in repo.tagslist() if t != b'tip'}
2548 s = {cl.rev(n) for t, n in repo.tagslist() if t != b'tip'}
2546 return subset & s
2549 return subset & s
2547
2550
2548
2551
2549 @predicate(b'tagged', safe=True)
2552 @predicate(b'tagged', safe=True)
2550 def tagged(repo, subset, x):
2553 def tagged(repo, subset, x):
2551 return tag(repo, subset, x)
2554 return tag(repo, subset, x)
2552
2555
2553
2556
2554 @predicate(b'orphan()', safe=True)
2557 @predicate(b'orphan()', safe=True)
2555 def orphan(repo, subset, x):
2558 def orphan(repo, subset, x):
2556 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL)
2559 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL)
2557 """
2560 """
2558 # i18n: "orphan" is a keyword
2561 # i18n: "orphan" is a keyword
2559 getargs(x, 0, 0, _(b"orphan takes no arguments"))
2562 getargs(x, 0, 0, _(b"orphan takes no arguments"))
2560 orphan = obsmod.getrevs(repo, b'orphan')
2563 orphan = obsmod.getrevs(repo, b'orphan')
2561 return subset & orphan
2564 return subset & orphan
2562
2565
2563
2566
2564 @predicate(b'unstable()', safe=True)
2567 @predicate(b'unstable()', safe=True)
2565 def unstable(repo, subset, x):
2568 def unstable(repo, subset, x):
2566 """Changesets with instabilities. (EXPERIMENTAL)
2569 """Changesets with instabilities. (EXPERIMENTAL)
2567 """
2570 """
2568 # i18n: "unstable" is a keyword
2571 # i18n: "unstable" is a keyword
2569 getargs(x, 0, 0, b'unstable takes no arguments')
2572 getargs(x, 0, 0, b'unstable takes no arguments')
2570 _unstable = set()
2573 _unstable = set()
2571 _unstable.update(obsmod.getrevs(repo, b'orphan'))
2574 _unstable.update(obsmod.getrevs(repo, b'orphan'))
2572 _unstable.update(obsmod.getrevs(repo, b'phasedivergent'))
2575 _unstable.update(obsmod.getrevs(repo, b'phasedivergent'))
2573 _unstable.update(obsmod.getrevs(repo, b'contentdivergent'))
2576 _unstable.update(obsmod.getrevs(repo, b'contentdivergent'))
2574 return subset & baseset(_unstable)
2577 return subset & baseset(_unstable)
2575
2578
2576
2579
2577 @predicate(b'user(string)', safe=True, weight=10)
2580 @predicate(b'user(string)', safe=True, weight=10)
2578 def user(repo, subset, x):
2581 def user(repo, subset, x):
2579 """User name contains string. The match is case-insensitive.
2582 """User name contains string. The match is case-insensitive.
2580
2583
2581 Pattern matching is supported for `string`. See
2584 Pattern matching is supported for `string`. See
2582 :hg:`help revisions.patterns`.
2585 :hg:`help revisions.patterns`.
2583 """
2586 """
2584 return author(repo, subset, x)
2587 return author(repo, subset, x)
2585
2588
2586
2589
2587 @predicate(b'wdir()', safe=True, weight=0)
2590 @predicate(b'wdir()', safe=True, weight=0)
2588 def wdir(repo, subset, x):
2591 def wdir(repo, subset, x):
2589 """Working directory. (EXPERIMENTAL)"""
2592 """Working directory. (EXPERIMENTAL)"""
2590 # i18n: "wdir" is a keyword
2593 # i18n: "wdir" is a keyword
2591 getargs(x, 0, 0, _(b"wdir takes no arguments"))
2594 getargs(x, 0, 0, _(b"wdir takes no arguments"))
2592 if node.wdirrev in subset or isinstance(subset, fullreposet):
2595 if node.wdirrev in subset or isinstance(subset, fullreposet):
2593 return baseset([node.wdirrev])
2596 return baseset([node.wdirrev])
2594 return baseset()
2597 return baseset()
2595
2598
2596
2599
2597 def _orderedlist(repo, subset, x):
2600 def _orderedlist(repo, subset, x):
2598 s = getstring(x, b"internal error")
2601 s = getstring(x, b"internal error")
2599 if not s:
2602 if not s:
2600 return baseset()
2603 return baseset()
2601 # remove duplicates here. it's difficult for caller to deduplicate sets
2604 # remove duplicates here. it's difficult for caller to deduplicate sets
2602 # because different symbols can point to the same rev.
2605 # because different symbols can point to the same rev.
2603 cl = repo.changelog
2606 cl = repo.changelog
2604 ls = []
2607 ls = []
2605 seen = set()
2608 seen = set()
2606 for t in s.split(b'\0'):
2609 for t in s.split(b'\0'):
2607 try:
2610 try:
2608 # fast path for integer revision
2611 # fast path for integer revision
2609 r = int(t)
2612 r = int(t)
2610 if (b'%d' % r) != t or r not in cl:
2613 if (b'%d' % r) != t or r not in cl:
2611 raise ValueError
2614 raise ValueError
2612 revs = [r]
2615 revs = [r]
2613 except ValueError:
2616 except ValueError:
2614 revs = stringset(repo, subset, t, defineorder)
2617 revs = stringset(repo, subset, t, defineorder)
2615
2618
2616 for r in revs:
2619 for r in revs:
2617 if r in seen:
2620 if r in seen:
2618 continue
2621 continue
2619 if (
2622 if (
2620 r in subset
2623 r in subset
2621 or r in _virtualrevs
2624 or r in _virtualrevs
2622 and isinstance(subset, fullreposet)
2625 and isinstance(subset, fullreposet)
2623 ):
2626 ):
2624 ls.append(r)
2627 ls.append(r)
2625 seen.add(r)
2628 seen.add(r)
2626 return baseset(ls)
2629 return baseset(ls)
2627
2630
2628
2631
2629 # for internal use
2632 # for internal use
2630 @predicate(b'_list', safe=True, takeorder=True)
2633 @predicate(b'_list', safe=True, takeorder=True)
2631 def _list(repo, subset, x, order):
2634 def _list(repo, subset, x, order):
2632 if order == followorder:
2635 if order == followorder:
2633 # slow path to take the subset order
2636 # slow path to take the subset order
2634 return subset & _orderedlist(repo, fullreposet(repo), x)
2637 return subset & _orderedlist(repo, fullreposet(repo), x)
2635 else:
2638 else:
2636 return _orderedlist(repo, subset, x)
2639 return _orderedlist(repo, subset, x)
2637
2640
2638
2641
2639 def _orderedintlist(repo, subset, x):
2642 def _orderedintlist(repo, subset, x):
2640 s = getstring(x, b"internal error")
2643 s = getstring(x, b"internal error")
2641 if not s:
2644 if not s:
2642 return baseset()
2645 return baseset()
2643 ls = [int(r) for r in s.split(b'\0')]
2646 ls = [int(r) for r in s.split(b'\0')]
2644 s = subset
2647 s = subset
2645 return baseset([r for r in ls if r in s])
2648 return baseset([r for r in ls if r in s])
2646
2649
2647
2650
2648 # for internal use
2651 # for internal use
2649 @predicate(b'_intlist', safe=True, takeorder=True, weight=0)
2652 @predicate(b'_intlist', safe=True, takeorder=True, weight=0)
2650 def _intlist(repo, subset, x, order):
2653 def _intlist(repo, subset, x, order):
2651 if order == followorder:
2654 if order == followorder:
2652 # slow path to take the subset order
2655 # slow path to take the subset order
2653 return subset & _orderedintlist(repo, fullreposet(repo), x)
2656 return subset & _orderedintlist(repo, fullreposet(repo), x)
2654 else:
2657 else:
2655 return _orderedintlist(repo, subset, x)
2658 return _orderedintlist(repo, subset, x)
2656
2659
2657
2660
2658 def _orderedhexlist(repo, subset, x):
2661 def _orderedhexlist(repo, subset, x):
2659 s = getstring(x, b"internal error")
2662 s = getstring(x, b"internal error")
2660 if not s:
2663 if not s:
2661 return baseset()
2664 return baseset()
2662 cl = repo.changelog
2665 cl = repo.changelog
2663 ls = [cl.rev(node.bin(r)) for r in s.split(b'\0')]
2666 ls = [cl.rev(node.bin(r)) for r in s.split(b'\0')]
2664 s = subset
2667 s = subset
2665 return baseset([r for r in ls if r in s])
2668 return baseset([r for r in ls if r in s])
2666
2669
2667
2670
2668 # for internal use
2671 # for internal use
2669 @predicate(b'_hexlist', safe=True, takeorder=True)
2672 @predicate(b'_hexlist', safe=True, takeorder=True)
2670 def _hexlist(repo, subset, x, order):
2673 def _hexlist(repo, subset, x, order):
2671 if order == followorder:
2674 if order == followorder:
2672 # slow path to take the subset order
2675 # slow path to take the subset order
2673 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2676 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2674 else:
2677 else:
2675 return _orderedhexlist(repo, subset, x)
2678 return _orderedhexlist(repo, subset, x)
2676
2679
2677
2680
2678 methods = {
2681 methods = {
2679 b"range": rangeset,
2682 b"range": rangeset,
2680 b"rangeall": rangeall,
2683 b"rangeall": rangeall,
2681 b"rangepre": rangepre,
2684 b"rangepre": rangepre,
2682 b"rangepost": rangepost,
2685 b"rangepost": rangepost,
2683 b"dagrange": dagrange,
2686 b"dagrange": dagrange,
2684 b"string": stringset,
2687 b"string": stringset,
2685 b"symbol": stringset,
2688 b"symbol": stringset,
2686 b"and": andset,
2689 b"and": andset,
2687 b"andsmally": andsmallyset,
2690 b"andsmally": andsmallyset,
2688 b"or": orset,
2691 b"or": orset,
2689 b"not": notset,
2692 b"not": notset,
2690 b"difference": differenceset,
2693 b"difference": differenceset,
2691 b"relation": relationset,
2694 b"relation": relationset,
2692 b"relsubscript": relsubscriptset,
2695 b"relsubscript": relsubscriptset,
2693 b"subscript": subscriptset,
2696 b"subscript": subscriptset,
2694 b"list": listset,
2697 b"list": listset,
2695 b"keyvalue": keyvaluepair,
2698 b"keyvalue": keyvaluepair,
2696 b"func": func,
2699 b"func": func,
2697 b"ancestor": ancestorspec,
2700 b"ancestor": ancestorspec,
2698 b"parent": parentspec,
2701 b"parent": parentspec,
2699 b"parentpost": parentpost,
2702 b"parentpost": parentpost,
2700 b"smartset": rawsmartset,
2703 b"smartset": rawsmartset,
2701 }
2704 }
2702
2705
2703 relations = {
2706 relations = {
2704 b"g": generationsrel,
2707 b"g": generationsrel,
2705 b"generations": generationsrel,
2708 b"generations": generationsrel,
2706 }
2709 }
2707
2710
2708 subscriptrelations = {
2711 subscriptrelations = {
2709 b"g": generationssubrel,
2712 b"g": generationssubrel,
2710 b"generations": generationssubrel,
2713 b"generations": generationssubrel,
2711 }
2714 }
2712
2715
2713
2716
2714 def lookupfn(repo):
2717 def lookupfn(repo):
2715 return lambda symbol: scmutil.isrevsymbol(repo, symbol)
2718 return lambda symbol: scmutil.isrevsymbol(repo, symbol)
2716
2719
2717
2720
2718 def match(ui, spec, lookup=None):
2721 def match(ui, spec, lookup=None):
2719 """Create a matcher for a single revision spec"""
2722 """Create a matcher for a single revision spec"""
2720 return matchany(ui, [spec], lookup=lookup)
2723 return matchany(ui, [spec], lookup=lookup)
2721
2724
2722
2725
2723 def matchany(ui, specs, lookup=None, localalias=None):
2726 def matchany(ui, specs, lookup=None, localalias=None):
2724 """Create a matcher that will include any revisions matching one of the
2727 """Create a matcher that will include any revisions matching one of the
2725 given specs
2728 given specs
2726
2729
2727 If lookup function is not None, the parser will first attempt to handle
2730 If lookup function is not None, the parser will first attempt to handle
2728 old-style ranges, which may contain operator characters.
2731 old-style ranges, which may contain operator characters.
2729
2732
2730 If localalias is not None, it is a dict {name: definitionstring}. It takes
2733 If localalias is not None, it is a dict {name: definitionstring}. It takes
2731 precedence over [revsetalias] config section.
2734 precedence over [revsetalias] config section.
2732 """
2735 """
2733 if not specs:
2736 if not specs:
2734
2737
2735 def mfunc(repo, subset=None):
2738 def mfunc(repo, subset=None):
2736 return baseset()
2739 return baseset()
2737
2740
2738 return mfunc
2741 return mfunc
2739 if not all(specs):
2742 if not all(specs):
2740 raise error.ParseError(_(b"empty query"))
2743 raise error.ParseError(_(b"empty query"))
2741 if len(specs) == 1:
2744 if len(specs) == 1:
2742 tree = revsetlang.parse(specs[0], lookup)
2745 tree = revsetlang.parse(specs[0], lookup)
2743 else:
2746 else:
2744 tree = (
2747 tree = (
2745 b'or',
2748 b'or',
2746 (b'list',) + tuple(revsetlang.parse(s, lookup) for s in specs),
2749 (b'list',) + tuple(revsetlang.parse(s, lookup) for s in specs),
2747 )
2750 )
2748
2751
2749 aliases = []
2752 aliases = []
2750 warn = None
2753 warn = None
2751 if ui:
2754 if ui:
2752 aliases.extend(ui.configitems(b'revsetalias'))
2755 aliases.extend(ui.configitems(b'revsetalias'))
2753 warn = ui.warn
2756 warn = ui.warn
2754 if localalias:
2757 if localalias:
2755 aliases.extend(localalias.items())
2758 aliases.extend(localalias.items())
2756 if aliases:
2759 if aliases:
2757 tree = revsetlang.expandaliases(tree, aliases, warn=warn)
2760 tree = revsetlang.expandaliases(tree, aliases, warn=warn)
2758 tree = revsetlang.foldconcat(tree)
2761 tree = revsetlang.foldconcat(tree)
2759 tree = revsetlang.analyze(tree)
2762 tree = revsetlang.analyze(tree)
2760 tree = revsetlang.optimize(tree)
2763 tree = revsetlang.optimize(tree)
2761 return makematcher(tree)
2764 return makematcher(tree)
2762
2765
2763
2766
2764 def makematcher(tree):
2767 def makematcher(tree):
2765 """Create a matcher from an evaluatable tree"""
2768 """Create a matcher from an evaluatable tree"""
2766
2769
2767 def mfunc(repo, subset=None, order=None):
2770 def mfunc(repo, subset=None, order=None):
2768 if order is None:
2771 if order is None:
2769 if subset is None:
2772 if subset is None:
2770 order = defineorder # 'x'
2773 order = defineorder # 'x'
2771 else:
2774 else:
2772 order = followorder # 'subset & x'
2775 order = followorder # 'subset & x'
2773 if subset is None:
2776 if subset is None:
2774 subset = fullreposet(repo)
2777 subset = fullreposet(repo)
2775 return getset(repo, subset, tree, order)
2778 return getset(repo, subset, tree, order)
2776
2779
2777 return mfunc
2780 return mfunc
2778
2781
2779
2782
2780 def loadpredicate(ui, extname, registrarobj):
2783 def loadpredicate(ui, extname, registrarobj):
2781 """Load revset predicates from specified registrarobj
2784 """Load revset predicates from specified registrarobj
2782 """
2785 """
2783 for name, func in pycompat.iteritems(registrarobj._table):
2786 for name, func in pycompat.iteritems(registrarobj._table):
2784 symbols[name] = func
2787 symbols[name] = func
2785 if func._safe:
2788 if func._safe:
2786 safesymbols.add(name)
2789 safesymbols.add(name)
2787
2790
2788
2791
2789 # load built-in predicates explicitly to setup safesymbols
2792 # load built-in predicates explicitly to setup safesymbols
2790 loadpredicate(None, None, predicate)
2793 loadpredicate(None, None, predicate)
2791
2794
2792 # tell hggettext to extract docstrings from these functions:
2795 # tell hggettext to extract docstrings from these functions:
2793 i18nfunctions = symbols.values()
2796 i18nfunctions = symbols.values()
@@ -1,26 +1,29 b''
1 == New Features ==
1 == New Features ==
2
2
3 * `hg mv -A` can now be used with `--at-rev`. It behaves just like
3 * `hg mv -A` can now be used with `--at-rev`. It behaves just like
4 `hg cp -A --at-rev`, i.e. it marks the destination as a copy of the
4 `hg cp -A --at-rev`, i.e. it marks the destination as a copy of the
5 source whether or not the source still exists (but the source must
5 source whether or not the source still exists (but the source must
6 exist in the parent revision).
6 exist in the parent revision).
7
7
8 * New revset predicate `diffcontains(pattern)` for filtering revisions
9 in the same way as `hg grep --diff pattern`.
10
8
11
9 == New Experimental Features ==
12 == New Experimental Features ==
10
13
11
14
12
15
13 == Bug Fixes ==
16 == Bug Fixes ==
14
17
15
18
16
19
17 == Backwards Compatibility Changes ==
20 == Backwards Compatibility Changes ==
18
21
19
22
20
23
21 == Internal API Changes ==
24 == Internal API Changes ==
22
25
23 * `merge.update()` is now private (renamed to `_update()`). Hopefully
26 * `merge.update()` is now private (renamed to `_update()`). Hopefully
24 the higher-level functions available in the same module cover your
27 the higher-level functions available in the same module cover your
25 use cases.
28 use cases.
26
29
@@ -1,108 +1,108 b''
1 ROOT = CWD + "/../.."
1 ROOT = CWD + "/../.."
2
2
3 IS_WINDOWS = "windows" in BUILD_TARGET_TRIPLE
3 IS_WINDOWS = "windows" in BUILD_TARGET_TRIPLE
4
4
5 # Code to run in Python interpreter.
5 # Code to run in Python interpreter.
6 RUN_CODE = "import hgdemandimport; hgdemandimport.enable(); from mercurial import dispatch; dispatch.run()"
6 RUN_CODE = "import hgdemandimport; hgdemandimport.enable(); from mercurial import dispatch; dispatch.run()"
7
7
8 set_build_path(ROOT + "/build/pyoxidizer")
8 set_build_path(ROOT + "/build/pyoxidizer")
9
9
10 def make_distribution():
10 def make_distribution():
11 return default_python_distribution()
11 return default_python_distribution()
12
12
13 def make_distribution_windows():
13 def make_distribution_windows():
14 return default_python_distribution(flavor = "standalone_dynamic")
14 return default_python_distribution(flavor = "standalone_dynamic")
15
15
16 def resource_callback(policy, resource):
16 def resource_callback(policy, resource):
17 # We use a custom resource routing policy to influence where things are loaded
17 # We use a custom resource routing policy to influence where things are loaded
18 # from.
18 # from.
19 #
19 #
20 # For Python modules and resources, we load from memory if they are in
20 # For Python modules and resources, we load from memory if they are in
21 # the standard library and from the filesystem if not. This is because
21 # the standard library and from the filesystem if not. This is because
22 # parts of Mercurial and some 3rd party packages aren't yet compatible
22 # parts of Mercurial and some 3rd party packages aren't yet compatible
23 # with memory loading.
23 # with memory loading.
24 #
24 #
25 # For Python extension modules, we load from the filesystem because
25 # For Python extension modules, we load from the filesystem because
26 # this yields greatest compatibility.
26 # this yields greatest compatibility.
27 if type(resource) in ("PythonModuleSource", "PythonPackageResource", "PythonPackageDistributionResource"):
27 if type(resource) in ("PythonModuleSource", "PythonPackageResource", "PythonPackageDistributionResource"):
28 if resource.is_stdlib:
28 if resource.is_stdlib:
29 resource.add_location = "in-memory"
29 resource.add_location = "in-memory"
30 else:
30 else:
31 resource.add_location = "filesystem-relative:lib"
31 resource.add_location = "filesystem-relative:lib"
32
32
33 elif type(resource) == "PythonExtensionModule":
33 elif type(resource) == "PythonExtensionModule":
34 resource.add_location = "filesystem-relative:lib"
34 resource.add_location = "filesystem-relative:lib"
35
35
36 def make_exe(dist):
36 def make_exe(dist):
37 """Builds a Rust-wrapped Mercurial binary."""
37 """Builds a Rust-wrapped Mercurial binary."""
38 packaging_policy = dist.make_python_packaging_policy()
38 packaging_policy = dist.make_python_packaging_policy()
39 # Extension may depend on any Python functionality. Include all
39 # Extension may depend on any Python functionality. Include all
40 # extensions.
40 # extensions.
41 packaging_policy.extension_module_filter = "all"
41 packaging_policy.extension_module_filter = "all"
42 packaging_policy.resources_policy = "prefer-in-memory-fallback-filesystem-relative:lib"
42 packaging_policy.resources_location = "in-memory"
43 packaging_policy.resources_location_fallback = "filesystem-relative:lib"
43 packaging_policy.register_resource_callback(resource_callback)
44 packaging_policy.register_resource_callback(resource_callback)
44
45
45 config = PythonInterpreterConfig(
46 config = dist.make_python_interpreter_config()
46 raw_allocator = "system",
47 config.raw_allocator = "system"
47 run_eval = RUN_CODE,
48 config.run_mode = "eval:%s" % RUN_CODE
48 # We want to let the user load extensions from the file system
49 # We want to let the user load extensions from the file system
49 filesystem_importer = True,
50 config.filesystem_importer = True
50 # We need this to make resourceutil happy, since it looks for sys.frozen.
51 # We need this to make resourceutil happy, since it looks for sys.frozen.
51 sys_frozen = True,
52 config.sys_frozen = True
52 legacy_windows_stdio = True,
53 config.legacy_windows_stdio = True
53 )
54
54
55 exe = dist.to_python_executable(
55 exe = dist.to_python_executable(
56 name = "hg",
56 name = "hg",
57 packaging_policy = packaging_policy,
57 packaging_policy = packaging_policy,
58 config = config,
58 config = config,
59 )
59 )
60
60
61 # Add Mercurial to resources.
61 # Add Mercurial to resources.
62 exe.add_python_resources(exe.pip_install(["--verbose", ROOT]))
62 exe.add_python_resources(exe.pip_install(["--verbose", ROOT]))
63
63
64 # On Windows, we install extra packages for convenience.
64 # On Windows, we install extra packages for convenience.
65 if IS_WINDOWS:
65 if IS_WINDOWS:
66 exe.add_python_resources(
66 exe.add_python_resources(
67 exe.pip_install(["-r", ROOT + "/contrib/packaging/requirements_win32.txt"]),
67 exe.pip_install(["-r", ROOT + "/contrib/packaging/requirements-windows-py2.txt"]),
68 )
68 )
69
69
70 return exe
70 return exe
71
71
72 def make_manifest(dist, exe):
72 def make_manifest(dist, exe):
73 m = FileManifest()
73 m = FileManifest()
74 m.add_python_resource(".", exe)
74 m.add_python_resource(".", exe)
75
75
76 return m
76 return m
77
77
78 def make_embedded_resources(exe):
78 def make_embedded_resources(exe):
79 return exe.to_embedded_resources()
79 return exe.to_embedded_resources()
80
80
81 register_target("distribution_posix", make_distribution)
81 register_target("distribution_posix", make_distribution)
82 register_target("distribution_windows", make_distribution_windows)
82 register_target("distribution_windows", make_distribution_windows)
83
83
84 register_target("exe_posix", make_exe, depends = ["distribution_posix"])
84 register_target("exe_posix", make_exe, depends = ["distribution_posix"])
85 register_target("exe_windows", make_exe, depends = ["distribution_windows"])
85 register_target("exe_windows", make_exe, depends = ["distribution_windows"])
86
86
87 register_target(
87 register_target(
88 "app_posix",
88 "app_posix",
89 make_manifest,
89 make_manifest,
90 depends = ["distribution_posix", "exe_posix"],
90 depends = ["distribution_posix", "exe_posix"],
91 default = "windows" not in BUILD_TARGET_TRIPLE,
91 default = "windows" not in BUILD_TARGET_TRIPLE,
92 )
92 )
93 register_target(
93 register_target(
94 "app_windows",
94 "app_windows",
95 make_manifest,
95 make_manifest,
96 depends = ["distribution_windows", "exe_windows"],
96 depends = ["distribution_windows", "exe_windows"],
97 default = "windows" in BUILD_TARGET_TRIPLE,
97 default = "windows" in BUILD_TARGET_TRIPLE,
98 )
98 )
99
99
100 resolve_targets()
100 resolve_targets()
101
101
102 # END OF COMMON USER-ADJUSTED SETTINGS.
102 # END OF COMMON USER-ADJUSTED SETTINGS.
103 #
103 #
104 # Everything below this is typically managed by PyOxidizer and doesn't need
104 # Everything below this is typically managed by PyOxidizer and doesn't need
105 # to be updated by people.
105 # to be updated by people.
106
106
107 PYOXIDIZER_VERSION = "0.8.0-pre"
107 PYOXIDIZER_VERSION = "0.9.0"
108 PYOXIDIZER_COMMIT = "4697fb25918dfad6dc73288daeea501063963a08"
108 PYOXIDIZER_COMMIT = "1fbc264cc004226cd76ee452e0a386ffca6ccfb1"
@@ -1,1464 +1,1464 b''
1 $ hg init t
1 $ hg init t
2 $ cd t
2 $ cd t
3 $ echo import > port
3 $ echo import > port
4 $ hg add port
4 $ hg add port
5 $ hg commit -m 0 -u spam -d '0 0'
5 $ hg commit -m 0 -u spam -d '0 0'
6 $ echo export >> port
6 $ echo export >> port
7 $ hg commit -m 1 -u eggs -d '1 0'
7 $ hg commit -m 1 -u eggs -d '1 0'
8 $ echo export > port
8 $ echo export > port
9 $ echo vaportight >> port
9 $ echo vaportight >> port
10 $ echo 'import/export' >> port
10 $ echo 'import/export' >> port
11 $ hg commit -m 2 -u spam -d '2 0'
11 $ hg commit -m 2 -u spam -d '2 0'
12 $ echo 'import/export' >> port
12 $ echo 'import/export' >> port
13 $ hg commit -m 3 -u eggs -d '3 0'
13 $ hg commit -m 3 -u eggs -d '3 0'
14 $ head -n 3 port > port1
14 $ head -n 3 port > port1
15 $ mv port1 port
15 $ mv port1 port
16 $ hg commit -m 4 -u spam -d '4 0'
16 $ hg commit -m 4 -u spam -d '4 0'
17
17
18 pattern error
18 pattern error
19
19
20 $ hg grep '**test**'
20 $ hg grep '**test**'
21 grep: invalid match pattern: nothing to repeat* (glob)
21 grep: invalid match pattern: nothing to repeat* (glob)
22 [1]
22 [1]
23
23
24 invalid revset syntax
24 invalid revset syntax
25
25
26 $ hg log -r 'diff()'
26 $ hg log -r 'diffcontains()'
27 hg: parse error: diff takes at least 1 argument
27 hg: parse error: diffcontains takes at least 1 argument
28 [255]
28 [255]
29 $ hg log -r 'diff(:)'
29 $ hg log -r 'diffcontains(:)'
30 hg: parse error: diff requires a string pattern
30 hg: parse error: diffcontains requires a string pattern
31 [255]
31 [255]
32 $ hg log -r 'diff("re:**test**")'
32 $ hg log -r 'diffcontains("re:**test**")'
33 hg: parse error: invalid regular expression: nothing to repeat* (glob)
33 hg: parse error: invalid regular expression: nothing to repeat* (glob)
34 [255]
34 [255]
35
35
36 simple
36 simple
37
37
38 $ hg grep -r tip:0 '.*'
38 $ hg grep -r tip:0 '.*'
39 port:4:export
39 port:4:export
40 port:4:vaportight
40 port:4:vaportight
41 port:4:import/export
41 port:4:import/export
42 port:3:export
42 port:3:export
43 port:3:vaportight
43 port:3:vaportight
44 port:3:import/export
44 port:3:import/export
45 port:3:import/export
45 port:3:import/export
46 port:2:export
46 port:2:export
47 port:2:vaportight
47 port:2:vaportight
48 port:2:import/export
48 port:2:import/export
49 port:1:import
49 port:1:import
50 port:1:export
50 port:1:export
51 port:0:import
51 port:0:import
52 $ hg grep -r tip:0 port port
52 $ hg grep -r tip:0 port port
53 port:4:export
53 port:4:export
54 port:4:vaportight
54 port:4:vaportight
55 port:4:import/export
55 port:4:import/export
56 port:3:export
56 port:3:export
57 port:3:vaportight
57 port:3:vaportight
58 port:3:import/export
58 port:3:import/export
59 port:3:import/export
59 port:3:import/export
60 port:2:export
60 port:2:export
61 port:2:vaportight
61 port:2:vaportight
62 port:2:import/export
62 port:2:import/export
63 port:1:import
63 port:1:import
64 port:1:export
64 port:1:export
65 port:0:import
65 port:0:import
66
66
67 simple from subdirectory
67 simple from subdirectory
68
68
69 $ mkdir dir
69 $ mkdir dir
70 $ cd dir
70 $ cd dir
71 $ hg grep -r tip:0 port
71 $ hg grep -r tip:0 port
72 port:4:export
72 port:4:export
73 port:4:vaportight
73 port:4:vaportight
74 port:4:import/export
74 port:4:import/export
75 port:3:export
75 port:3:export
76 port:3:vaportight
76 port:3:vaportight
77 port:3:import/export
77 port:3:import/export
78 port:3:import/export
78 port:3:import/export
79 port:2:export
79 port:2:export
80 port:2:vaportight
80 port:2:vaportight
81 port:2:import/export
81 port:2:import/export
82 port:1:import
82 port:1:import
83 port:1:export
83 port:1:export
84 port:0:import
84 port:0:import
85 $ hg grep -r tip:0 port --config ui.relative-paths=yes
85 $ hg grep -r tip:0 port --config ui.relative-paths=yes
86 ../port:4:export
86 ../port:4:export
87 ../port:4:vaportight
87 ../port:4:vaportight
88 ../port:4:import/export
88 ../port:4:import/export
89 ../port:3:export
89 ../port:3:export
90 ../port:3:vaportight
90 ../port:3:vaportight
91 ../port:3:import/export
91 ../port:3:import/export
92 ../port:3:import/export
92 ../port:3:import/export
93 ../port:2:export
93 ../port:2:export
94 ../port:2:vaportight
94 ../port:2:vaportight
95 ../port:2:import/export
95 ../port:2:import/export
96 ../port:1:import
96 ../port:1:import
97 ../port:1:export
97 ../port:1:export
98 ../port:0:import
98 ../port:0:import
99 $ cd ..
99 $ cd ..
100
100
101 simple with color
101 simple with color
102
102
103 $ hg --config extensions.color= grep --config color.mode=ansi \
103 $ hg --config extensions.color= grep --config color.mode=ansi \
104 > --color=always port port -r tip:0
104 > --color=always port port -r tip:0
105 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
105 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
106 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
106 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
107 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
107 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
108 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
108 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
109 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
109 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
110 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
110 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
111 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
111 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
112 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
112 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
113 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
113 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
114 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
114 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
115 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m (esc)
115 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m (esc)
116 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
116 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
117 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m0\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m (esc)
117 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m0\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m (esc)
118
118
119 simple templated
119 simple templated
120
120
121 $ hg grep port -r tip:0 \
121 $ hg grep port -r tip:0 \
122 > -T '{path}:{rev}:{node|short}:{texts % "{if(matched, text|upper, text)}"}\n'
122 > -T '{path}:{rev}:{node|short}:{texts % "{if(matched, text|upper, text)}"}\n'
123 port:4:914fa752cdea:exPORT
123 port:4:914fa752cdea:exPORT
124 port:4:914fa752cdea:vaPORTight
124 port:4:914fa752cdea:vaPORTight
125 port:4:914fa752cdea:imPORT/exPORT
125 port:4:914fa752cdea:imPORT/exPORT
126 port:3:95040cfd017d:exPORT
126 port:3:95040cfd017d:exPORT
127 port:3:95040cfd017d:vaPORTight
127 port:3:95040cfd017d:vaPORTight
128 port:3:95040cfd017d:imPORT/exPORT
128 port:3:95040cfd017d:imPORT/exPORT
129 port:3:95040cfd017d:imPORT/exPORT
129 port:3:95040cfd017d:imPORT/exPORT
130 port:2:3b325e3481a1:exPORT
130 port:2:3b325e3481a1:exPORT
131 port:2:3b325e3481a1:vaPORTight
131 port:2:3b325e3481a1:vaPORTight
132 port:2:3b325e3481a1:imPORT/exPORT
132 port:2:3b325e3481a1:imPORT/exPORT
133 port:1:8b20f75c1585:imPORT
133 port:1:8b20f75c1585:imPORT
134 port:1:8b20f75c1585:exPORT
134 port:1:8b20f75c1585:exPORT
135 port:0:f31323c92170:imPORT
135 port:0:f31323c92170:imPORT
136
136
137 $ hg grep port -r tip:0 -T '{path}:{rev}:{texts}\n'
137 $ hg grep port -r tip:0 -T '{path}:{rev}:{texts}\n'
138 port:4:export
138 port:4:export
139 port:4:vaportight
139 port:4:vaportight
140 port:4:import/export
140 port:4:import/export
141 port:3:export
141 port:3:export
142 port:3:vaportight
142 port:3:vaportight
143 port:3:import/export
143 port:3:import/export
144 port:3:import/export
144 port:3:import/export
145 port:2:export
145 port:2:export
146 port:2:vaportight
146 port:2:vaportight
147 port:2:import/export
147 port:2:import/export
148 port:1:import
148 port:1:import
149 port:1:export
149 port:1:export
150 port:0:import
150 port:0:import
151
151
152 $ hg grep port -r tip:0 -T '{path}:{tags}:{texts}\n'
152 $ hg grep port -r tip:0 -T '{path}:{tags}:{texts}\n'
153 port:tip:export
153 port:tip:export
154 port:tip:vaportight
154 port:tip:vaportight
155 port:tip:import/export
155 port:tip:import/export
156 port::export
156 port::export
157 port::vaportight
157 port::vaportight
158 port::import/export
158 port::import/export
159 port::import/export
159 port::import/export
160 port::export
160 port::export
161 port::vaportight
161 port::vaportight
162 port::import/export
162 port::import/export
163 port::import
163 port::import
164 port::export
164 port::export
165 port::import
165 port::import
166
166
167 simple JSON (no "change" field)
167 simple JSON (no "change" field)
168
168
169 $ hg grep -r tip:0 -Tjson port
169 $ hg grep -r tip:0 -Tjson port
170 [
170 [
171 {
171 {
172 "date": [4, 0],
172 "date": [4, 0],
173 "lineno": 1,
173 "lineno": 1,
174 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
174 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
175 "path": "port",
175 "path": "port",
176 "rev": 4,
176 "rev": 4,
177 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
177 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
178 "user": "spam"
178 "user": "spam"
179 },
179 },
180 {
180 {
181 "date": [4, 0],
181 "date": [4, 0],
182 "lineno": 2,
182 "lineno": 2,
183 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
183 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
184 "path": "port",
184 "path": "port",
185 "rev": 4,
185 "rev": 4,
186 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
186 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
187 "user": "spam"
187 "user": "spam"
188 },
188 },
189 {
189 {
190 "date": [4, 0],
190 "date": [4, 0],
191 "lineno": 3,
191 "lineno": 3,
192 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
192 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
193 "path": "port",
193 "path": "port",
194 "rev": 4,
194 "rev": 4,
195 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
195 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
196 "user": "spam"
196 "user": "spam"
197 },
197 },
198 {
198 {
199 "date": [3, 0],
199 "date": [3, 0],
200 "lineno": 1,
200 "lineno": 1,
201 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
201 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
202 "path": "port",
202 "path": "port",
203 "rev": 3,
203 "rev": 3,
204 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
204 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
205 "user": "eggs"
205 "user": "eggs"
206 },
206 },
207 {
207 {
208 "date": [3, 0],
208 "date": [3, 0],
209 "lineno": 2,
209 "lineno": 2,
210 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
210 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
211 "path": "port",
211 "path": "port",
212 "rev": 3,
212 "rev": 3,
213 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
213 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
214 "user": "eggs"
214 "user": "eggs"
215 },
215 },
216 {
216 {
217 "date": [3, 0],
217 "date": [3, 0],
218 "lineno": 3,
218 "lineno": 3,
219 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
219 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
220 "path": "port",
220 "path": "port",
221 "rev": 3,
221 "rev": 3,
222 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
222 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
223 "user": "eggs"
223 "user": "eggs"
224 },
224 },
225 {
225 {
226 "date": [3, 0],
226 "date": [3, 0],
227 "lineno": 4,
227 "lineno": 4,
228 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
228 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
229 "path": "port",
229 "path": "port",
230 "rev": 3,
230 "rev": 3,
231 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
231 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
232 "user": "eggs"
232 "user": "eggs"
233 },
233 },
234 {
234 {
235 "date": [2, 0],
235 "date": [2, 0],
236 "lineno": 1,
236 "lineno": 1,
237 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
237 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
238 "path": "port",
238 "path": "port",
239 "rev": 2,
239 "rev": 2,
240 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
240 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
241 "user": "spam"
241 "user": "spam"
242 },
242 },
243 {
243 {
244 "date": [2, 0],
244 "date": [2, 0],
245 "lineno": 2,
245 "lineno": 2,
246 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
246 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
247 "path": "port",
247 "path": "port",
248 "rev": 2,
248 "rev": 2,
249 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
249 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
250 "user": "spam"
250 "user": "spam"
251 },
251 },
252 {
252 {
253 "date": [2, 0],
253 "date": [2, 0],
254 "lineno": 3,
254 "lineno": 3,
255 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
255 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
256 "path": "port",
256 "path": "port",
257 "rev": 2,
257 "rev": 2,
258 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
258 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
259 "user": "spam"
259 "user": "spam"
260 },
260 },
261 {
261 {
262 "date": [1, 0],
262 "date": [1, 0],
263 "lineno": 1,
263 "lineno": 1,
264 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
264 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
265 "path": "port",
265 "path": "port",
266 "rev": 1,
266 "rev": 1,
267 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
267 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
268 "user": "eggs"
268 "user": "eggs"
269 },
269 },
270 {
270 {
271 "date": [1, 0],
271 "date": [1, 0],
272 "lineno": 2,
272 "lineno": 2,
273 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
273 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
274 "path": "port",
274 "path": "port",
275 "rev": 1,
275 "rev": 1,
276 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
276 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
277 "user": "eggs"
277 "user": "eggs"
278 },
278 },
279 {
279 {
280 "date": [0, 0],
280 "date": [0, 0],
281 "lineno": 1,
281 "lineno": 1,
282 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
282 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
283 "path": "port",
283 "path": "port",
284 "rev": 0,
284 "rev": 0,
285 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
285 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
286 "user": "spam"
286 "user": "spam"
287 }
287 }
288 ]
288 ]
289
289
290 simple JSON without matching lines
290 simple JSON without matching lines
291
291
292 $ hg grep -r tip:0 -Tjson -l port
292 $ hg grep -r tip:0 -Tjson -l port
293 [
293 [
294 {
294 {
295 "date": [4, 0],
295 "date": [4, 0],
296 "lineno": 1,
296 "lineno": 1,
297 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
297 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
298 "path": "port",
298 "path": "port",
299 "rev": 4,
299 "rev": 4,
300 "user": "spam"
300 "user": "spam"
301 },
301 },
302 {
302 {
303 "date": [3, 0],
303 "date": [3, 0],
304 "lineno": 1,
304 "lineno": 1,
305 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
305 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
306 "path": "port",
306 "path": "port",
307 "rev": 3,
307 "rev": 3,
308 "user": "eggs"
308 "user": "eggs"
309 },
309 },
310 {
310 {
311 "date": [2, 0],
311 "date": [2, 0],
312 "lineno": 1,
312 "lineno": 1,
313 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
313 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
314 "path": "port",
314 "path": "port",
315 "rev": 2,
315 "rev": 2,
316 "user": "spam"
316 "user": "spam"
317 },
317 },
318 {
318 {
319 "date": [1, 0],
319 "date": [1, 0],
320 "lineno": 1,
320 "lineno": 1,
321 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
321 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
322 "path": "port",
322 "path": "port",
323 "rev": 1,
323 "rev": 1,
324 "user": "eggs"
324 "user": "eggs"
325 },
325 },
326 {
326 {
327 "date": [0, 0],
327 "date": [0, 0],
328 "lineno": 1,
328 "lineno": 1,
329 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
329 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
330 "path": "port",
330 "path": "port",
331 "rev": 0,
331 "rev": 0,
332 "user": "spam"
332 "user": "spam"
333 }
333 }
334 ]
334 ]
335
335
336 diff of each revision for reference
336 diff of each revision for reference
337
337
338 $ hg log -p -T'== rev: {rev} ==\n'
338 $ hg log -p -T'== rev: {rev} ==\n'
339 == rev: 4 ==
339 == rev: 4 ==
340 diff -r 95040cfd017d -r 914fa752cdea port
340 diff -r 95040cfd017d -r 914fa752cdea port
341 --- a/port Thu Jan 01 00:00:03 1970 +0000
341 --- a/port Thu Jan 01 00:00:03 1970 +0000
342 +++ b/port Thu Jan 01 00:00:04 1970 +0000
342 +++ b/port Thu Jan 01 00:00:04 1970 +0000
343 @@ -1,4 +1,3 @@
343 @@ -1,4 +1,3 @@
344 export
344 export
345 vaportight
345 vaportight
346 import/export
346 import/export
347 -import/export
347 -import/export
348
348
349 == rev: 3 ==
349 == rev: 3 ==
350 diff -r 3b325e3481a1 -r 95040cfd017d port
350 diff -r 3b325e3481a1 -r 95040cfd017d port
351 --- a/port Thu Jan 01 00:00:02 1970 +0000
351 --- a/port Thu Jan 01 00:00:02 1970 +0000
352 +++ b/port Thu Jan 01 00:00:03 1970 +0000
352 +++ b/port Thu Jan 01 00:00:03 1970 +0000
353 @@ -1,3 +1,4 @@
353 @@ -1,3 +1,4 @@
354 export
354 export
355 vaportight
355 vaportight
356 import/export
356 import/export
357 +import/export
357 +import/export
358
358
359 == rev: 2 ==
359 == rev: 2 ==
360 diff -r 8b20f75c1585 -r 3b325e3481a1 port
360 diff -r 8b20f75c1585 -r 3b325e3481a1 port
361 --- a/port Thu Jan 01 00:00:01 1970 +0000
361 --- a/port Thu Jan 01 00:00:01 1970 +0000
362 +++ b/port Thu Jan 01 00:00:02 1970 +0000
362 +++ b/port Thu Jan 01 00:00:02 1970 +0000
363 @@ -1,2 +1,3 @@
363 @@ -1,2 +1,3 @@
364 -import
364 -import
365 export
365 export
366 +vaportight
366 +vaportight
367 +import/export
367 +import/export
368
368
369 == rev: 1 ==
369 == rev: 1 ==
370 diff -r f31323c92170 -r 8b20f75c1585 port
370 diff -r f31323c92170 -r 8b20f75c1585 port
371 --- a/port Thu Jan 01 00:00:00 1970 +0000
371 --- a/port Thu Jan 01 00:00:00 1970 +0000
372 +++ b/port Thu Jan 01 00:00:01 1970 +0000
372 +++ b/port Thu Jan 01 00:00:01 1970 +0000
373 @@ -1,1 +1,2 @@
373 @@ -1,1 +1,2 @@
374 import
374 import
375 +export
375 +export
376
376
377 == rev: 0 ==
377 == rev: 0 ==
378 diff -r 000000000000 -r f31323c92170 port
378 diff -r 000000000000 -r f31323c92170 port
379 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
379 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
380 +++ b/port Thu Jan 01 00:00:00 1970 +0000
380 +++ b/port Thu Jan 01 00:00:00 1970 +0000
381 @@ -0,0 +1,1 @@
381 @@ -0,0 +1,1 @@
382 +import
382 +import
383
383
384
384
385 all
385 all
386
386
387 $ hg grep --traceback --all -nu port port
387 $ hg grep --traceback --all -nu port port
388 port:4:4:-:spam:import/export
388 port:4:4:-:spam:import/export
389 port:3:4:+:eggs:import/export
389 port:3:4:+:eggs:import/export
390 port:2:1:-:spam:import
390 port:2:1:-:spam:import
391 port:2:2:+:spam:vaportight
391 port:2:2:+:spam:vaportight
392 port:2:3:+:spam:import/export
392 port:2:3:+:spam:import/export
393 port:1:2:+:eggs:export
393 port:1:2:+:eggs:export
394 port:0:1:+:spam:import
394 port:0:1:+:spam:import
395
395
396 all JSON
396 all JSON
397
397
398 $ hg grep --all -Tjson port port
398 $ hg grep --all -Tjson port port
399 [
399 [
400 {
400 {
401 "change": "-",
401 "change": "-",
402 "date": [4, 0],
402 "date": [4, 0],
403 "lineno": 4,
403 "lineno": 4,
404 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
404 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
405 "path": "port",
405 "path": "port",
406 "rev": 4,
406 "rev": 4,
407 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
407 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
408 "user": "spam"
408 "user": "spam"
409 },
409 },
410 {
410 {
411 "change": "+",
411 "change": "+",
412 "date": [3, 0],
412 "date": [3, 0],
413 "lineno": 4,
413 "lineno": 4,
414 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
414 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
415 "path": "port",
415 "path": "port",
416 "rev": 3,
416 "rev": 3,
417 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
417 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
418 "user": "eggs"
418 "user": "eggs"
419 },
419 },
420 {
420 {
421 "change": "-",
421 "change": "-",
422 "date": [2, 0],
422 "date": [2, 0],
423 "lineno": 1,
423 "lineno": 1,
424 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
424 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
425 "path": "port",
425 "path": "port",
426 "rev": 2,
426 "rev": 2,
427 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
427 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
428 "user": "spam"
428 "user": "spam"
429 },
429 },
430 {
430 {
431 "change": "+",
431 "change": "+",
432 "date": [2, 0],
432 "date": [2, 0],
433 "lineno": 2,
433 "lineno": 2,
434 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
434 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
435 "path": "port",
435 "path": "port",
436 "rev": 2,
436 "rev": 2,
437 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
437 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
438 "user": "spam"
438 "user": "spam"
439 },
439 },
440 {
440 {
441 "change": "+",
441 "change": "+",
442 "date": [2, 0],
442 "date": [2, 0],
443 "lineno": 3,
443 "lineno": 3,
444 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
444 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
445 "path": "port",
445 "path": "port",
446 "rev": 2,
446 "rev": 2,
447 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
447 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
448 "user": "spam"
448 "user": "spam"
449 },
449 },
450 {
450 {
451 "change": "+",
451 "change": "+",
452 "date": [1, 0],
452 "date": [1, 0],
453 "lineno": 2,
453 "lineno": 2,
454 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
454 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
455 "path": "port",
455 "path": "port",
456 "rev": 1,
456 "rev": 1,
457 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
457 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
458 "user": "eggs"
458 "user": "eggs"
459 },
459 },
460 {
460 {
461 "change": "+",
461 "change": "+",
462 "date": [0, 0],
462 "date": [0, 0],
463 "lineno": 1,
463 "lineno": 1,
464 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
464 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
465 "path": "port",
465 "path": "port",
466 "rev": 0,
466 "rev": 0,
467 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
467 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
468 "user": "spam"
468 "user": "spam"
469 }
469 }
470 ]
470 ]
471
471
472 other
472 other
473
473
474 $ hg grep -r tip:0 -l port port
474 $ hg grep -r tip:0 -l port port
475 port:4
475 port:4
476 port:3
476 port:3
477 port:2
477 port:2
478 port:1
478 port:1
479 port:0
479 port:0
480 $ hg grep -r tip:0 import port
480 $ hg grep -r tip:0 import port
481 port:4:import/export
481 port:4:import/export
482 port:3:import/export
482 port:3:import/export
483 port:3:import/export
483 port:3:import/export
484 port:2:import/export
484 port:2:import/export
485 port:1:import
485 port:1:import
486 port:0:import
486 port:0:import
487
487
488 $ hg cp port port2
488 $ hg cp port port2
489 $ hg commit -m 4 -u spam -d '5 0'
489 $ hg commit -m 4 -u spam -d '5 0'
490
490
491 follow
491 follow
492
492
493 $ hg grep -r tip:0 --traceback -f 'import\n\Z' port2
493 $ hg grep -r tip:0 --traceback -f 'import\n\Z' port2
494 [1]
494 [1]
495 $ echo deport >> port2
495 $ echo deport >> port2
496 $ hg commit -m 5 -u eggs -d '6 0'
496 $ hg commit -m 5 -u eggs -d '6 0'
497 $ hg grep -f --all -nu port port2
497 $ hg grep -f --all -nu port port2
498 port2:6:4:+:eggs:deport
498 port2:6:4:+:eggs:deport
499 port:4:4:-:spam:import/export
499 port:4:4:-:spam:import/export
500 port:3:4:+:eggs:import/export
500 port:3:4:+:eggs:import/export
501 port:2:1:-:spam:import
501 port:2:1:-:spam:import
502 port:2:2:+:spam:vaportight
502 port:2:2:+:spam:vaportight
503 port:2:3:+:spam:import/export
503 port:2:3:+:spam:import/export
504 port:1:2:+:eggs:export
504 port:1:2:+:eggs:export
505 port:0:1:+:spam:import
505 port:0:1:+:spam:import
506
506
507 $ hg up -q null
507 $ hg up -q null
508 $ hg grep -r 'reverse(:.)' -f port
508 $ hg grep -r 'reverse(:.)' -f port
509 port:0:import
509 port:0:import
510
510
511 Test wdir
511 Test wdir
512 (at least, this shouldn't crash)
512 (at least, this shouldn't crash)
513
513
514 $ hg up -q
514 $ hg up -q
515 $ echo wport >> port2
515 $ echo wport >> port2
516 $ hg stat
516 $ hg stat
517 M port2
517 M port2
518 $ hg grep -r 'wdir()' port
518 $ hg grep -r 'wdir()' port
519 port:2147483647:export
519 port:2147483647:export
520 port:2147483647:vaportight
520 port:2147483647:vaportight
521 port:2147483647:import/export
521 port:2147483647:import/export
522 port2:2147483647:export
522 port2:2147483647:export
523 port2:2147483647:vaportight
523 port2:2147483647:vaportight
524 port2:2147483647:import/export
524 port2:2147483647:import/export
525 port2:2147483647:deport
525 port2:2147483647:deport
526 port2:2147483647:wport
526 port2:2147483647:wport
527
527
528 $ cd ..
528 $ cd ..
529 $ hg init t2
529 $ hg init t2
530 $ cd t2
530 $ cd t2
531 $ hg grep -r tip:0 foobar foo
531 $ hg grep -r tip:0 foobar foo
532 [1]
532 [1]
533 $ hg grep -r tip:0 foobar
533 $ hg grep -r tip:0 foobar
534 [1]
534 [1]
535 $ echo blue >> color
535 $ echo blue >> color
536 $ echo black >> color
536 $ echo black >> color
537 $ hg add color
537 $ hg add color
538 $ hg ci -m 0
538 $ hg ci -m 0
539 $ echo orange >> color
539 $ echo orange >> color
540 $ hg ci -m 1
540 $ hg ci -m 1
541 $ echo black > color
541 $ echo black > color
542 $ hg ci -m 2
542 $ hg ci -m 2
543 $ echo orange >> color
543 $ echo orange >> color
544 $ echo blue >> color
544 $ echo blue >> color
545 $ hg ci -m 3
545 $ hg ci -m 3
546 $ hg grep -r tip:0 orange
546 $ hg grep -r tip:0 orange
547 color:3:orange
547 color:3:orange
548 color:1:orange
548 color:1:orange
549 $ hg grep --all orange
549 $ hg grep --all orange
550 color:3:+:orange
550 color:3:+:orange
551 color:2:-:orange
551 color:2:-:orange
552 color:1:+:orange
552 color:1:+:orange
553 $ hg grep --diff orange --color=debug
553 $ hg grep --diff orange --color=debug
554 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
554 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
555 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.deleted grep.change|-][grep.sep|:][grep.match|orange]
555 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.deleted grep.change|-][grep.sep|:][grep.match|orange]
556 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
556 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
557
557
558 $ hg grep --diff orange --color=yes
558 $ hg grep --diff orange --color=yes
559 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
559 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
560 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1m-\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
560 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1m-\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
561 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
561 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
562
562
563 $ hg grep --diff orange
563 $ hg grep --diff orange
564 color:3:+:orange
564 color:3:+:orange
565 color:2:-:orange
565 color:2:-:orange
566 color:1:+:orange
566 color:1:+:orange
567
567
568 revset predicate for "grep --diff"
568 revset predicate for "grep --diff"
569
569
570 $ hg log -qr 'diff("re:^bl...$")'
570 $ hg log -qr 'diffcontains("re:^bl...$")'
571 0:203191eb5e21
571 0:203191eb5e21
572 $ hg log -qr 'diff("orange")'
572 $ hg log -qr 'diffcontains("orange")'
573 1:7c585a21e0d1
573 1:7c585a21e0d1
574 2:11bd8bc8d653
574 2:11bd8bc8d653
575 3:e0116d3829f8
575 3:e0116d3829f8
576 $ hg log -qr '2:0 & diff("orange")'
576 $ hg log -qr '2:0 & diffcontains("orange")'
577 2:11bd8bc8d653
577 2:11bd8bc8d653
578 1:7c585a21e0d1
578 1:7c585a21e0d1
579
579
580 test substring match: '^' should only match at the beginning
580 test substring match: '^' should only match at the beginning
581
581
582 $ hg grep -r tip:0 '^.' --config extensions.color= --color debug
582 $ hg grep -r tip:0 '^.' --config extensions.color= --color debug
583 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lack
583 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lack
584 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|o]range
584 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|o]range
585 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lue
585 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lue
586 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.match|b]lack
586 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.match|b]lack
587 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|b]lue
587 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|b]lue
588 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|b]lack
588 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|b]lack
589 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|o]range
589 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|o]range
590 [grep.filename|color][grep.sep|:][grep.rev|0][grep.sep|:][grep.match|b]lue
590 [grep.filename|color][grep.sep|:][grep.rev|0][grep.sep|:][grep.match|b]lue
591 [grep.filename|color][grep.sep|:][grep.rev|0][grep.sep|:][grep.match|b]lack
591 [grep.filename|color][grep.sep|:][grep.rev|0][grep.sep|:][grep.match|b]lack
592
592
593 match in last "line" without newline
593 match in last "line" without newline
594
594
595 $ "$PYTHON" -c 'fp = open("noeol", "wb"); fp.write(b"no infinite loop"); fp.close();'
595 $ "$PYTHON" -c 'fp = open("noeol", "wb"); fp.write(b"no infinite loop"); fp.close();'
596 $ hg ci -Amnoeol
596 $ hg ci -Amnoeol
597 adding noeol
597 adding noeol
598 $ hg grep -r tip:0 loop
598 $ hg grep -r tip:0 loop
599 noeol:4:no infinite loop
599 noeol:4:no infinite loop
600
600
601 $ cd ..
601 $ cd ..
602
602
603 Issue685: traceback in grep -r after rename
603 Issue685: traceback in grep -r after rename
604
604
605 Got a traceback when using grep on a single
605 Got a traceback when using grep on a single
606 revision with renamed files.
606 revision with renamed files.
607
607
608 $ hg init issue685
608 $ hg init issue685
609 $ cd issue685
609 $ cd issue685
610 $ echo octarine > color
610 $ echo octarine > color
611 $ hg ci -Amcolor
611 $ hg ci -Amcolor
612 adding color
612 adding color
613 $ hg rename color colour
613 $ hg rename color colour
614 $ hg ci -Am rename
614 $ hg ci -Am rename
615 $ hg grep -r tip:0 octarine
615 $ hg grep -r tip:0 octarine
616 colour:1:octarine
616 colour:1:octarine
617 color:0:octarine
617 color:0:octarine
618
618
619 Used to crash here
619 Used to crash here
620
620
621 $ hg grep -r 1 octarine
621 $ hg grep -r 1 octarine
622 colour:1:octarine
622 colour:1:octarine
623 $ cd ..
623 $ cd ..
624
624
625
625
626 Issue337: test that grep follows parent-child relationships instead
626 Issue337: test that grep follows parent-child relationships instead
627 of just using revision numbers.
627 of just using revision numbers.
628
628
629 $ hg init issue337
629 $ hg init issue337
630 $ cd issue337
630 $ cd issue337
631
631
632 $ echo white > color
632 $ echo white > color
633 $ hg commit -A -m "0 white"
633 $ hg commit -A -m "0 white"
634 adding color
634 adding color
635
635
636 $ echo red > color
636 $ echo red > color
637 $ hg commit -A -m "1 red"
637 $ hg commit -A -m "1 red"
638
638
639 $ hg update 0
639 $ hg update 0
640 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
640 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
641 $ echo black > color
641 $ echo black > color
642 $ hg commit -A -m "2 black"
642 $ hg commit -A -m "2 black"
643 created new head
643 created new head
644
644
645 $ hg update --clean 1
645 $ hg update --clean 1
646 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
646 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
647 $ echo blue > color
647 $ echo blue > color
648 $ hg commit -A -m "3 blue"
648 $ hg commit -A -m "3 blue"
649
649
650 $ hg grep --all red
650 $ hg grep --all red
651 color:3:-:red
651 color:3:-:red
652 color:1:+:red
652 color:1:+:red
653
653
654 $ hg grep --diff red
654 $ hg grep --diff red
655 color:3:-:red
655 color:3:-:red
656 color:1:+:red
656 color:1:+:red
657
657
658 Issue3885: test that changing revision order does not alter the
658 Issue3885: test that changing revision order does not alter the
659 revisions printed, just their order.
659 revisions printed, just their order.
660
660
661 $ hg grep --all red -r "all()"
661 $ hg grep --all red -r "all()"
662 color:1:+:red
662 color:1:+:red
663 color:3:-:red
663 color:3:-:red
664
664
665 $ hg grep --all red -r "reverse(all())"
665 $ hg grep --all red -r "reverse(all())"
666 color:3:-:red
666 color:3:-:red
667 color:1:+:red
667 color:1:+:red
668
668
669 $ hg grep --diff red -r "all()"
669 $ hg grep --diff red -r "all()"
670 color:1:+:red
670 color:1:+:red
671 color:3:-:red
671 color:3:-:red
672
672
673 $ hg grep --diff red -r "reverse(all())"
673 $ hg grep --diff red -r "reverse(all())"
674 color:3:-:red
674 color:3:-:red
675 color:1:+:red
675 color:1:+:red
676
676
677 $ cd ..
677 $ cd ..
678
678
679 $ hg init a
679 $ hg init a
680 $ cd a
680 $ cd a
681 $ cp "$TESTDIR/binfile.bin" .
681 $ cp "$TESTDIR/binfile.bin" .
682 $ hg add binfile.bin
682 $ hg add binfile.bin
683 $ hg ci -m 'add binfile.bin'
683 $ hg ci -m 'add binfile.bin'
684 $ hg grep "MaCam" --all
684 $ hg grep "MaCam" --all
685 binfile.bin:0:+: Binary file matches
685 binfile.bin:0:+: Binary file matches
686
686
687 $ hg grep "MaCam" --diff
687 $ hg grep "MaCam" --diff
688 binfile.bin:0:+: Binary file matches
688 binfile.bin:0:+: Binary file matches
689
689
690 $ cd ..
690 $ cd ..
691
691
692 Moved line may not be collected by "grep --diff" since it first filters
692 Moved line may not be collected by "grep --diff" since it first filters
693 the contents to be diffed by the pattern. (i.e.
693 the contents to be diffed by the pattern. (i.e.
694 "diff <(grep pat a) <(grep pat b)", not "diff a b | grep pat".)
694 "diff <(grep pat a) <(grep pat b)", not "diff a b | grep pat".)
695 This is much faster than generating full diff per revision.
695 This is much faster than generating full diff per revision.
696
696
697 $ hg init moved-line
697 $ hg init moved-line
698 $ cd moved-line
698 $ cd moved-line
699 $ cat <<'EOF' > a
699 $ cat <<'EOF' > a
700 > foo
700 > foo
701 > bar
701 > bar
702 > baz
702 > baz
703 > EOF
703 > EOF
704 $ hg ci -Am initial
704 $ hg ci -Am initial
705 adding a
705 adding a
706 $ cat <<'EOF' > a
706 $ cat <<'EOF' > a
707 > bar
707 > bar
708 > baz
708 > baz
709 > foo
709 > foo
710 > EOF
710 > EOF
711 $ hg ci -m reorder
711 $ hg ci -m reorder
712
712
713 $ hg diff -c 1
713 $ hg diff -c 1
714 diff -r a593cc55e81b -r 69789a3b6e80 a
714 diff -r a593cc55e81b -r 69789a3b6e80 a
715 --- a/a Thu Jan 01 00:00:00 1970 +0000
715 --- a/a Thu Jan 01 00:00:00 1970 +0000
716 +++ b/a Thu Jan 01 00:00:00 1970 +0000
716 +++ b/a Thu Jan 01 00:00:00 1970 +0000
717 @@ -1,3 +1,3 @@
717 @@ -1,3 +1,3 @@
718 -foo
718 -foo
719 bar
719 bar
720 baz
720 baz
721 +foo
721 +foo
722
722
723 can't find the move of "foo" at the revision 1:
723 can't find the move of "foo" at the revision 1:
724
724
725 $ hg grep --diff foo -r1
725 $ hg grep --diff foo -r1
726 [1]
726 [1]
727
727
728 "bar" isn't moved at the revisoin 1:
728 "bar" isn't moved at the revisoin 1:
729
729
730 $ hg grep --diff bar -r1
730 $ hg grep --diff bar -r1
731 [1]
731 [1]
732
732
733 $ cd ..
733 $ cd ..
734
734
735 Test for showing working of allfiles flag
735 Test for showing working of allfiles flag
736
736
737 $ hg init sng
737 $ hg init sng
738 $ cd sng
738 $ cd sng
739 $ echo "unmod" >> um
739 $ echo "unmod" >> um
740 $ echo old > old
740 $ echo old > old
741 $ hg ci -q -A -m "adds unmod to um"
741 $ hg ci -q -A -m "adds unmod to um"
742 $ echo "something else" >> new
742 $ echo "something else" >> new
743 $ hg ci -A -m "second commit"
743 $ hg ci -A -m "second commit"
744 adding new
744 adding new
745 $ hg grep -r "." "unmod"
745 $ hg grep -r "." "unmod"
746 um:1:unmod
746 um:1:unmod
747
747
748 Existing tracked files in the working directory are searched by default
748 Existing tracked files in the working directory are searched by default
749
749
750 $ echo modified >> new
750 $ echo modified >> new
751 $ echo 'added' > added; hg add added
751 $ echo 'added' > added; hg add added
752 $ echo 'added, missing' > added-missing; hg add added-missing; rm added-missing
752 $ echo 'added, missing' > added-missing; hg add added-missing; rm added-missing
753 $ echo 'untracked' > untracked
753 $ echo 'untracked' > untracked
754 $ hg rm old
754 $ hg rm old
755 $ hg grep ''
755 $ hg grep ''
756 added:added
756 added:added
757 new:something else
757 new:something else
758 new:modified
758 new:modified
759 um:unmod
759 um:unmod
760
760
761 #if symlink
761 #if symlink
762 Grepping a symlink greps its destination
762 Grepping a symlink greps its destination
763
763
764 $ rm -f added; ln -s symlink-added added
764 $ rm -f added; ln -s symlink-added added
765 $ hg grep '' | grep added
765 $ hg grep '' | grep added
766 added:symlink-added
766 added:symlink-added
767
767
768 But we reject symlinks as directories components of a tracked file as
768 But we reject symlinks as directories components of a tracked file as
769 usual:
769 usual:
770
770
771 $ mkdir dir; touch dir/f; hg add dir/f
771 $ mkdir dir; touch dir/f; hg add dir/f
772 $ rm -rf dir; ln -s / dir
772 $ rm -rf dir; ln -s / dir
773 $ hg grep ''
773 $ hg grep ''
774 abort: path 'dir/f' traverses symbolic link 'dir'
774 abort: path 'dir/f' traverses symbolic link 'dir'
775 [255]
775 [255]
776 #endif
776 #endif
777
777
778 But we can search files from some other revision with -rREV
778 But we can search files from some other revision with -rREV
779
779
780 $ hg grep -r. mod
780 $ hg grep -r. mod
781 um:1:unmod
781 um:1:unmod
782
782
783 $ hg grep --diff mod
783 $ hg grep --diff mod
784 um:0:+:unmod
784 um:0:+:unmod
785
785
786 $ cd ..
786 $ cd ..
787
787
788 Change Default of grep by ui.tweakdefaults, that is, the files not in current
788 Change Default of grep by ui.tweakdefaults, that is, the files not in current
789 working directory should not be grepp-ed on
789 working directory should not be grepp-ed on
790
790
791 $ hg init ab
791 $ hg init ab
792 $ cd ab
792 $ cd ab
793 $ cat <<'EOF' >> .hg/hgrc
793 $ cat <<'EOF' >> .hg/hgrc
794 > [ui]
794 > [ui]
795 > tweakdefaults = True
795 > tweakdefaults = True
796 > EOF
796 > EOF
797 $ echo "some text">>file1
797 $ echo "some text">>file1
798 $ hg add file1
798 $ hg add file1
799 $ hg commit -m "adds file1"
799 $ hg commit -m "adds file1"
800 $ hg mv file1 file2
800 $ hg mv file1 file2
801
801
802 wdir revision is hidden by default:
802 wdir revision is hidden by default:
803
803
804 $ hg grep "some"
804 $ hg grep "some"
805 file2:some text
805 file2:some text
806
806
807 but it should be available in template dict:
807 but it should be available in template dict:
808
808
809 $ hg grep "some" -Tjson
809 $ hg grep "some" -Tjson
810 [
810 [
811 {
811 {
812 "date": [0, 0],
812 "date": [0, 0],
813 "lineno": 1,
813 "lineno": 1,
814 "node": "ffffffffffffffffffffffffffffffffffffffff",
814 "node": "ffffffffffffffffffffffffffffffffffffffff",
815 "path": "file2",
815 "path": "file2",
816 "rev": 2147483647,
816 "rev": 2147483647,
817 "texts": [{"matched": true, "text": "some"}, {"matched": false, "text": " text"}],
817 "texts": [{"matched": true, "text": "some"}, {"matched": false, "text": " text"}],
818 "user": "test"
818 "user": "test"
819 }
819 }
820 ]
820 ]
821
821
822 $ cd ..
822 $ cd ..
823
823
824 test -rMULTIREV
824 test -rMULTIREV
825
825
826 $ cd sng
826 $ cd sng
827 $ hg rm um
827 $ hg rm um
828 $ hg commit -m "deletes um"
828 $ hg commit -m "deletes um"
829 $ hg grep -r "0:2" "unmod"
829 $ hg grep -r "0:2" "unmod"
830 um:0:unmod
830 um:0:unmod
831 um:1:unmod
831 um:1:unmod
832 $ hg grep -r "0:2" "unmod" um
832 $ hg grep -r "0:2" "unmod" um
833 um:0:unmod
833 um:0:unmod
834 um:1:unmod
834 um:1:unmod
835 $ hg grep -r "0:2" "unmod" "glob:**/um" # Check that patterns also work
835 $ hg grep -r "0:2" "unmod" "glob:**/um" # Check that patterns also work
836 um:0:unmod
836 um:0:unmod
837 um:1:unmod
837 um:1:unmod
838 $ cd ..
838 $ cd ..
839
839
840 --follow with/without --diff and/or paths
840 --follow with/without --diff and/or paths
841 -----------------------------------------
841 -----------------------------------------
842
842
843 For each test case, we compare the history traversal of "hg log",
843 For each test case, we compare the history traversal of "hg log",
844 "hg grep --diff", and "hg grep" (--all-files).
844 "hg grep --diff", and "hg grep" (--all-files).
845
845
846 "hg grep --diff" should traverse the log in the same way as "hg log".
846 "hg grep --diff" should traverse the log in the same way as "hg log".
847 "hg grep" (--all-files) is slightly different in that it includes
847 "hg grep" (--all-files) is slightly different in that it includes
848 unmodified changes.
848 unmodified changes.
849
849
850 $ hg init follow
850 $ hg init follow
851 $ cd follow
851 $ cd follow
852
852
853 $ cat <<'EOF' >> .hg/hgrc
853 $ cat <<'EOF' >> .hg/hgrc
854 > [ui]
854 > [ui]
855 > logtemplate = '{rev}: {join(files % "{status} {path}", ", ")}\n'
855 > logtemplate = '{rev}: {join(files % "{status} {path}", ", ")}\n'
856 > EOF
856 > EOF
857
857
858 $ for f in add0 add0-mod1 add0-rm1 add0-mod2 add0-rm2 add0-mod3 add0-mod4 add0-rm4; do
858 $ for f in add0 add0-mod1 add0-rm1 add0-mod2 add0-rm2 add0-mod3 add0-mod4 add0-rm4; do
859 > echo data0 >> $f
859 > echo data0 >> $f
860 > done
860 > done
861 $ hg ci -qAm0
861 $ hg ci -qAm0
862
862
863 $ hg cp add0 add0-cp1
863 $ hg cp add0 add0-cp1
864 $ hg cp add0 add0-cp1-mod1
864 $ hg cp add0 add0-cp1-mod1
865 $ hg cp add0 add0-cp1-mod1-rm3
865 $ hg cp add0 add0-cp1-mod1-rm3
866 $ hg rm add0-rm1
866 $ hg rm add0-rm1
867 $ for f in *mod1*; do
867 $ for f in *mod1*; do
868 > echo data1 >> $f
868 > echo data1 >> $f
869 > done
869 > done
870 $ hg ci -qAm1
870 $ hg ci -qAm1
871
871
872 $ hg update -q 0
872 $ hg update -q 0
873 $ hg cp add0 add0-cp2
873 $ hg cp add0 add0-cp2
874 $ hg cp add0 add0-cp2-mod2
874 $ hg cp add0 add0-cp2-mod2
875 $ hg rm add0-rm2
875 $ hg rm add0-rm2
876 $ for f in *mod2*; do
876 $ for f in *mod2*; do
877 > echo data2 >> $f
877 > echo data2 >> $f
878 > done
878 > done
879 $ hg ci -qAm2
879 $ hg ci -qAm2
880
880
881 $ hg update -q 1
881 $ hg update -q 1
882 $ hg cp add0-cp1 add0-cp1-cp3
882 $ hg cp add0-cp1 add0-cp1-cp3
883 $ hg cp add0-cp1-mod1 add0-cp1-mod1-cp3-mod3
883 $ hg cp add0-cp1-mod1 add0-cp1-mod1-cp3-mod3
884 $ hg rm add0-cp1-mod1-rm3
884 $ hg rm add0-cp1-mod1-rm3
885 $ for f in *mod3*; do
885 $ for f in *mod3*; do
886 > echo data3 >> $f
886 > echo data3 >> $f
887 > done
887 > done
888 $ hg ci -qAm3
888 $ hg ci -qAm3
889
889
890 $ hg cp add0 add0-cp4
890 $ hg cp add0 add0-cp4
891 $ hg cp add0 add0-cp4-mod4
891 $ hg cp add0 add0-cp4-mod4
892 $ hg rm add0-rm4
892 $ hg rm add0-rm4
893 $ for f in *mod4*; do
893 $ for f in *mod4*; do
894 > echo data4 >> $f
894 > echo data4 >> $f
895 > done
895 > done
896
896
897 $ hg log -Gr':wdir()'
897 $ hg log -Gr':wdir()'
898 o 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
898 o 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
899 |
899 |
900 @ 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
900 @ 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
901 |
901 |
902 | o 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
902 | o 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
903 | |
903 | |
904 o | 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
904 o | 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
905 |/
905 |/
906 o 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
906 o 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
907
907
908
908
909 follow revision history from wdir parent:
909 follow revision history from wdir parent:
910
910
911 $ hg log -f
911 $ hg log -f
912 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
912 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
913 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
913 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
914 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
914 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
915
915
916 $ hg grep --diff -f data
916 $ hg grep --diff -f data
917 add0-cp1-mod1-cp3-mod3:3:+:data3
917 add0-cp1-mod1-cp3-mod3:3:+:data3
918 add0-mod3:3:+:data3
918 add0-mod3:3:+:data3
919 add0-cp1-mod1:1:+:data1
919 add0-cp1-mod1:1:+:data1
920 add0-cp1-mod1-rm3:1:+:data1
920 add0-cp1-mod1-rm3:1:+:data1
921 add0-mod1:1:+:data1
921 add0-mod1:1:+:data1
922 add0:0:+:data0
922 add0:0:+:data0
923 add0-mod1:0:+:data0
923 add0-mod1:0:+:data0
924 add0-mod2:0:+:data0
924 add0-mod2:0:+:data0
925 add0-mod3:0:+:data0
925 add0-mod3:0:+:data0
926 add0-mod4:0:+:data0
926 add0-mod4:0:+:data0
927 add0-rm1:0:+:data0
927 add0-rm1:0:+:data0
928 add0-rm2:0:+:data0
928 add0-rm2:0:+:data0
929 add0-rm4:0:+:data0
929 add0-rm4:0:+:data0
930
930
931 $ hg grep -f data
931 $ hg grep -f data
932 add0:3:data0
932 add0:3:data0
933 add0-cp1:3:data0
933 add0-cp1:3:data0
934 add0-cp1-cp3:3:data0
934 add0-cp1-cp3:3:data0
935 add0-cp1-mod1:3:data0
935 add0-cp1-mod1:3:data0
936 add0-cp1-mod1:3:data1
936 add0-cp1-mod1:3:data1
937 add0-cp1-mod1-cp3-mod3:3:data0
937 add0-cp1-mod1-cp3-mod3:3:data0
938 add0-cp1-mod1-cp3-mod3:3:data1
938 add0-cp1-mod1-cp3-mod3:3:data1
939 add0-cp1-mod1-cp3-mod3:3:data3
939 add0-cp1-mod1-cp3-mod3:3:data3
940 add0-mod1:3:data0
940 add0-mod1:3:data0
941 add0-mod1:3:data1
941 add0-mod1:3:data1
942 add0-mod2:3:data0
942 add0-mod2:3:data0
943 add0-mod3:3:data0
943 add0-mod3:3:data0
944 add0-mod3:3:data3
944 add0-mod3:3:data3
945 add0-mod4:3:data0
945 add0-mod4:3:data0
946 add0-rm2:3:data0
946 add0-rm2:3:data0
947 add0-rm4:3:data0
947 add0-rm4:3:data0
948 add0:1:data0
948 add0:1:data0
949 add0-cp1:1:data0
949 add0-cp1:1:data0
950 add0-cp1-mod1:1:data0
950 add0-cp1-mod1:1:data0
951 add0-cp1-mod1:1:data1
951 add0-cp1-mod1:1:data1
952 add0-cp1-mod1-rm3:1:data0
952 add0-cp1-mod1-rm3:1:data0
953 add0-cp1-mod1-rm3:1:data1
953 add0-cp1-mod1-rm3:1:data1
954 add0-mod1:1:data0
954 add0-mod1:1:data0
955 add0-mod1:1:data1
955 add0-mod1:1:data1
956 add0-mod2:1:data0
956 add0-mod2:1:data0
957 add0-mod3:1:data0
957 add0-mod3:1:data0
958 add0-mod4:1:data0
958 add0-mod4:1:data0
959 add0-rm2:1:data0
959 add0-rm2:1:data0
960 add0-rm4:1:data0
960 add0-rm4:1:data0
961 add0:0:data0
961 add0:0:data0
962 add0-mod1:0:data0
962 add0-mod1:0:data0
963 add0-mod2:0:data0
963 add0-mod2:0:data0
964 add0-mod3:0:data0
964 add0-mod3:0:data0
965 add0-mod4:0:data0
965 add0-mod4:0:data0
966 add0-rm1:0:data0
966 add0-rm1:0:data0
967 add0-rm2:0:data0
967 add0-rm2:0:data0
968 add0-rm4:0:data0
968 add0-rm4:0:data0
969
969
970 follow revision history from specified revision:
970 follow revision history from specified revision:
971
971
972 $ hg log -fr2
972 $ hg log -fr2
973 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
973 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
974 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
974 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
975
975
976 $ hg grep --diff -fr2 data
976 $ hg grep --diff -fr2 data
977 add0-cp2-mod2:2:+:data2
977 add0-cp2-mod2:2:+:data2
978 add0-mod2:2:+:data2
978 add0-mod2:2:+:data2
979 add0:0:+:data0
979 add0:0:+:data0
980 add0-mod1:0:+:data0
980 add0-mod1:0:+:data0
981 add0-mod2:0:+:data0
981 add0-mod2:0:+:data0
982 add0-mod3:0:+:data0
982 add0-mod3:0:+:data0
983 add0-mod4:0:+:data0
983 add0-mod4:0:+:data0
984 add0-rm1:0:+:data0
984 add0-rm1:0:+:data0
985 add0-rm2:0:+:data0
985 add0-rm2:0:+:data0
986 add0-rm4:0:+:data0
986 add0-rm4:0:+:data0
987
987
988 $ hg grep -fr2 data
988 $ hg grep -fr2 data
989 add0:2:data0
989 add0:2:data0
990 add0-cp2:2:data0
990 add0-cp2:2:data0
991 add0-cp2-mod2:2:data0
991 add0-cp2-mod2:2:data0
992 add0-cp2-mod2:2:data2
992 add0-cp2-mod2:2:data2
993 add0-mod1:2:data0
993 add0-mod1:2:data0
994 add0-mod2:2:data0
994 add0-mod2:2:data0
995 add0-mod2:2:data2
995 add0-mod2:2:data2
996 add0-mod3:2:data0
996 add0-mod3:2:data0
997 add0-mod4:2:data0
997 add0-mod4:2:data0
998 add0-rm1:2:data0
998 add0-rm1:2:data0
999 add0-rm4:2:data0
999 add0-rm4:2:data0
1000 add0:0:data0
1000 add0:0:data0
1001 add0-mod1:0:data0
1001 add0-mod1:0:data0
1002 add0-mod2:0:data0
1002 add0-mod2:0:data0
1003 add0-mod3:0:data0
1003 add0-mod3:0:data0
1004 add0-mod4:0:data0
1004 add0-mod4:0:data0
1005 add0-rm1:0:data0
1005 add0-rm1:0:data0
1006 add0-rm2:0:data0
1006 add0-rm2:0:data0
1007 add0-rm4:0:data0
1007 add0-rm4:0:data0
1008
1008
1009 follow revision history from wdir:
1009 follow revision history from wdir:
1010
1010
1011 $ hg log -fr'wdir()'
1011 $ hg log -fr'wdir()'
1012 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1012 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1013 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1013 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1014 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1014 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1015 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1015 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1016
1016
1017 BROKEN: should not abort because of removed file
1017 BROKEN: should not abort because of removed file
1018 $ hg grep --diff -fr'wdir()' data
1018 $ hg grep --diff -fr'wdir()' data
1019 add0-cp4-mod4:2147483647:+:data4
1019 add0-cp4-mod4:2147483647:+:data4
1020 add0-mod4:2147483647:+:data4
1020 add0-mod4:2147483647:+:data4
1021 add0-rm4:2147483647:-:abort: add0-rm4@None: not found in manifest!
1021 add0-rm4:2147483647:-:abort: add0-rm4@None: not found in manifest!
1022 [255]
1022 [255]
1023
1023
1024 $ hg grep -fr'wdir()' data
1024 $ hg grep -fr'wdir()' data
1025 add0:2147483647:data0
1025 add0:2147483647:data0
1026 add0-cp1:2147483647:data0
1026 add0-cp1:2147483647:data0
1027 add0-cp1-cp3:2147483647:data0
1027 add0-cp1-cp3:2147483647:data0
1028 add0-cp1-mod1:2147483647:data0
1028 add0-cp1-mod1:2147483647:data0
1029 add0-cp1-mod1:2147483647:data1
1029 add0-cp1-mod1:2147483647:data1
1030 add0-cp1-mod1-cp3-mod3:2147483647:data0
1030 add0-cp1-mod1-cp3-mod3:2147483647:data0
1031 add0-cp1-mod1-cp3-mod3:2147483647:data1
1031 add0-cp1-mod1-cp3-mod3:2147483647:data1
1032 add0-cp1-mod1-cp3-mod3:2147483647:data3
1032 add0-cp1-mod1-cp3-mod3:2147483647:data3
1033 add0-cp4:2147483647:data0
1033 add0-cp4:2147483647:data0
1034 add0-cp4-mod4:2147483647:data0
1034 add0-cp4-mod4:2147483647:data0
1035 add0-cp4-mod4:2147483647:data4
1035 add0-cp4-mod4:2147483647:data4
1036 add0-mod1:2147483647:data0
1036 add0-mod1:2147483647:data0
1037 add0-mod1:2147483647:data1
1037 add0-mod1:2147483647:data1
1038 add0-mod2:2147483647:data0
1038 add0-mod2:2147483647:data0
1039 add0-mod3:2147483647:data0
1039 add0-mod3:2147483647:data0
1040 add0-mod3:2147483647:data3
1040 add0-mod3:2147483647:data3
1041 add0-mod4:2147483647:data0
1041 add0-mod4:2147483647:data0
1042 add0-mod4:2147483647:data4
1042 add0-mod4:2147483647:data4
1043 add0-rm2:2147483647:data0
1043 add0-rm2:2147483647:data0
1044 add0:3:data0
1044 add0:3:data0
1045 add0-cp1:3:data0
1045 add0-cp1:3:data0
1046 add0-cp1-cp3:3:data0
1046 add0-cp1-cp3:3:data0
1047 add0-cp1-mod1:3:data0
1047 add0-cp1-mod1:3:data0
1048 add0-cp1-mod1:3:data1
1048 add0-cp1-mod1:3:data1
1049 add0-cp1-mod1-cp3-mod3:3:data0
1049 add0-cp1-mod1-cp3-mod3:3:data0
1050 add0-cp1-mod1-cp3-mod3:3:data1
1050 add0-cp1-mod1-cp3-mod3:3:data1
1051 add0-cp1-mod1-cp3-mod3:3:data3
1051 add0-cp1-mod1-cp3-mod3:3:data3
1052 add0-mod1:3:data0
1052 add0-mod1:3:data0
1053 add0-mod1:3:data1
1053 add0-mod1:3:data1
1054 add0-mod2:3:data0
1054 add0-mod2:3:data0
1055 add0-mod3:3:data0
1055 add0-mod3:3:data0
1056 add0-mod3:3:data3
1056 add0-mod3:3:data3
1057 add0-mod4:3:data0
1057 add0-mod4:3:data0
1058 add0-rm2:3:data0
1058 add0-rm2:3:data0
1059 add0-rm4:3:data0
1059 add0-rm4:3:data0
1060 add0:1:data0
1060 add0:1:data0
1061 add0-cp1:1:data0
1061 add0-cp1:1:data0
1062 add0-cp1-mod1:1:data0
1062 add0-cp1-mod1:1:data0
1063 add0-cp1-mod1:1:data1
1063 add0-cp1-mod1:1:data1
1064 add0-cp1-mod1-rm3:1:data0
1064 add0-cp1-mod1-rm3:1:data0
1065 add0-cp1-mod1-rm3:1:data1
1065 add0-cp1-mod1-rm3:1:data1
1066 add0-mod1:1:data0
1066 add0-mod1:1:data0
1067 add0-mod1:1:data1
1067 add0-mod1:1:data1
1068 add0-mod2:1:data0
1068 add0-mod2:1:data0
1069 add0-mod3:1:data0
1069 add0-mod3:1:data0
1070 add0-mod4:1:data0
1070 add0-mod4:1:data0
1071 add0-rm2:1:data0
1071 add0-rm2:1:data0
1072 add0-rm4:1:data0
1072 add0-rm4:1:data0
1073 add0:0:data0
1073 add0:0:data0
1074 add0-mod1:0:data0
1074 add0-mod1:0:data0
1075 add0-mod2:0:data0
1075 add0-mod2:0:data0
1076 add0-mod3:0:data0
1076 add0-mod3:0:data0
1077 add0-mod4:0:data0
1077 add0-mod4:0:data0
1078 add0-rm1:0:data0
1078 add0-rm1:0:data0
1079 add0-rm2:0:data0
1079 add0-rm2:0:data0
1080 add0-rm4:0:data0
1080 add0-rm4:0:data0
1081
1081
1082 follow revision history from multiple revisions:
1082 follow revision history from multiple revisions:
1083
1083
1084 $ hg log -fr'1+2'
1084 $ hg log -fr'1+2'
1085 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1085 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1086 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1086 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1087 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1087 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1088
1088
1089 $ hg grep --diff -fr'1+2' data
1089 $ hg grep --diff -fr'1+2' data
1090 add0-cp2-mod2:2:+:data2
1090 add0-cp2-mod2:2:+:data2
1091 add0-mod2:2:+:data2
1091 add0-mod2:2:+:data2
1092 add0-cp1-mod1:1:+:data1
1092 add0-cp1-mod1:1:+:data1
1093 add0-cp1-mod1-rm3:1:+:data1
1093 add0-cp1-mod1-rm3:1:+:data1
1094 add0-mod1:1:+:data1
1094 add0-mod1:1:+:data1
1095 add0:0:+:data0
1095 add0:0:+:data0
1096 add0-mod1:0:+:data0
1096 add0-mod1:0:+:data0
1097 add0-mod2:0:+:data0
1097 add0-mod2:0:+:data0
1098 add0-mod3:0:+:data0
1098 add0-mod3:0:+:data0
1099 add0-mod4:0:+:data0
1099 add0-mod4:0:+:data0
1100 add0-rm1:0:+:data0
1100 add0-rm1:0:+:data0
1101 add0-rm2:0:+:data0
1101 add0-rm2:0:+:data0
1102 add0-rm4:0:+:data0
1102 add0-rm4:0:+:data0
1103
1103
1104 $ hg grep -fr'1+2' data
1104 $ hg grep -fr'1+2' data
1105 add0:2:data0
1105 add0:2:data0
1106 add0-cp2:2:data0
1106 add0-cp2:2:data0
1107 add0-cp2-mod2:2:data0
1107 add0-cp2-mod2:2:data0
1108 add0-cp2-mod2:2:data2
1108 add0-cp2-mod2:2:data2
1109 add0-mod1:2:data0
1109 add0-mod1:2:data0
1110 add0-mod2:2:data0
1110 add0-mod2:2:data0
1111 add0-mod2:2:data2
1111 add0-mod2:2:data2
1112 add0-mod3:2:data0
1112 add0-mod3:2:data0
1113 add0-mod4:2:data0
1113 add0-mod4:2:data0
1114 add0-rm1:2:data0
1114 add0-rm1:2:data0
1115 add0-rm4:2:data0
1115 add0-rm4:2:data0
1116 add0:1:data0
1116 add0:1:data0
1117 add0-cp1:1:data0
1117 add0-cp1:1:data0
1118 add0-cp1-mod1:1:data0
1118 add0-cp1-mod1:1:data0
1119 add0-cp1-mod1:1:data1
1119 add0-cp1-mod1:1:data1
1120 add0-cp1-mod1-rm3:1:data0
1120 add0-cp1-mod1-rm3:1:data0
1121 add0-cp1-mod1-rm3:1:data1
1121 add0-cp1-mod1-rm3:1:data1
1122 add0-mod1:1:data0
1122 add0-mod1:1:data0
1123 add0-mod1:1:data1
1123 add0-mod1:1:data1
1124 add0-mod2:1:data0
1124 add0-mod2:1:data0
1125 add0-mod3:1:data0
1125 add0-mod3:1:data0
1126 add0-mod4:1:data0
1126 add0-mod4:1:data0
1127 add0-rm2:1:data0
1127 add0-rm2:1:data0
1128 add0-rm4:1:data0
1128 add0-rm4:1:data0
1129 add0:0:data0
1129 add0:0:data0
1130 add0-mod1:0:data0
1130 add0-mod1:0:data0
1131 add0-mod2:0:data0
1131 add0-mod2:0:data0
1132 add0-mod3:0:data0
1132 add0-mod3:0:data0
1133 add0-mod4:0:data0
1133 add0-mod4:0:data0
1134 add0-rm1:0:data0
1134 add0-rm1:0:data0
1135 add0-rm2:0:data0
1135 add0-rm2:0:data0
1136 add0-rm4:0:data0
1136 add0-rm4:0:data0
1137
1137
1138 follow file history from wdir parent, unmodified in wdir:
1138 follow file history from wdir parent, unmodified in wdir:
1139
1139
1140 $ hg log -f add0-mod3
1140 $ hg log -f add0-mod3
1141 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1141 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1142 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1142 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1143
1143
1144 $ hg grep --diff -f data add0-mod3
1144 $ hg grep --diff -f data add0-mod3
1145 add0-mod3:3:+:data3
1145 add0-mod3:3:+:data3
1146 add0-mod3:0:+:data0
1146 add0-mod3:0:+:data0
1147
1147
1148 $ hg grep -f data add0-mod3
1148 $ hg grep -f data add0-mod3
1149 add0-mod3:3:data0
1149 add0-mod3:3:data0
1150 add0-mod3:3:data3
1150 add0-mod3:3:data3
1151 add0-mod3:1:data0
1151 add0-mod3:1:data0
1152 add0-mod3:0:data0
1152 add0-mod3:0:data0
1153
1153
1154 follow file history from wdir parent, modified in wdir:
1154 follow file history from wdir parent, modified in wdir:
1155
1155
1156 $ hg log -f add0-mod4
1156 $ hg log -f add0-mod4
1157 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1157 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1158
1158
1159 $ hg grep --diff -f data add0-mod4
1159 $ hg grep --diff -f data add0-mod4
1160 add0-mod4:0:+:data0
1160 add0-mod4:0:+:data0
1161
1161
1162 $ hg grep -f data add0-mod4
1162 $ hg grep -f data add0-mod4
1163 add0-mod4:3:data0
1163 add0-mod4:3:data0
1164 add0-mod4:1:data0
1164 add0-mod4:1:data0
1165 add0-mod4:0:data0
1165 add0-mod4:0:data0
1166
1166
1167 follow file history from wdir parent, copied but unmodified:
1167 follow file history from wdir parent, copied but unmodified:
1168
1168
1169 $ hg log -f add0-cp1-cp3
1169 $ hg log -f add0-cp1-cp3
1170 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1170 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1171 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1171 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1172 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1172 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1173
1173
1174 $ hg grep --diff -f data add0-cp1-cp3
1174 $ hg grep --diff -f data add0-cp1-cp3
1175 add0:0:+:data0
1175 add0:0:+:data0
1176
1176
1177 BROKEN: should follow history across renames
1177 BROKEN: should follow history across renames
1178 $ hg grep -f data add0-cp1-cp3
1178 $ hg grep -f data add0-cp1-cp3
1179 add0-cp1-cp3:3:data0
1179 add0-cp1-cp3:3:data0
1180
1180
1181 follow file history from wdir parent, copied and modified:
1181 follow file history from wdir parent, copied and modified:
1182
1182
1183 $ hg log -f add0-cp1-mod1-cp3-mod3
1183 $ hg log -f add0-cp1-mod1-cp3-mod3
1184 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1184 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1185 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1185 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1186 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1186 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1187
1187
1188 $ hg grep --diff -f data add0-cp1-mod1-cp3-mod3
1188 $ hg grep --diff -f data add0-cp1-mod1-cp3-mod3
1189 add0-cp1-mod1-cp3-mod3:3:+:data3
1189 add0-cp1-mod1-cp3-mod3:3:+:data3
1190 add0-cp1-mod1:1:+:data1
1190 add0-cp1-mod1:1:+:data1
1191 add0:0:+:data0
1191 add0:0:+:data0
1192
1192
1193 BROKEN: should follow history across renames
1193 BROKEN: should follow history across renames
1194 $ hg grep -f data add0-cp1-mod1-cp3-mod3
1194 $ hg grep -f data add0-cp1-mod1-cp3-mod3
1195 add0-cp1-mod1-cp3-mod3:3:data0
1195 add0-cp1-mod1-cp3-mod3:3:data0
1196 add0-cp1-mod1-cp3-mod3:3:data1
1196 add0-cp1-mod1-cp3-mod3:3:data1
1197 add0-cp1-mod1-cp3-mod3:3:data3
1197 add0-cp1-mod1-cp3-mod3:3:data3
1198
1198
1199 follow file history from wdir parent, copied in wdir:
1199 follow file history from wdir parent, copied in wdir:
1200
1200
1201 $ hg log -f add0-cp4
1201 $ hg log -f add0-cp4
1202 abort: cannot follow nonexistent file: "add0-cp4"
1202 abort: cannot follow nonexistent file: "add0-cp4"
1203 [255]
1203 [255]
1204
1204
1205 $ hg grep --diff -f data add0-cp4
1205 $ hg grep --diff -f data add0-cp4
1206 abort: cannot follow nonexistent file: "add0-cp4"
1206 abort: cannot follow nonexistent file: "add0-cp4"
1207 [255]
1207 [255]
1208
1208
1209 BROKEN: maybe better to abort
1209 BROKEN: maybe better to abort
1210 $ hg grep -f data add0-cp4
1210 $ hg grep -f data add0-cp4
1211 [1]
1211 [1]
1212
1212
1213 follow file history from wdir parent, removed:
1213 follow file history from wdir parent, removed:
1214
1214
1215 $ hg log -f add0-cp1-mod1-rm3
1215 $ hg log -f add0-cp1-mod1-rm3
1216 abort: cannot follow file not in parent revision: "add0-cp1-mod1-rm3"
1216 abort: cannot follow file not in parent revision: "add0-cp1-mod1-rm3"
1217 [255]
1217 [255]
1218
1218
1219 $ hg grep --diff -f data add0-cp1-mod1-rm3
1219 $ hg grep --diff -f data add0-cp1-mod1-rm3
1220 abort: cannot follow file not in parent revision: "add0-cp1-mod1-rm3"
1220 abort: cannot follow file not in parent revision: "add0-cp1-mod1-rm3"
1221 [255]
1221 [255]
1222
1222
1223 BROKEN: maybe better to abort
1223 BROKEN: maybe better to abort
1224 $ hg grep -f data add0-cp1-mod1-rm3
1224 $ hg grep -f data add0-cp1-mod1-rm3
1225 add0-cp1-mod1-rm3:1:data0
1225 add0-cp1-mod1-rm3:1:data0
1226 add0-cp1-mod1-rm3:1:data1
1226 add0-cp1-mod1-rm3:1:data1
1227
1227
1228 follow file history from wdir parent (explicit), removed:
1228 follow file history from wdir parent (explicit), removed:
1229
1229
1230 $ hg log -fr. add0-cp1-mod1-rm3
1230 $ hg log -fr. add0-cp1-mod1-rm3
1231 abort: cannot follow file not in any of the specified revisions: "add0-cp1-mod1-rm3"
1231 abort: cannot follow file not in any of the specified revisions: "add0-cp1-mod1-rm3"
1232 [255]
1232 [255]
1233
1233
1234 $ hg grep --diff -fr. data add0-cp1-mod1-rm3
1234 $ hg grep --diff -fr. data add0-cp1-mod1-rm3
1235 abort: cannot follow file not in any of the specified revisions: "add0-cp1-mod1-rm3"
1235 abort: cannot follow file not in any of the specified revisions: "add0-cp1-mod1-rm3"
1236 [255]
1236 [255]
1237
1237
1238 BROKEN: should abort
1238 BROKEN: should abort
1239 $ hg grep -fr. data add0-cp1-mod1-rm3
1239 $ hg grep -fr. data add0-cp1-mod1-rm3
1240 add0-cp1-mod1-rm3:1:data0
1240 add0-cp1-mod1-rm3:1:data0
1241 add0-cp1-mod1-rm3:1:data1
1241 add0-cp1-mod1-rm3:1:data1
1242
1242
1243 follow file history from wdir parent, removed in wdir:
1243 follow file history from wdir parent, removed in wdir:
1244
1244
1245 $ hg log -f add0-rm4
1245 $ hg log -f add0-rm4
1246 abort: cannot follow file not in parent revision: "add0-rm4"
1246 abort: cannot follow file not in parent revision: "add0-rm4"
1247 [255]
1247 [255]
1248
1248
1249 $ hg grep --diff -f data add0-rm4
1249 $ hg grep --diff -f data add0-rm4
1250 abort: cannot follow file not in parent revision: "add0-rm4"
1250 abort: cannot follow file not in parent revision: "add0-rm4"
1251 [255]
1251 [255]
1252
1252
1253 BROKEN: should abort
1253 BROKEN: should abort
1254 $ hg grep -f data add0-rm4
1254 $ hg grep -f data add0-rm4
1255 add0-rm4:3:data0
1255 add0-rm4:3:data0
1256 add0-rm4:1:data0
1256 add0-rm4:1:data0
1257 add0-rm4:0:data0
1257 add0-rm4:0:data0
1258
1258
1259 follow file history from wdir parent (explicit), removed in wdir:
1259 follow file history from wdir parent (explicit), removed in wdir:
1260
1260
1261 $ hg log -fr. add0-rm4
1261 $ hg log -fr. add0-rm4
1262 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1262 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1263
1263
1264 $ hg grep --diff -fr. data add0-rm4
1264 $ hg grep --diff -fr. data add0-rm4
1265 add0-rm4:0:+:data0
1265 add0-rm4:0:+:data0
1266
1266
1267 $ hg grep -fr. data add0-rm4
1267 $ hg grep -fr. data add0-rm4
1268 add0-rm4:3:data0
1268 add0-rm4:3:data0
1269 add0-rm4:1:data0
1269 add0-rm4:1:data0
1270 add0-rm4:0:data0
1270 add0-rm4:0:data0
1271
1271
1272 follow file history from wdir parent, multiple files:
1272 follow file history from wdir parent, multiple files:
1273
1273
1274 $ hg log -f add0-mod3 add0-cp1-mod1
1274 $ hg log -f add0-mod3 add0-cp1-mod1
1275 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1275 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1276 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1276 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1277 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1277 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1278
1278
1279 $ hg grep --diff -f data add0-mod3 add0-cp1-mod1
1279 $ hg grep --diff -f data add0-mod3 add0-cp1-mod1
1280 add0-mod3:3:+:data3
1280 add0-mod3:3:+:data3
1281 add0-cp1-mod1:1:+:data1
1281 add0-cp1-mod1:1:+:data1
1282 add0:0:+:data0
1282 add0:0:+:data0
1283 add0-mod3:0:+:data0
1283 add0-mod3:0:+:data0
1284
1284
1285 BROKEN: should follow history across renames
1285 BROKEN: should follow history across renames
1286 $ hg grep -f data add0-mod3 add0-cp1-mod1
1286 $ hg grep -f data add0-mod3 add0-cp1-mod1
1287 add0-cp1-mod1:3:data0
1287 add0-cp1-mod1:3:data0
1288 add0-cp1-mod1:3:data1
1288 add0-cp1-mod1:3:data1
1289 add0-mod3:3:data0
1289 add0-mod3:3:data0
1290 add0-mod3:3:data3
1290 add0-mod3:3:data3
1291 add0-cp1-mod1:1:data0
1291 add0-cp1-mod1:1:data0
1292 add0-cp1-mod1:1:data1
1292 add0-cp1-mod1:1:data1
1293 add0-mod3:1:data0
1293 add0-mod3:1:data0
1294 add0-mod3:0:data0
1294 add0-mod3:0:data0
1295
1295
1296 follow file history from specified revision, modified:
1296 follow file history from specified revision, modified:
1297
1297
1298 $ hg log -fr2 add0-mod2
1298 $ hg log -fr2 add0-mod2
1299 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1299 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1300 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1300 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1301
1301
1302 $ hg grep --diff -fr2 data add0-mod2
1302 $ hg grep --diff -fr2 data add0-mod2
1303 add0-mod2:2:+:data2
1303 add0-mod2:2:+:data2
1304 add0-mod2:0:+:data0
1304 add0-mod2:0:+:data0
1305
1305
1306 $ hg grep -fr2 data add0-mod2
1306 $ hg grep -fr2 data add0-mod2
1307 add0-mod2:2:data0
1307 add0-mod2:2:data0
1308 add0-mod2:2:data2
1308 add0-mod2:2:data2
1309 add0-mod2:0:data0
1309 add0-mod2:0:data0
1310
1310
1311 follow file history from specified revision, copied but unmodified:
1311 follow file history from specified revision, copied but unmodified:
1312
1312
1313 $ hg log -fr2 add0-cp2
1313 $ hg log -fr2 add0-cp2
1314 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1314 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1315 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1315 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1316
1316
1317 $ hg grep --diff -fr2 data add0-cp2
1317 $ hg grep --diff -fr2 data add0-cp2
1318 add0:0:+:data0
1318 add0:0:+:data0
1319
1319
1320 BROKEN: should follow history across renames
1320 BROKEN: should follow history across renames
1321 $ hg grep -fr2 data add0-cp2
1321 $ hg grep -fr2 data add0-cp2
1322 add0-cp2:2:data0
1322 add0-cp2:2:data0
1323
1323
1324 follow file history from specified revision, copied and modified:
1324 follow file history from specified revision, copied and modified:
1325
1325
1326 $ hg log -fr2 add0-cp2-mod2
1326 $ hg log -fr2 add0-cp2-mod2
1327 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1327 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1328 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1328 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1329
1329
1330 $ hg grep --diff -fr2 data add0-cp2-mod2
1330 $ hg grep --diff -fr2 data add0-cp2-mod2
1331 add0-cp2-mod2:2:+:data2
1331 add0-cp2-mod2:2:+:data2
1332 add0:0:+:data0
1332 add0:0:+:data0
1333
1333
1334 BROKEN: should follow history across renames
1334 BROKEN: should follow history across renames
1335 $ hg grep -fr2 data add0-cp2-mod2
1335 $ hg grep -fr2 data add0-cp2-mod2
1336 add0-cp2-mod2:2:data0
1336 add0-cp2-mod2:2:data0
1337 add0-cp2-mod2:2:data2
1337 add0-cp2-mod2:2:data2
1338
1338
1339 follow file history from specified revision, removed:
1339 follow file history from specified revision, removed:
1340
1340
1341 $ hg log -fr2 add0-rm2
1341 $ hg log -fr2 add0-rm2
1342 abort: cannot follow file not in any of the specified revisions: "add0-rm2"
1342 abort: cannot follow file not in any of the specified revisions: "add0-rm2"
1343 [255]
1343 [255]
1344
1344
1345 $ hg grep --diff -fr2 data add0-rm2
1345 $ hg grep --diff -fr2 data add0-rm2
1346 abort: cannot follow file not in any of the specified revisions: "add0-rm2"
1346 abort: cannot follow file not in any of the specified revisions: "add0-rm2"
1347 [255]
1347 [255]
1348
1348
1349 BROKEN: should abort
1349 BROKEN: should abort
1350 $ hg grep -fr2 data add0-rm2
1350 $ hg grep -fr2 data add0-rm2
1351 add0-rm2:0:data0
1351 add0-rm2:0:data0
1352
1352
1353 follow file history from specified revision, multiple files:
1353 follow file history from specified revision, multiple files:
1354
1354
1355 $ hg log -fr2 add0-cp2 add0-mod2
1355 $ hg log -fr2 add0-cp2 add0-mod2
1356 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1356 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1357 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1357 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1358
1358
1359 $ hg grep --diff -fr2 data add0-cp2 add0-mod2
1359 $ hg grep --diff -fr2 data add0-cp2 add0-mod2
1360 add0-mod2:2:+:data2
1360 add0-mod2:2:+:data2
1361 add0:0:+:data0
1361 add0:0:+:data0
1362 add0-mod2:0:+:data0
1362 add0-mod2:0:+:data0
1363
1363
1364 BROKEN: should follow history across renames
1364 BROKEN: should follow history across renames
1365 $ hg grep -fr2 data add0-cp2 add0-mod2
1365 $ hg grep -fr2 data add0-cp2 add0-mod2
1366 add0-cp2:2:data0
1366 add0-cp2:2:data0
1367 add0-mod2:2:data0
1367 add0-mod2:2:data0
1368 add0-mod2:2:data2
1368 add0-mod2:2:data2
1369 add0-mod2:0:data0
1369 add0-mod2:0:data0
1370
1370
1371 follow file history from wdir, unmodified:
1371 follow file history from wdir, unmodified:
1372
1372
1373 $ hg log -fr'wdir()' add0-mod3
1373 $ hg log -fr'wdir()' add0-mod3
1374 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1374 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1375 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1375 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1376 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1376 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1377
1377
1378 $ hg grep --diff -fr'wdir()' data add0-mod3
1378 $ hg grep --diff -fr'wdir()' data add0-mod3
1379 add0-mod3:3:+:data3
1379 add0-mod3:3:+:data3
1380 add0-mod3:0:+:data0
1380 add0-mod3:0:+:data0
1381
1381
1382 $ hg grep -fr'wdir()' data add0-mod3
1382 $ hg grep -fr'wdir()' data add0-mod3
1383 add0-mod3:2147483647:data0
1383 add0-mod3:2147483647:data0
1384 add0-mod3:2147483647:data3
1384 add0-mod3:2147483647:data3
1385 add0-mod3:3:data0
1385 add0-mod3:3:data0
1386 add0-mod3:3:data3
1386 add0-mod3:3:data3
1387 add0-mod3:1:data0
1387 add0-mod3:1:data0
1388 add0-mod3:0:data0
1388 add0-mod3:0:data0
1389
1389
1390 follow file history from wdir, modified:
1390 follow file history from wdir, modified:
1391
1391
1392 $ hg log -fr'wdir()' add0-mod4
1392 $ hg log -fr'wdir()' add0-mod4
1393 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1393 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1394 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1394 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1395
1395
1396 $ hg grep --diff -fr'wdir()' data add0-mod4
1396 $ hg grep --diff -fr'wdir()' data add0-mod4
1397 add0-mod4:2147483647:+:data4
1397 add0-mod4:2147483647:+:data4
1398 add0-mod4:0:+:data0
1398 add0-mod4:0:+:data0
1399
1399
1400 $ hg grep -fr'wdir()' data add0-mod4
1400 $ hg grep -fr'wdir()' data add0-mod4
1401 add0-mod4:2147483647:data0
1401 add0-mod4:2147483647:data0
1402 add0-mod4:2147483647:data4
1402 add0-mod4:2147483647:data4
1403 add0-mod4:3:data0
1403 add0-mod4:3:data0
1404 add0-mod4:1:data0
1404 add0-mod4:1:data0
1405 add0-mod4:0:data0
1405 add0-mod4:0:data0
1406
1406
1407 follow file history from wdir, copied but unmodified:
1407 follow file history from wdir, copied but unmodified:
1408
1408
1409 $ hg log -fr'wdir()' add0-cp4
1409 $ hg log -fr'wdir()' add0-cp4
1410 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1410 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1411 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1411 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1412
1412
1413 $ hg grep --diff -fr'wdir()' data add0-cp4
1413 $ hg grep --diff -fr'wdir()' data add0-cp4
1414 add0:0:+:data0
1414 add0:0:+:data0
1415
1415
1416 BROKEN: should follow history across renames
1416 BROKEN: should follow history across renames
1417 $ hg grep -fr'wdir()' data add0-cp4
1417 $ hg grep -fr'wdir()' data add0-cp4
1418 add0-cp4:2147483647:data0
1418 add0-cp4:2147483647:data0
1419
1419
1420 follow file history from wdir, copied and modified:
1420 follow file history from wdir, copied and modified:
1421
1421
1422 $ hg log -fr'wdir()' add0-cp4-mod4
1422 $ hg log -fr'wdir()' add0-cp4-mod4
1423 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1423 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1424 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1424 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1425
1425
1426 $ hg grep --diff -fr'wdir()' data add0-cp4-mod4
1426 $ hg grep --diff -fr'wdir()' data add0-cp4-mod4
1427 add0-cp4-mod4:2147483647:+:data4
1427 add0-cp4-mod4:2147483647:+:data4
1428 add0:0:+:data0
1428 add0:0:+:data0
1429
1429
1430 BROKEN: should follow history across renames
1430 BROKEN: should follow history across renames
1431 $ hg grep -fr'wdir()' data add0-cp4-mod4
1431 $ hg grep -fr'wdir()' data add0-cp4-mod4
1432 add0-cp4-mod4:2147483647:data0
1432 add0-cp4-mod4:2147483647:data0
1433 add0-cp4-mod4:2147483647:data4
1433 add0-cp4-mod4:2147483647:data4
1434
1434
1435 follow file history from wdir, multiple files:
1435 follow file history from wdir, multiple files:
1436
1436
1437 $ hg log -fr'wdir()' add0-cp4 add0-mod4 add0-mod3
1437 $ hg log -fr'wdir()' add0-cp4 add0-mod4 add0-mod3
1438 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1438 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1439 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1439 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1440 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1440 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1441
1441
1442 $ hg grep --diff -fr'wdir()' data add0-cp4 add0-mod4 add0-mod3
1442 $ hg grep --diff -fr'wdir()' data add0-cp4 add0-mod4 add0-mod3
1443 add0-mod4:2147483647:+:data4
1443 add0-mod4:2147483647:+:data4
1444 add0-mod3:3:+:data3
1444 add0-mod3:3:+:data3
1445 add0:0:+:data0
1445 add0:0:+:data0
1446 add0-mod3:0:+:data0
1446 add0-mod3:0:+:data0
1447 add0-mod4:0:+:data0
1447 add0-mod4:0:+:data0
1448
1448
1449 BROKEN: should follow history across renames
1449 BROKEN: should follow history across renames
1450 $ hg grep -fr'wdir()' data add0-cp4 add0-mod4 add0-mod3
1450 $ hg grep -fr'wdir()' data add0-cp4 add0-mod4 add0-mod3
1451 add0-cp4:2147483647:data0
1451 add0-cp4:2147483647:data0
1452 add0-mod3:2147483647:data0
1452 add0-mod3:2147483647:data0
1453 add0-mod3:2147483647:data3
1453 add0-mod3:2147483647:data3
1454 add0-mod4:2147483647:data0
1454 add0-mod4:2147483647:data0
1455 add0-mod4:2147483647:data4
1455 add0-mod4:2147483647:data4
1456 add0-mod3:3:data0
1456 add0-mod3:3:data0
1457 add0-mod3:3:data3
1457 add0-mod3:3:data3
1458 add0-mod4:3:data0
1458 add0-mod4:3:data0
1459 add0-mod3:1:data0
1459 add0-mod3:1:data0
1460 add0-mod4:1:data0
1460 add0-mod4:1:data0
1461 add0-mod3:0:data0
1461 add0-mod3:0:data0
1462 add0-mod4:0:data0
1462 add0-mod4:0:data0
1463
1463
1464 $ cd ..
1464 $ cd ..
@@ -1,67 +1,62 b''
1 Test that, when an hg push is interrupted and the remote side recieves SIGPIPE,
1 Test that, when an hg push is interrupted and the remote side recieves SIGPIPE,
2 the remote hg is able to successfully roll back the transaction.
2 the remote hg is able to successfully roll back the transaction.
3
3
4 $ hg init -q remote
4 $ hg init -q remote
5 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" -q ssh://user@dummy/`pwd`/remote local
5 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" -q ssh://user@dummy/`pwd`/remote local
6
6
7 $ check_for_abandoned_transaction() {
7 $ check_for_abandoned_transaction() {
8 > [[ -f $TESTTMP/remote/.hg/store/journal ]] && echo "Abandoned transaction!"
8 > [ -f $TESTTMP/remote/.hg/store/journal ] && echo "Abandoned transaction!"
9 > }
9 > }
10
10
11 $ pidfile=`pwd`/pidfile
11 $ pidfile=`pwd`/pidfile
12 $ >$pidfile
12 $ >$pidfile
13
13
14 $ script() {
14 $ script() {
15 > cat >"$1"
15 > cat >"$1"
16 > chmod +x "$1"
16 > chmod +x "$1"
17 > }
17 > }
18
18
19 On the remote end, run hg, piping stdout and stderr through processes that we
19 On the remote end, run hg, piping stdout and stderr through processes that we
20 know the PIDs of. We will later kill these to simulate an ssh client
20 know the PIDs of. We will later kill these to simulate an ssh client
21 disconnecting.
21 disconnecting.
22
22
23 $ killable_pipe=`pwd`/killable_pipe.sh
23 $ killable_pipe=`pwd`/killable_pipe.sh
24 $ script $killable_pipe <<EOF
24 $ script $killable_pipe <<EOF
25 > #!/bin/bash
25 > #!/bin/bash
26 > echo \$\$ >> $pidfile
26 > echo \$\$ >> $pidfile
27 > exec cat
27 > exec cat
28 > EOF
28 > EOF
29
29
30 $ remotecmd=`pwd`/remotecmd.sh
30 $ remotecmd=`pwd`/remotecmd.sh
31 $ script $remotecmd <<EOF
31 $ script $remotecmd <<EOF
32 > #!/bin/bash
32 > #!/bin/bash
33 > hg "\$@" 1> >($killable_pipe) 2> >($killable_pipe >&2)
33 > hg "\$@" 1> >($killable_pipe) 2> >($killable_pipe >&2)
34 > EOF
34 > EOF
35
35
36 In the pretxnchangegroup hook, kill the PIDs recorded above to simulate ssh
36 In the pretxnchangegroup hook, kill the PIDs recorded above to simulate ssh
37 disconnecting. Then exit nonzero, to force a transaction rollback.
37 disconnecting. Then exit nonzero, to force a transaction rollback.
38
38
39 $ hook_script=`pwd`/pretxnchangegroup.sh
39 $ hook_script=`pwd`/pretxnchangegroup.sh
40 $ script $hook_script <<EOF
40 $ script $hook_script <<EOF
41 > #!/bin/bash
41 > #!/bin/bash
42 > for pid in \$(cat $pidfile) ; do
42 > for pid in \$(cat $pidfile) ; do
43 > kill \$pid
43 > kill \$pid
44 > while kill -0 \$pid 2>/dev/null ; do
44 > while kill -0 \$pid 2>/dev/null ; do
45 > sleep 0.1
45 > sleep 0.1
46 > done
46 > done
47 > done
47 > done
48 > exit 1
48 > exit 1
49 > EOF
49 > EOF
50
50
51 $ cat >remote/.hg/hgrc <<EOF
51 $ cat >remote/.hg/hgrc <<EOF
52 > [hooks]
52 > [hooks]
53 > pretxnchangegroup.break-things=$hook_script
53 > pretxnchangegroup.break-things=$hook_script
54 > EOF
54 > EOF
55
55
56 $ cd local
56 $ cd local
57 $ echo foo > foo ; hg commit -qAm "commit"
57 $ echo foo > foo ; hg commit -qAm "commit"
58 $ hg push -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --remotecmd $remotecmd 2>&1 | grep -v $killable_pipe
58 $ hg push -q -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --remotecmd $remotecmd 2>&1 | grep -v $killable_pipe
59 pushing to ssh://user@dummy/$TESTTMP/remote
60 searching for changes
61 remote: adding changesets
62 remote: adding manifests
63 remote: adding file changes
64 abort: stream ended unexpectedly (got 0 bytes, expected 4)
59 abort: stream ended unexpectedly (got 0 bytes, expected 4)
65
60
66 $ check_for_abandoned_transaction
61 $ check_for_abandoned_transaction
67 [1]
62 [1]
General Comments 0
You need to be logged in to leave comments. Login now