##// END OF EJS Templates
merge with stable
Augie Fackler -
r42406:e64d8d73 merge default
parent child Browse files
Show More
@@ -1,180 +1,181 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,193 +1,194 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
@@ -1,76 +1,76 b''
1 PYTHONVER=2.7.14
1 PYTHONVER=2.7.16
2 PYTHONNAME=python-
2 PYTHONNAME=python-
3 PREFIX=$(HOME)/bin/prefix-$(PYTHONNAME)$(PYTHONVER)
3 PREFIX=$(HOME)/bin/prefix-$(PYTHONNAME)$(PYTHONVER)
4 SYMLINKDIR=$(HOME)/bin
4 SYMLINKDIR=$(HOME)/bin
5
5
6 help:
6 help:
7 @echo
7 @echo
8 @echo 'Make a custom installation of a Python version'
8 @echo 'Make a custom installation of a Python version'
9 @echo
9 @echo
10 @echo 'Common make parameters:'
10 @echo 'Common make parameters:'
11 @echo ' PYTHONVER=... [$(PYTHONVER)]'
11 @echo ' PYTHONVER=... [$(PYTHONVER)]'
12 @echo ' PREFIX=... [$(PREFIX)]'
12 @echo ' PREFIX=... [$(PREFIX)]'
13 @echo ' SYMLINKDIR=... [$(SYMLINKDIR) creating $(PYTHONNAME)$(PYTHONVER)]'
13 @echo ' SYMLINKDIR=... [$(SYMLINKDIR) creating $(PYTHONNAME)$(PYTHONVER)]'
14 @echo
14 @echo
15 @echo 'Common make targets:'
15 @echo 'Common make targets:'
16 @echo ' python - install Python $$PYTHONVER in $$PREFIX'
16 @echo ' python - install Python $$PYTHONVER in $$PREFIX'
17 @echo ' symlink - create a $$SYMLINKDIR/$(PYTHONNAME)$$PYTHONVER symlink'
17 @echo ' symlink - create a $$SYMLINKDIR/$(PYTHONNAME)$$PYTHONVER symlink'
18 @echo
18 @echo
19 @echo 'Example: create a temporary Python installation:'
19 @echo 'Example: create a temporary Python installation:'
20 @echo ' $$ make -f Makefile.python python PYTHONVER=${PYTHONVER} PREFIX=/tmp/p27'
20 @echo ' $$ make -f Makefile.python python PYTHONVER=${PYTHONVER} PREFIX=/tmp/p27'
21 @echo ' $$ /tmp/p27/bin/python -V'
21 @echo ' $$ /tmp/p27/bin/python -V'
22 @echo ' Python 2.7'
22 @echo ' Python 2.7'
23 @echo
23 @echo
24 @echo 'Some external libraries are required for building Python: zlib bzip2 openssl.'
24 @echo 'Some external libraries are required for building Python: zlib bzip2 openssl.'
25 @echo 'Make sure their development packages are installed systemwide.'
25 @echo 'Make sure their development packages are installed systemwide.'
26 # fedora: yum install zlib-devel bzip2-devel openssl-devel
26 # fedora: yum install zlib-devel bzip2-devel openssl-devel
27 # debian: apt-get install zlib1g-dev libbz2-dev libssl-dev
27 # debian: apt-get install zlib1g-dev libbz2-dev libssl-dev
28 @echo
28 @echo
29 @echo 'To build a nice collection of interesting Python versions:'
29 @echo 'To build a nice collection of interesting Python versions:'
30 @echo ' $$ for v in 2.{6{,.1,.2,.9},7{,.8,.10}}; do'
30 @echo ' $$ for v in 2.{6{,.1,.2,.9},7{,.8,.10}}; do'
31 @echo ' make -f Makefile.python symlink PYTHONVER=$$v || break; done'
31 @echo ' make -f Makefile.python symlink PYTHONVER=$$v || break; done'
32 @echo 'To run a Mercurial test on all these Python versions:'
32 @echo 'To run a Mercurial test on all these Python versions:'
33 @echo ' $$ for py in `cd ~/bin && ls $(PYTHONNAME)2.*`; do'
33 @echo ' $$ for py in `cd ~/bin && ls $(PYTHONNAME)2.*`; do'
34 @echo ' echo $$py; $$py run-tests.py test-http.t; echo; done'
34 @echo ' echo $$py; $$py run-tests.py test-http.t; echo; done'
35 @echo
35 @echo
36
36
37 export LANGUAGE=C
37 export LANGUAGE=C
38 export LC_ALL=C
38 export LC_ALL=C
39
39
40 python: $(PREFIX)/bin/python docutils
40 python: $(PREFIX)/bin/python docutils
41 printf 'import sys, zlib, bz2, docutils, ssl' | $(PREFIX)/bin/python
41 printf 'import sys, zlib, bz2, docutils, ssl' | $(PREFIX)/bin/python
42
42
43 PYTHON_SRCDIR=Python-$(PYTHONVER)
43 PYTHON_SRCDIR=Python-$(PYTHONVER)
44 PYTHON_SRCFILE=$(PYTHON_SRCDIR).tgz
44 PYTHON_SRCFILE=$(PYTHON_SRCDIR).tgz
45
45
46 $(PREFIX)/bin/python:
46 $(PREFIX)/bin/python:
47 [ -f $(PYTHON_SRCFILE) ] || wget http://www.python.org/ftp/python/$(PYTHONVER)/$(PYTHON_SRCFILE) || curl -OL http://www.python.org/ftp/python/$(PYTHONVER)/$(PYTHON_SRCFILE) || [ -f $(PYTHON_SRCFILE) ]
47 [ -f $(PYTHON_SRCFILE) ] || wget http://www.python.org/ftp/python/$(PYTHONVER)/$(PYTHON_SRCFILE) || curl -OL http://www.python.org/ftp/python/$(PYTHONVER)/$(PYTHON_SRCFILE) || [ -f $(PYTHON_SRCFILE) ]
48 rm -rf $(PYTHON_SRCDIR)
48 rm -rf $(PYTHON_SRCDIR)
49 tar xf $(PYTHON_SRCFILE)
49 tar xf $(PYTHON_SRCFILE)
50 # Debian/Ubuntu disables SSLv2,3 the hard way, disable it on old Pythons too
50 # Debian/Ubuntu disables SSLv2,3 the hard way, disable it on old Pythons too
51 -sed -i 's,self.*SSLv[23]_method(),0;//\0,g' $(PYTHON_SRCDIR)/Modules/_ssl.c
51 -sed -i 's,self.*SSLv[23]_method(),0;//\0,g' $(PYTHON_SRCDIR)/Modules/_ssl.c
52 # Find multiarch system libraries on Ubuntu and disable fortify error when setting argv
52 # Find multiarch system libraries on Ubuntu and disable fortify error when setting argv
53 LDFLAGS="-L/usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH`"; \
53 LDFLAGS="-L/usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH`"; \
54 BASECFLAGS=-U_FORTIFY_SOURCE; \
54 BASECFLAGS=-U_FORTIFY_SOURCE; \
55 export LDFLAGS BASECFLAGS; \
55 export LDFLAGS BASECFLAGS; \
56 cd $(PYTHON_SRCDIR) && ./configure --prefix=$(PREFIX) && make all SVNVERSION=pwd && make install
56 cd $(PYTHON_SRCDIR) && ./configure --prefix=$(PREFIX) && make all SVNVERSION=pwd && make install
57 printf 'import sys, zlib, bz2, ssl' | $(PREFIX)/bin/python
57 printf 'import sys, zlib, bz2, ssl' | $(PREFIX)/bin/python
58 rm -rf $(PYTHON_SRCDIR)
58 rm -rf $(PYTHON_SRCDIR)
59
59
60 DOCUTILSVER=0.12
60 DOCUTILSVER=0.12
61 DOCUTILS_SRCDIR=docutils-$(DOCUTILSVER)
61 DOCUTILS_SRCDIR=docutils-$(DOCUTILSVER)
62 DOCUTILS_SRCFILE=$(DOCUTILS_SRCDIR).tar.gz
62 DOCUTILS_SRCFILE=$(DOCUTILS_SRCDIR).tar.gz
63
63
64 docutils: $(PREFIX)/bin/python
64 docutils: $(PREFIX)/bin/python
65 @$(PREFIX)/bin/python -c 'import docutils' || ( set -ex; \
65 @$(PREFIX)/bin/python -c 'import docutils' || ( set -ex; \
66 [ -f $(DOCUTILS_SRCFILE) ] || wget http://downloads.sourceforge.net/project/docutils/docutils/$(DOCUTILSVER)/$(DOCUTILS_SRCFILE) || [ -f $(DOCUTILS_SRCFILE) ]; \
66 [ -f $(DOCUTILS_SRCFILE) ] || wget http://downloads.sourceforge.net/project/docutils/docutils/$(DOCUTILSVER)/$(DOCUTILS_SRCFILE) || [ -f $(DOCUTILS_SRCFILE) ]; \
67 rm -rf $(DOCUTILS_SRCDIR); \
67 rm -rf $(DOCUTILS_SRCDIR); \
68 tar xf $(DOCUTILS_SRCFILE); \
68 tar xf $(DOCUTILS_SRCFILE); \
69 cd $(DOCUTILS_SRCDIR) && $(PREFIX)/bin/python setup.py install --prefix=$(PREFIX); \
69 cd $(DOCUTILS_SRCDIR) && $(PREFIX)/bin/python setup.py install --prefix=$(PREFIX); \
70 $(PREFIX)/bin/python -c 'import docutils'; \
70 $(PREFIX)/bin/python -c 'import docutils'; \
71 rm -rf $(DOCUTILS_SRCDIR); )
71 rm -rf $(DOCUTILS_SRCDIR); )
72
72
73 symlink: python $(SYMLINKDIR)
73 symlink: python $(SYMLINKDIR)
74 ln -sf $(PREFIX)/bin/python $(SYMLINKDIR)/$(PYTHONNAME)$(PYTHONVER)
74 ln -sf $(PREFIX)/bin/python $(SYMLINKDIR)/$(PYTHONNAME)$(PYTHONVER)
75
75
76 .PHONY: help python docutils symlink
76 .PHONY: help python docutils symlink
@@ -1,160 +1,160 b''
1 #!/bin/bash -e
1 #!/bin/bash -e
2 #
2 #
3 # Build a Mercurial RPM from the current repo
3 # Build a Mercurial RPM from the current repo
4 #
4 #
5 # Tested on
5 # Tested on
6 # - Fedora 20
6 # - Fedora 20
7 # - CentOS 5
7 # - CentOS 5
8 # - centOS 6
8 # - centOS 6
9
9
10 . $(dirname $0)/packagelib.sh
10 . $(dirname $0)/packagelib.sh
11
11
12 BUILD=1
12 BUILD=1
13 RPMBUILDDIR="$PWD/rpmbuild"
13 RPMBUILDDIR="$PWD/rpmbuild"
14
14
15 while [ "$1" ]; do
15 while [ "$1" ]; do
16 case "$1" in
16 case "$1" in
17 --prepare )
17 --prepare )
18 shift
18 shift
19 BUILD=
19 BUILD=
20 ;;
20 ;;
21 --withpython | --with-python)
21 --withpython | --with-python)
22 shift
22 shift
23 PYTHONVER=2.7.14
23 PYTHONVER=2.7.16
24 PYTHONMD5=cee2e4b33ad3750da77b2e85f2f8b724
24 PYTHONMD5=f1a2ace631068444831d01485466ece0
25 ;;
25 ;;
26 --rpmbuilddir )
26 --rpmbuilddir )
27 shift
27 shift
28 RPMBUILDDIR="$1"
28 RPMBUILDDIR="$1"
29 shift
29 shift
30 ;;
30 ;;
31 * )
31 * )
32 echo "Invalid parameter $1!" 1>&2
32 echo "Invalid parameter $1!" 1>&2
33 exit 1
33 exit 1
34 ;;
34 ;;
35 esac
35 esac
36 done
36 done
37
37
38 cd "`dirname $0`/../.."
38 cd "`dirname $0`/../.."
39
39
40 specfile=$PWD/contrib/packaging/mercurial.spec
40 specfile=$PWD/contrib/packaging/mercurial.spec
41 if [ ! -f $specfile ]; then
41 if [ ! -f $specfile ]; then
42 echo "Cannot find $specfile!" 1>&2
42 echo "Cannot find $specfile!" 1>&2
43 exit 1
43 exit 1
44 fi
44 fi
45
45
46 if [ ! -d .hg ]; then
46 if [ ! -d .hg ]; then
47 echo 'You are not inside a Mercurial repository!' 1>&2
47 echo 'You are not inside a Mercurial repository!' 1>&2
48 exit 1
48 exit 1
49 fi
49 fi
50
50
51 gethgversion
51 gethgversion
52
52
53 if [ -z "$type" ] ; then
53 if [ -z "$type" ] ; then
54 release=1
54 release=1
55 else
55 else
56 release=0.9_$type
56 release=0.9_$type
57 fi
57 fi
58
58
59 if [ -n "$distance" ] ; then
59 if [ -n "$distance" ] ; then
60 release=$release+${distance}_${node}
60 release=$release+${distance}_${node}
61 fi
61 fi
62
62
63 if [ "$PYTHONVER" ]; then
63 if [ "$PYTHONVER" ]; then
64 release=$release+$PYTHONVER
64 release=$release+$PYTHONVER
65 RPMPYTHONVER=$PYTHONVER
65 RPMPYTHONVER=$PYTHONVER
66 else
66 else
67 RPMPYTHONVER=%{nil}
67 RPMPYTHONVER=%{nil}
68 fi
68 fi
69
69
70 mkdir -p $RPMBUILDDIR/{SOURCES,BUILD,SRPMS,RPMS}
70 mkdir -p $RPMBUILDDIR/{SOURCES,BUILD,SRPMS,RPMS}
71 $HG archive -t tgz $RPMBUILDDIR/SOURCES/mercurial-$version-$release.tar.gz
71 $HG archive -t tgz $RPMBUILDDIR/SOURCES/mercurial-$version-$release.tar.gz
72 if [ "$PYTHONVER" ]; then
72 if [ "$PYTHONVER" ]; then
73 (
73 (
74 mkdir -p build
74 mkdir -p build
75 cd build
75 cd build
76 PYTHON_SRCFILE=Python-$PYTHONVER.tgz
76 PYTHON_SRCFILE=Python-$PYTHONVER.tgz
77 [ -f $PYTHON_SRCFILE ] || curl -Lo $PYTHON_SRCFILE http://www.python.org/ftp/python/$PYTHONVER/$PYTHON_SRCFILE
77 [ -f $PYTHON_SRCFILE ] || curl -Lo $PYTHON_SRCFILE http://www.python.org/ftp/python/$PYTHONVER/$PYTHON_SRCFILE
78 if [ "$PYTHONMD5" ]; then
78 if [ "$PYTHONMD5" ]; then
79 echo "$PYTHONMD5 $PYTHON_SRCFILE" | md5sum -w -c
79 echo "$PYTHONMD5 $PYTHON_SRCFILE" | md5sum -w -c
80 fi
80 fi
81 ln -f $PYTHON_SRCFILE $RPMBUILDDIR/SOURCES/$PYTHON_SRCFILE
81 ln -f $PYTHON_SRCFILE $RPMBUILDDIR/SOURCES/$PYTHON_SRCFILE
82
82
83 DOCUTILSVER=`sed -ne "s/^%global docutilsname docutils-//p" $specfile`
83 DOCUTILSVER=`sed -ne "s/^%global docutilsname docutils-//p" $specfile`
84 DOCUTILS_SRCFILE=docutils-$DOCUTILSVER.tar.gz
84 DOCUTILS_SRCFILE=docutils-$DOCUTILSVER.tar.gz
85 [ -f $DOCUTILS_SRCFILE ] || curl -Lo $DOCUTILS_SRCFILE http://downloads.sourceforge.net/project/docutils/docutils/$DOCUTILSVER/$DOCUTILS_SRCFILE
85 [ -f $DOCUTILS_SRCFILE ] || curl -Lo $DOCUTILS_SRCFILE http://downloads.sourceforge.net/project/docutils/docutils/$DOCUTILSVER/$DOCUTILS_SRCFILE
86 DOCUTILSMD5=`sed -ne "s/^%global docutilsmd5 //p" $specfile`
86 DOCUTILSMD5=`sed -ne "s/^%global docutilsmd5 //p" $specfile`
87 if [ "$DOCUTILSMD5" ]; then
87 if [ "$DOCUTILSMD5" ]; then
88 echo "$DOCUTILSMD5 $DOCUTILS_SRCFILE" | md5sum -w -c
88 echo "$DOCUTILSMD5 $DOCUTILS_SRCFILE" | md5sum -w -c
89 fi
89 fi
90 ln -f $DOCUTILS_SRCFILE $RPMBUILDDIR/SOURCES/$DOCUTILS_SRCFILE
90 ln -f $DOCUTILS_SRCFILE $RPMBUILDDIR/SOURCES/$DOCUTILS_SRCFILE
91 )
91 )
92 fi
92 fi
93
93
94 mkdir -p $RPMBUILDDIR/SPECS
94 mkdir -p $RPMBUILDDIR/SPECS
95 rpmspec=$RPMBUILDDIR/SPECS/mercurial.spec
95 rpmspec=$RPMBUILDDIR/SPECS/mercurial.spec
96
96
97 sed -e "s,^Version:.*,Version: $version," \
97 sed -e "s,^Version:.*,Version: $version," \
98 -e "s,^Release:.*,Release: $release," \
98 -e "s,^Release:.*,Release: $release," \
99 $specfile > $rpmspec
99 $specfile > $rpmspec
100
100
101 echo >> $rpmspec
101 echo >> $rpmspec
102 echo "%changelog" >> $rpmspec
102 echo "%changelog" >> $rpmspec
103
103
104 if echo $version | grep '+' > /dev/null 2>&1; then
104 if echo $version | grep '+' > /dev/null 2>&1; then
105 latesttag="`echo $version | sed -e 's/+.*//'`"
105 latesttag="`echo $version | sed -e 's/+.*//'`"
106 $HG log -r .:"$latesttag" -fM \
106 $HG log -r .:"$latesttag" -fM \
107 --template '{date|hgdate}\t{author}\t{desc|firstline}\n' | python -c '
107 --template '{date|hgdate}\t{author}\t{desc|firstline}\n' | python -c '
108 import sys, time
108 import sys, time
109
109
110 def datestr(date, format):
110 def datestr(date, format):
111 return time.strftime(format, time.gmtime(float(date[0]) - date[1]))
111 return time.strftime(format, time.gmtime(float(date[0]) - date[1]))
112
112
113 changelog = []
113 changelog = []
114 for l in sys.stdin.readlines():
114 for l in sys.stdin.readlines():
115 tok = l.split("\t")
115 tok = l.split("\t")
116 hgdate = tuple(int(v) for v in tok[0].split())
116 hgdate = tuple(int(v) for v in tok[0].split())
117 changelog.append((datestr(hgdate, "%F"), tok[1], hgdate, tok[2]))
117 changelog.append((datestr(hgdate, "%F"), tok[1], hgdate, tok[2]))
118 prevtitle = ""
118 prevtitle = ""
119 for l in sorted(changelog, reverse=True):
119 for l in sorted(changelog, reverse=True):
120 title = "* %s %s" % (datestr(l[2], "%a %b %d %Y"), l[1])
120 title = "* %s %s" % (datestr(l[2], "%a %b %d %Y"), l[1])
121 if prevtitle != title:
121 if prevtitle != title:
122 prevtitle = title
122 prevtitle = title
123 print
123 print
124 print title
124 print title
125 print "- %s" % l[3].strip()
125 print "- %s" % l[3].strip()
126 ' >> $rpmspec
126 ' >> $rpmspec
127
127
128 else
128 else
129
129
130 $HG log \
130 $HG log \
131 --template '{date|hgdate}\t{author}\t{desc|firstline}\n' \
131 --template '{date|hgdate}\t{author}\t{desc|firstline}\n' \
132 .hgtags | python -c '
132 .hgtags | python -c '
133 import sys, time
133 import sys, time
134
134
135 def datestr(date, format):
135 def datestr(date, format):
136 return time.strftime(format, time.gmtime(float(date[0]) - date[1]))
136 return time.strftime(format, time.gmtime(float(date[0]) - date[1]))
137
137
138 for l in sys.stdin.readlines():
138 for l in sys.stdin.readlines():
139 tok = l.split("\t")
139 tok = l.split("\t")
140 hgdate = tuple(int(v) for v in tok[0].split())
140 hgdate = tuple(int(v) for v in tok[0].split())
141 print "* %s %s\n- %s" % (datestr(hgdate, "%a %b %d %Y"), tok[1], tok[2])
141 print "* %s %s\n- %s" % (datestr(hgdate, "%a %b %d %Y"), tok[1], tok[2])
142 ' >> $rpmspec
142 ' >> $rpmspec
143
143
144 fi
144 fi
145
145
146 sed -i \
146 sed -i \
147 -e "s/^%define withpython.*$/%define withpython $RPMPYTHONVER/" \
147 -e "s/^%define withpython.*$/%define withpython $RPMPYTHONVER/" \
148 $rpmspec
148 $rpmspec
149
149
150 if [ "$BUILD" ]; then
150 if [ "$BUILD" ]; then
151 rpmbuild --define "_topdir $RPMBUILDDIR" -ba $rpmspec --clean
151 rpmbuild --define "_topdir $RPMBUILDDIR" -ba $rpmspec --clean
152 if [ $? = 0 ]; then
152 if [ $? = 0 ]; then
153 echo
153 echo
154 echo "Built packages for $version-$release:"
154 echo "Built packages for $version-$release:"
155 find $RPMBUILDDIR/*RPMS/ -type f -newer $rpmspec
155 find $RPMBUILDDIR/*RPMS/ -type f -newer $rpmspec
156 fi
156 fi
157 else
157 else
158 echo "Prepared sources for $version-$release $rpmspec are in $RPMBUILDDIR/SOURCES/ - use like:"
158 echo "Prepared sources for $version-$release $rpmspec are in $RPMBUILDDIR/SOURCES/ - use like:"
159 echo "rpmbuild --define '_topdir $RPMBUILDDIR' -ba $rpmspec --clean"
159 echo "rpmbuild --define '_topdir $RPMBUILDDIR' -ba $rpmspec --clean"
160 fi
160 fi
@@ -1,38 +1,38 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 contrib/packaging/inno/requirements.txt.in -o contrib/packaging/inno/requirements.txt
5 # pip-compile --generate-hashes contrib/packaging/inno/requirements.txt.in -o contrib/packaging/inno/requirements.txt
6 #
6 #
7 certifi==2018.11.29 \
7 certifi==2018.11.29 \
8 --hash=sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7 \
8 --hash=sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7 \
9 --hash=sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033 \
9 --hash=sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033 \
10 # via dulwich
10 # via dulwich
11 configparser==3.7.3 \
11 configparser==3.7.3 \
12 --hash=sha256:27594cf4fc279f321974061ac69164aaebd2749af962ac8686b20503ac0bcf2d \
12 --hash=sha256:27594cf4fc279f321974061ac69164aaebd2749af962ac8686b20503ac0bcf2d \
13 --hash=sha256:9d51fe0a382f05b6b117c5e601fc219fede4a8c71703324af3f7d883aef476a3 \
13 --hash=sha256:9d51fe0a382f05b6b117c5e601fc219fede4a8c71703324af3f7d883aef476a3 \
14 # via entrypoints
14 # via entrypoints
15 docutils==0.14 \
15 docutils==0.14 \
16 --hash=sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6 \
16 --hash=sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6 \
17 --hash=sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274 \
17 --hash=sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274 \
18 --hash=sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6
18 --hash=sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6
19 dulwich==0.19.11 \
19 dulwich==0.19.11 \
20 --hash=sha256:afbe070f6899357e33f63f3f3696e601731fef66c64a489dea1bc9f539f4a725
20 --hash=sha256:afbe070f6899357e33f63f3f3696e601731fef66c64a489dea1bc9f539f4a725
21 entrypoints==0.3 \
21 entrypoints==0.3 \
22 --hash=sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19 \
22 --hash=sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19 \
23 --hash=sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451 \
23 --hash=sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451 \
24 # via keyring
24 # via keyring
25 keyring==18.0.0 \
25 keyring==18.0.1 \
26 --hash=sha256:12833d2b05d2055e0e25931184af9cd6a738f320a2264853cabbd8a3a0f0b65d \
26 --hash=sha256:67d6cc0132bd77922725fae9f18366bb314fd8f95ff4d323a4df41890a96a838 \
27 --hash=sha256:ca33f5ccc542b9ffaa196ee9a33488069e5e7eac77d5b81969f8a3ce74d0230c
27 --hash=sha256:7b29ebfcf8678c4da531b2478a912eea01e80007e5ddca9ee0c7038cb3489ec6
28 pygments==2.3.1 \
28 pygments==2.3.1 \
29 --hash=sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a \
29 --hash=sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a \
30 --hash=sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d
30 --hash=sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d
31 pywin32-ctypes==0.2.0 \
31 pywin32-ctypes==0.2.0 \
32 --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
32 --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
33 --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 \
33 --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 \
34 # via keyring
34 # via keyring
35 urllib3==1.24.1 \
35 urllib3==1.24.1 \
36 --hash=sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39 \
36 --hash=sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39 \
37 --hash=sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22 \
37 --hash=sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22 \
38 # via dulwich
38 # via dulwich
@@ -1,280 +1,300 b''
1 # narrowbundle2.py - bundle2 extensions for narrow repository support
1 # narrowbundle2.py - bundle2 extensions for narrow repository support
2 #
2 #
3 # Copyright 2017 Google, Inc.
3 # Copyright 2017 Google, 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 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import struct
11 import struct
12
12
13 from mercurial.i18n import _
13 from mercurial.i18n import _
14 from mercurial.node import (
14 from mercurial.node import (
15 bin,
15 bin,
16 nullid,
16 nullid,
17 )
17 )
18 from mercurial import (
18 from mercurial import (
19 bundle2,
19 bundle2,
20 changegroup,
20 changegroup,
21 error,
21 error,
22 exchange,
22 exchange,
23 localrepo,
23 localrepo,
24 narrowspec,
24 narrowspec,
25 repair,
25 repair,
26 repository,
26 repository,
27 util,
27 util,
28 wireprototypes,
28 wireprototypes,
29 )
29 )
30 from mercurial.utils import (
30 from mercurial.utils import (
31 stringutil,
31 stringutil,
32 )
32 )
33
33
34 _NARROWACL_SECTION = 'narrowhgacl'
34 _NARROWACL_SECTION = 'narrowacl'
35 _CHANGESPECPART = 'narrow:changespec'
35 _CHANGESPECPART = 'narrow:changespec'
36 _RESSPECS = 'narrow:responsespec'
36 _SPECPART = 'narrow:spec'
37 _SPECPART = 'narrow:spec'
37 _SPECPART_INCLUDE = 'include'
38 _SPECPART_INCLUDE = 'include'
38 _SPECPART_EXCLUDE = 'exclude'
39 _SPECPART_EXCLUDE = 'exclude'
39 _KILLNODESIGNAL = 'KILL'
40 _KILLNODESIGNAL = 'KILL'
40 _DONESIGNAL = 'DONE'
41 _DONESIGNAL = 'DONE'
41 _ELIDEDCSHEADER = '>20s20s20sl' # cset id, p1, p2, len(text)
42 _ELIDEDCSHEADER = '>20s20s20sl' # cset id, p1, p2, len(text)
42 _ELIDEDMFHEADER = '>20s20s20s20sl' # manifest id, p1, p2, link id, len(text)
43 _ELIDEDMFHEADER = '>20s20s20s20sl' # manifest id, p1, p2, link id, len(text)
43 _CSHEADERSIZE = struct.calcsize(_ELIDEDCSHEADER)
44 _CSHEADERSIZE = struct.calcsize(_ELIDEDCSHEADER)
44 _MFHEADERSIZE = struct.calcsize(_ELIDEDMFHEADER)
45 _MFHEADERSIZE = struct.calcsize(_ELIDEDMFHEADER)
45
46
46 # Serve a changegroup for a client with a narrow clone.
47 # Serve a changegroup for a client with a narrow clone.
47 def getbundlechangegrouppart_narrow(bundler, repo, source,
48 def getbundlechangegrouppart_narrow(bundler, repo, source,
48 bundlecaps=None, b2caps=None, heads=None,
49 bundlecaps=None, b2caps=None, heads=None,
49 common=None, **kwargs):
50 common=None, **kwargs):
50 assert repo.ui.configbool('experimental', 'narrowservebrokenellipses')
51 assert repo.ui.configbool('experimental', 'narrowservebrokenellipses')
51
52
52 cgversions = b2caps.get('changegroup')
53 cgversions = b2caps.get('changegroup')
53 if cgversions: # 3.1 and 3.2 ship with an empty value
54 if cgversions: # 3.1 and 3.2 ship with an empty value
54 cgversions = [v for v in cgversions
55 cgversions = [v for v in cgversions
55 if v in changegroup.supportedoutgoingversions(repo)]
56 if v in changegroup.supportedoutgoingversions(repo)]
56 if not cgversions:
57 if not cgversions:
57 raise ValueError(_('no common changegroup version'))
58 raise ValueError(_('no common changegroup version'))
58 version = max(cgversions)
59 version = max(cgversions)
59 else:
60 else:
60 raise ValueError(_("server does not advertise changegroup version,"
61 raise ValueError(_("server does not advertise changegroup version,"
61 " can't negotiate support for ellipsis nodes"))
62 " can't negotiate support for ellipsis nodes"))
62
63
63 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
64 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
64 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
65 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
65 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
66 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
66
67
67 depth = kwargs.get(r'depth', None)
68 depth = kwargs.get(r'depth', None)
68 if depth is not None:
69 if depth is not None:
69 depth = int(depth)
70 depth = int(depth)
70 if depth < 1:
71 if depth < 1:
71 raise error.Abort(_('depth must be positive, got %d') % depth)
72 raise error.Abort(_('depth must be positive, got %d') % depth)
72
73
73 heads = set(heads or repo.heads())
74 heads = set(heads or repo.heads())
74 common = set(common or [nullid])
75 common = set(common or [nullid])
75 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
76 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
76 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
77 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
77 known = {bin(n) for n in kwargs.get(r'known', [])}
78 known = {bin(n) for n in kwargs.get(r'known', [])}
78 if known and (oldinclude != include or oldexclude != exclude):
79 if known and (oldinclude != include or oldexclude != exclude):
79 # Steps:
80 # Steps:
80 # 1. Send kill for "$known & ::common"
81 # 1. Send kill for "$known & ::common"
81 #
82 #
82 # 2. Send changegroup for ::common
83 # 2. Send changegroup for ::common
83 #
84 #
84 # 3. Proceed.
85 # 3. Proceed.
85 #
86 #
86 # In the future, we can send kills for only the specific
87 # In the future, we can send kills for only the specific
87 # nodes we know should go away or change shape, and then
88 # nodes we know should go away or change shape, and then
88 # send a data stream that tells the client something like this:
89 # send a data stream that tells the client something like this:
89 #
90 #
90 # a) apply this changegroup
91 # a) apply this changegroup
91 # b) apply nodes XXX, YYY, ZZZ that you already have
92 # b) apply nodes XXX, YYY, ZZZ that you already have
92 # c) goto a
93 # c) goto a
93 #
94 #
94 # until they've built up the full new state.
95 # until they've built up the full new state.
95 # Convert to revnums and intersect with "common". The client should
96 # Convert to revnums and intersect with "common". The client should
96 # have made it a subset of "common" already, but let's be safe.
97 # have made it a subset of "common" already, but let's be safe.
97 known = set(repo.revs("%ln & ::%ln", known, common))
98 known = set(repo.revs("%ln & ::%ln", known, common))
98 # TODO: we could send only roots() of this set, and the
99 # TODO: we could send only roots() of this set, and the
99 # list of nodes in common, and the client could work out
100 # list of nodes in common, and the client could work out
100 # what to strip, instead of us explicitly sending every
101 # what to strip, instead of us explicitly sending every
101 # single node.
102 # single node.
102 deadrevs = known
103 deadrevs = known
103 def genkills():
104 def genkills():
104 for r in deadrevs:
105 for r in deadrevs:
105 yield _KILLNODESIGNAL
106 yield _KILLNODESIGNAL
106 yield repo.changelog.node(r)
107 yield repo.changelog.node(r)
107 yield _DONESIGNAL
108 yield _DONESIGNAL
108 bundler.newpart(_CHANGESPECPART, data=genkills())
109 bundler.newpart(_CHANGESPECPART, data=genkills())
109 newvisit, newfull, newellipsis = exchange._computeellipsis(
110 newvisit, newfull, newellipsis = exchange._computeellipsis(
110 repo, set(), common, known, newmatch)
111 repo, set(), common, known, newmatch)
111 if newvisit:
112 if newvisit:
112 packer = changegroup.getbundler(version, repo,
113 packer = changegroup.getbundler(version, repo,
113 matcher=newmatch,
114 matcher=newmatch,
114 ellipses=True,
115 ellipses=True,
115 shallow=depth is not None,
116 shallow=depth is not None,
116 ellipsisroots=newellipsis,
117 ellipsisroots=newellipsis,
117 fullnodes=newfull)
118 fullnodes=newfull)
118 cgdata = packer.generate(common, newvisit, False, 'narrow_widen')
119 cgdata = packer.generate(common, newvisit, False, 'narrow_widen')
119
120
120 part = bundler.newpart('changegroup', data=cgdata)
121 part = bundler.newpart('changegroup', data=cgdata)
121 part.addparam('version', version)
122 part.addparam('version', version)
122 if 'treemanifest' in repo.requirements:
123 if 'treemanifest' in repo.requirements:
123 part.addparam('treemanifest', '1')
124 part.addparam('treemanifest', '1')
124
125
125 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
126 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
126 repo, common, heads, set(), newmatch, depth=depth)
127 repo, common, heads, set(), newmatch, depth=depth)
127
128
128 repo.ui.debug('Found %d relevant revs\n' % len(relevant_nodes))
129 repo.ui.debug('Found %d relevant revs\n' % len(relevant_nodes))
129 if visitnodes:
130 if visitnodes:
130 packer = changegroup.getbundler(version, repo,
131 packer = changegroup.getbundler(version, repo,
131 matcher=newmatch,
132 matcher=newmatch,
132 ellipses=True,
133 ellipses=True,
133 shallow=depth is not None,
134 shallow=depth is not None,
134 ellipsisroots=ellipsisroots,
135 ellipsisroots=ellipsisroots,
135 fullnodes=relevant_nodes)
136 fullnodes=relevant_nodes)
136 cgdata = packer.generate(common, visitnodes, False, 'narrow_widen')
137 cgdata = packer.generate(common, visitnodes, False, 'narrow_widen')
137
138
138 part = bundler.newpart('changegroup', data=cgdata)
139 part = bundler.newpart('changegroup', data=cgdata)
139 part.addparam('version', version)
140 part.addparam('version', version)
140 if 'treemanifest' in repo.requirements:
141 if 'treemanifest' in repo.requirements:
141 part.addparam('treemanifest', '1')
142 part.addparam('treemanifest', '1')
142
143
143 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE))
144 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE))
144 def _handlechangespec_2(op, inpart):
145 def _handlechangespec_2(op, inpart):
146 # XXX: This bundle2 handling is buggy and should be removed after hg5.2 is
147 # released. New servers will send a mandatory bundle2 part named
148 # 'Narrowspec' and will send specs as data instead of params.
149 # Refer to issue5952 and 6019
145 includepats = set(inpart.params.get(_SPECPART_INCLUDE, '').splitlines())
150 includepats = set(inpart.params.get(_SPECPART_INCLUDE, '').splitlines())
146 excludepats = set(inpart.params.get(_SPECPART_EXCLUDE, '').splitlines())
151 excludepats = set(inpart.params.get(_SPECPART_EXCLUDE, '').splitlines())
147 narrowspec.validatepatterns(includepats)
152 narrowspec.validatepatterns(includepats)
148 narrowspec.validatepatterns(excludepats)
153 narrowspec.validatepatterns(excludepats)
149
154
150 if not repository.NARROW_REQUIREMENT in op.repo.requirements:
155 if not repository.NARROW_REQUIREMENT in op.repo.requirements:
151 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
156 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
152 op.repo._writerequirements()
157 op.repo._writerequirements()
153 op.repo.setnarrowpats(includepats, excludepats)
158 op.repo.setnarrowpats(includepats, excludepats)
154 narrowspec.copytoworkingcopy(op.repo)
159 narrowspec.copytoworkingcopy(op.repo)
155
160
161 @bundle2.parthandler(_RESSPECS)
162 def _handlenarrowspecs(op, inpart):
163 data = inpart.read()
164 inc, exc = data.split('\0')
165 includepats = set(inc.splitlines())
166 excludepats = set(exc.splitlines())
167 narrowspec.validatepatterns(includepats)
168 narrowspec.validatepatterns(excludepats)
169
170 if repository.NARROW_REQUIREMENT not in op.repo.requirements:
171 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
172 op.repo._writerequirements()
173 op.repo.setnarrowpats(includepats, excludepats)
174 narrowspec.copytoworkingcopy(op.repo)
175
156 @bundle2.parthandler(_CHANGESPECPART)
176 @bundle2.parthandler(_CHANGESPECPART)
157 def _handlechangespec(op, inpart):
177 def _handlechangespec(op, inpart):
158 repo = op.repo
178 repo = op.repo
159 cl = repo.changelog
179 cl = repo.changelog
160
180
161 # changesets which need to be stripped entirely. either they're no longer
181 # changesets which need to be stripped entirely. either they're no longer
162 # needed in the new narrow spec, or the server is sending a replacement
182 # needed in the new narrow spec, or the server is sending a replacement
163 # in the changegroup part.
183 # in the changegroup part.
164 clkills = set()
184 clkills = set()
165
185
166 # A changespec part contains all the updates to ellipsis nodes
186 # A changespec part contains all the updates to ellipsis nodes
167 # that will happen as a result of widening or narrowing a
187 # that will happen as a result of widening or narrowing a
168 # repo. All the changes that this block encounters are ellipsis
188 # repo. All the changes that this block encounters are ellipsis
169 # nodes or flags to kill an existing ellipsis.
189 # nodes or flags to kill an existing ellipsis.
170 chunksignal = changegroup.readexactly(inpart, 4)
190 chunksignal = changegroup.readexactly(inpart, 4)
171 while chunksignal != _DONESIGNAL:
191 while chunksignal != _DONESIGNAL:
172 if chunksignal == _KILLNODESIGNAL:
192 if chunksignal == _KILLNODESIGNAL:
173 # a node used to be an ellipsis but isn't anymore
193 # a node used to be an ellipsis but isn't anymore
174 ck = changegroup.readexactly(inpart, 20)
194 ck = changegroup.readexactly(inpart, 20)
175 if cl.hasnode(ck):
195 if cl.hasnode(ck):
176 clkills.add(ck)
196 clkills.add(ck)
177 else:
197 else:
178 raise error.Abort(
198 raise error.Abort(
179 _('unexpected changespec node chunk type: %s') % chunksignal)
199 _('unexpected changespec node chunk type: %s') % chunksignal)
180 chunksignal = changegroup.readexactly(inpart, 4)
200 chunksignal = changegroup.readexactly(inpart, 4)
181
201
182 if clkills:
202 if clkills:
183 # preserve bookmarks that repair.strip() would otherwise strip
203 # preserve bookmarks that repair.strip() would otherwise strip
184 op._bookmarksbackup = repo._bookmarks
204 op._bookmarksbackup = repo._bookmarks
185 class dummybmstore(dict):
205 class dummybmstore(dict):
186 def applychanges(self, repo, tr, changes):
206 def applychanges(self, repo, tr, changes):
187 pass
207 pass
188 localrepo.localrepository._bookmarks.set(repo, dummybmstore())
208 localrepo.localrepository._bookmarks.set(repo, dummybmstore())
189 chgrpfile = repair.strip(op.ui, repo, list(clkills), backup=True,
209 chgrpfile = repair.strip(op.ui, repo, list(clkills), backup=True,
190 topic='widen')
210 topic='widen')
191 if chgrpfile:
211 if chgrpfile:
192 op._widen_uninterr = repo.ui.uninterruptible()
212 op._widen_uninterr = repo.ui.uninterruptible()
193 op._widen_uninterr.__enter__()
213 op._widen_uninterr.__enter__()
194 # presence of _widen_bundle attribute activates widen handler later
214 # presence of _widen_bundle attribute activates widen handler later
195 op._widen_bundle = chgrpfile
215 op._widen_bundle = chgrpfile
196 # Set the new narrowspec if we're widening. The setnewnarrowpats() method
216 # Set the new narrowspec if we're widening. The setnewnarrowpats() method
197 # will currently always be there when using the core+narrowhg server, but
217 # will currently always be there when using the core+narrowhg server, but
198 # other servers may include a changespec part even when not widening (e.g.
218 # other servers may include a changespec part even when not widening (e.g.
199 # because we're deepening a shallow repo).
219 # because we're deepening a shallow repo).
200 if util.safehasattr(repo, 'setnewnarrowpats'):
220 if util.safehasattr(repo, 'setnewnarrowpats'):
201 repo.setnewnarrowpats()
221 repo.setnewnarrowpats()
202
222
203 def handlechangegroup_widen(op, inpart):
223 def handlechangegroup_widen(op, inpart):
204 """Changegroup exchange handler which restores temporarily-stripped nodes"""
224 """Changegroup exchange handler which restores temporarily-stripped nodes"""
205 # We saved a bundle with stripped node data we must now restore.
225 # We saved a bundle with stripped node data we must now restore.
206 # This approach is based on mercurial/repair.py@6ee26a53c111.
226 # This approach is based on mercurial/repair.py@6ee26a53c111.
207 repo = op.repo
227 repo = op.repo
208 ui = op.ui
228 ui = op.ui
209
229
210 chgrpfile = op._widen_bundle
230 chgrpfile = op._widen_bundle
211 del op._widen_bundle
231 del op._widen_bundle
212 vfs = repo.vfs
232 vfs = repo.vfs
213
233
214 ui.note(_("adding branch\n"))
234 ui.note(_("adding branch\n"))
215 f = vfs.open(chgrpfile, "rb")
235 f = vfs.open(chgrpfile, "rb")
216 try:
236 try:
217 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
237 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
218 if not ui.verbose:
238 if not ui.verbose:
219 # silence internal shuffling chatter
239 # silence internal shuffling chatter
220 ui.pushbuffer()
240 ui.pushbuffer()
221 if isinstance(gen, bundle2.unbundle20):
241 if isinstance(gen, bundle2.unbundle20):
222 with repo.transaction('strip') as tr:
242 with repo.transaction('strip') as tr:
223 bundle2.processbundle(repo, gen, lambda: tr)
243 bundle2.processbundle(repo, gen, lambda: tr)
224 else:
244 else:
225 gen.apply(repo, 'strip', 'bundle:' + vfs.join(chgrpfile), True)
245 gen.apply(repo, 'strip', 'bundle:' + vfs.join(chgrpfile), True)
226 if not ui.verbose:
246 if not ui.verbose:
227 ui.popbuffer()
247 ui.popbuffer()
228 finally:
248 finally:
229 f.close()
249 f.close()
230
250
231 # remove undo files
251 # remove undo files
232 for undovfs, undofile in repo.undofiles():
252 for undovfs, undofile in repo.undofiles():
233 try:
253 try:
234 undovfs.unlink(undofile)
254 undovfs.unlink(undofile)
235 except OSError as e:
255 except OSError as e:
236 if e.errno != errno.ENOENT:
256 if e.errno != errno.ENOENT:
237 ui.warn(_('error removing %s: %s\n') %
257 ui.warn(_('error removing %s: %s\n') %
238 (undovfs.join(undofile), stringutil.forcebytestr(e)))
258 (undovfs.join(undofile), stringutil.forcebytestr(e)))
239
259
240 # Remove partial backup only if there were no exceptions
260 # Remove partial backup only if there were no exceptions
241 op._widen_uninterr.__exit__(None, None, None)
261 op._widen_uninterr.__exit__(None, None, None)
242 vfs.unlink(chgrpfile)
262 vfs.unlink(chgrpfile)
243
263
244 def setup():
264 def setup():
245 """Enable narrow repo support in bundle2-related extension points."""
265 """Enable narrow repo support in bundle2-related extension points."""
246 getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS
266 getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS
247
267
248 getbundleargs['narrow'] = 'boolean'
268 getbundleargs['narrow'] = 'boolean'
249 getbundleargs['depth'] = 'plain'
269 getbundleargs['depth'] = 'plain'
250 getbundleargs['oldincludepats'] = 'csv'
270 getbundleargs['oldincludepats'] = 'csv'
251 getbundleargs['oldexcludepats'] = 'csv'
271 getbundleargs['oldexcludepats'] = 'csv'
252 getbundleargs['known'] = 'csv'
272 getbundleargs['known'] = 'csv'
253
273
254 # Extend changegroup serving to handle requests from narrow clients.
274 # Extend changegroup serving to handle requests from narrow clients.
255 origcgfn = exchange.getbundle2partsmapping['changegroup']
275 origcgfn = exchange.getbundle2partsmapping['changegroup']
256 def wrappedcgfn(*args, **kwargs):
276 def wrappedcgfn(*args, **kwargs):
257 repo = args[1]
277 repo = args[1]
258 if repo.ui.has_section(_NARROWACL_SECTION):
278 if repo.ui.has_section(_NARROWACL_SECTION):
259 kwargs = exchange.applynarrowacl(repo, kwargs)
279 kwargs = exchange.applynarrowacl(repo, kwargs)
260
280
261 if (kwargs.get(r'narrow', False) and
281 if (kwargs.get(r'narrow', False) and
262 repo.ui.configbool('experimental', 'narrowservebrokenellipses')):
282 repo.ui.configbool('experimental', 'narrowservebrokenellipses')):
263 getbundlechangegrouppart_narrow(*args, **kwargs)
283 getbundlechangegrouppart_narrow(*args, **kwargs)
264 else:
284 else:
265 origcgfn(*args, **kwargs)
285 origcgfn(*args, **kwargs)
266 exchange.getbundle2partsmapping['changegroup'] = wrappedcgfn
286 exchange.getbundle2partsmapping['changegroup'] = wrappedcgfn
267
287
268 # Extend changegroup receiver so client can fixup after widen requests.
288 # Extend changegroup receiver so client can fixup after widen requests.
269 origcghandler = bundle2.parthandlermapping['changegroup']
289 origcghandler = bundle2.parthandlermapping['changegroup']
270 def wrappedcghandler(op, inpart):
290 def wrappedcghandler(op, inpart):
271 origcghandler(op, inpart)
291 origcghandler(op, inpart)
272 if util.safehasattr(op, '_widen_bundle'):
292 if util.safehasattr(op, '_widen_bundle'):
273 handlechangegroup_widen(op, inpart)
293 handlechangegroup_widen(op, inpart)
274 if util.safehasattr(op, '_bookmarksbackup'):
294 if util.safehasattr(op, '_bookmarksbackup'):
275 localrepo.localrepository._bookmarks.set(op.repo,
295 localrepo.localrepository._bookmarks.set(op.repo,
276 op._bookmarksbackup)
296 op._bookmarksbackup)
277 del op._bookmarksbackup
297 del op._bookmarksbackup
278
298
279 wrappedcghandler.params = origcghandler.params
299 wrappedcghandler.params = origcghandler.params
280 bundle2.parthandlermapping['changegroup'] = wrappedcghandler
300 bundle2.parthandlermapping['changegroup'] = wrappedcghandler
@@ -1,2566 +1,2566 b''
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import filecmp
11 import filecmp
12 import os
12 import os
13 import stat
13 import stat
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 addednodeid,
17 addednodeid,
18 hex,
18 hex,
19 modifiednodeid,
19 modifiednodeid,
20 nullid,
20 nullid,
21 nullrev,
21 nullrev,
22 short,
22 short,
23 wdirfilenodeids,
23 wdirfilenodeids,
24 wdirhex,
24 wdirhex,
25 )
25 )
26 from . import (
26 from . import (
27 dagop,
27 dagop,
28 encoding,
28 encoding,
29 error,
29 error,
30 fileset,
30 fileset,
31 match as matchmod,
31 match as matchmod,
32 obsolete as obsmod,
32 obsolete as obsmod,
33 patch,
33 patch,
34 pathutil,
34 pathutil,
35 phases,
35 phases,
36 pycompat,
36 pycompat,
37 repoview,
37 repoview,
38 scmutil,
38 scmutil,
39 sparse,
39 sparse,
40 subrepo,
40 subrepo,
41 subrepoutil,
41 subrepoutil,
42 util,
42 util,
43 )
43 )
44 from .utils import (
44 from .utils import (
45 dateutil,
45 dateutil,
46 stringutil,
46 stringutil,
47 )
47 )
48
48
49 propertycache = util.propertycache
49 propertycache = util.propertycache
50
50
51 class basectx(object):
51 class basectx(object):
52 """A basectx object represents the common logic for its children:
52 """A basectx object represents the common logic for its children:
53 changectx: read-only context that is already present in the repo,
53 changectx: read-only context that is already present in the repo,
54 workingctx: a context that represents the working directory and can
54 workingctx: a context that represents the working directory and can
55 be committed,
55 be committed,
56 memctx: a context that represents changes in-memory and can also
56 memctx: a context that represents changes in-memory and can also
57 be committed."""
57 be committed."""
58
58
59 def __init__(self, repo):
59 def __init__(self, repo):
60 self._repo = repo
60 self._repo = repo
61
61
62 def __bytes__(self):
62 def __bytes__(self):
63 return short(self.node())
63 return short(self.node())
64
64
65 __str__ = encoding.strmethod(__bytes__)
65 __str__ = encoding.strmethod(__bytes__)
66
66
67 def __repr__(self):
67 def __repr__(self):
68 return r"<%s %s>" % (type(self).__name__, str(self))
68 return r"<%s %s>" % (type(self).__name__, str(self))
69
69
70 def __eq__(self, other):
70 def __eq__(self, other):
71 try:
71 try:
72 return type(self) == type(other) and self._rev == other._rev
72 return type(self) == type(other) and self._rev == other._rev
73 except AttributeError:
73 except AttributeError:
74 return False
74 return False
75
75
76 def __ne__(self, other):
76 def __ne__(self, other):
77 return not (self == other)
77 return not (self == other)
78
78
79 def __contains__(self, key):
79 def __contains__(self, key):
80 return key in self._manifest
80 return key in self._manifest
81
81
82 def __getitem__(self, key):
82 def __getitem__(self, key):
83 return self.filectx(key)
83 return self.filectx(key)
84
84
85 def __iter__(self):
85 def __iter__(self):
86 return iter(self._manifest)
86 return iter(self._manifest)
87
87
88 def _buildstatusmanifest(self, status):
88 def _buildstatusmanifest(self, status):
89 """Builds a manifest that includes the given status results, if this is
89 """Builds a manifest that includes the given status results, if this is
90 a working copy context. For non-working copy contexts, it just returns
90 a working copy context. For non-working copy contexts, it just returns
91 the normal manifest."""
91 the normal manifest."""
92 return self.manifest()
92 return self.manifest()
93
93
94 def _matchstatus(self, other, match):
94 def _matchstatus(self, other, match):
95 """This internal method provides a way for child objects to override the
95 """This internal method provides a way for child objects to override the
96 match operator.
96 match operator.
97 """
97 """
98 return match
98 return match
99
99
100 def _buildstatus(self, other, s, match, listignored, listclean,
100 def _buildstatus(self, other, s, match, listignored, listclean,
101 listunknown):
101 listunknown):
102 """build a status with respect to another context"""
102 """build a status with respect to another context"""
103 # Load earliest manifest first for caching reasons. More specifically,
103 # Load earliest manifest first for caching reasons. More specifically,
104 # if you have revisions 1000 and 1001, 1001 is probably stored as a
104 # if you have revisions 1000 and 1001, 1001 is probably stored as a
105 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
105 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
106 # 1000 and cache it so that when you read 1001, we just need to apply a
106 # 1000 and cache it so that when you read 1001, we just need to apply a
107 # delta to what's in the cache. So that's one full reconstruction + one
107 # delta to what's in the cache. So that's one full reconstruction + one
108 # delta application.
108 # delta application.
109 mf2 = None
109 mf2 = None
110 if self.rev() is not None and self.rev() < other.rev():
110 if self.rev() is not None and self.rev() < other.rev():
111 mf2 = self._buildstatusmanifest(s)
111 mf2 = self._buildstatusmanifest(s)
112 mf1 = other._buildstatusmanifest(s)
112 mf1 = other._buildstatusmanifest(s)
113 if mf2 is None:
113 if mf2 is None:
114 mf2 = self._buildstatusmanifest(s)
114 mf2 = self._buildstatusmanifest(s)
115
115
116 modified, added = [], []
116 modified, added = [], []
117 removed = []
117 removed = []
118 clean = []
118 clean = []
119 deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
119 deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
120 deletedset = set(deleted)
120 deletedset = set(deleted)
121 d = mf1.diff(mf2, match=match, clean=listclean)
121 d = mf1.diff(mf2, match=match, clean=listclean)
122 for fn, value in d.iteritems():
122 for fn, value in d.iteritems():
123 if fn in deletedset:
123 if fn in deletedset:
124 continue
124 continue
125 if value is None:
125 if value is None:
126 clean.append(fn)
126 clean.append(fn)
127 continue
127 continue
128 (node1, flag1), (node2, flag2) = value
128 (node1, flag1), (node2, flag2) = value
129 if node1 is None:
129 if node1 is None:
130 added.append(fn)
130 added.append(fn)
131 elif node2 is None:
131 elif node2 is None:
132 removed.append(fn)
132 removed.append(fn)
133 elif flag1 != flag2:
133 elif flag1 != flag2:
134 modified.append(fn)
134 modified.append(fn)
135 elif node2 not in wdirfilenodeids:
135 elif node2 not in wdirfilenodeids:
136 # When comparing files between two commits, we save time by
136 # When comparing files between two commits, we save time by
137 # not comparing the file contents when the nodeids differ.
137 # not comparing the file contents when the nodeids differ.
138 # Note that this means we incorrectly report a reverted change
138 # Note that this means we incorrectly report a reverted change
139 # to a file as a modification.
139 # to a file as a modification.
140 modified.append(fn)
140 modified.append(fn)
141 elif self[fn].cmp(other[fn]):
141 elif self[fn].cmp(other[fn]):
142 modified.append(fn)
142 modified.append(fn)
143 else:
143 else:
144 clean.append(fn)
144 clean.append(fn)
145
145
146 if removed:
146 if removed:
147 # need to filter files if they are already reported as removed
147 # need to filter files if they are already reported as removed
148 unknown = [fn for fn in unknown if fn not in mf1 and
148 unknown = [fn for fn in unknown if fn not in mf1 and
149 (not match or match(fn))]
149 (not match or match(fn))]
150 ignored = [fn for fn in ignored if fn not in mf1 and
150 ignored = [fn for fn in ignored if fn not in mf1 and
151 (not match or match(fn))]
151 (not match or match(fn))]
152 # if they're deleted, don't report them as removed
152 # if they're deleted, don't report them as removed
153 removed = [fn for fn in removed if fn not in deletedset]
153 removed = [fn for fn in removed if fn not in deletedset]
154
154
155 return scmutil.status(modified, added, removed, deleted, unknown,
155 return scmutil.status(modified, added, removed, deleted, unknown,
156 ignored, clean)
156 ignored, clean)
157
157
158 @propertycache
158 @propertycache
159 def substate(self):
159 def substate(self):
160 return subrepoutil.state(self, self._repo.ui)
160 return subrepoutil.state(self, self._repo.ui)
161
161
162 def subrev(self, subpath):
162 def subrev(self, subpath):
163 return self.substate[subpath][1]
163 return self.substate[subpath][1]
164
164
165 def rev(self):
165 def rev(self):
166 return self._rev
166 return self._rev
167 def node(self):
167 def node(self):
168 return self._node
168 return self._node
169 def hex(self):
169 def hex(self):
170 return hex(self.node())
170 return hex(self.node())
171 def manifest(self):
171 def manifest(self):
172 return self._manifest
172 return self._manifest
173 def manifestctx(self):
173 def manifestctx(self):
174 return self._manifestctx
174 return self._manifestctx
175 def repo(self):
175 def repo(self):
176 return self._repo
176 return self._repo
177 def phasestr(self):
177 def phasestr(self):
178 return phases.phasenames[self.phase()]
178 return phases.phasenames[self.phase()]
179 def mutable(self):
179 def mutable(self):
180 return self.phase() > phases.public
180 return self.phase() > phases.public
181
181
182 def matchfileset(self, expr, badfn=None):
182 def matchfileset(self, expr, badfn=None):
183 return fileset.match(self, expr, badfn=badfn)
183 return fileset.match(self, expr, badfn=badfn)
184
184
185 def obsolete(self):
185 def obsolete(self):
186 """True if the changeset is obsolete"""
186 """True if the changeset is obsolete"""
187 return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
187 return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
188
188
189 def extinct(self):
189 def extinct(self):
190 """True if the changeset is extinct"""
190 """True if the changeset is extinct"""
191 return self.rev() in obsmod.getrevs(self._repo, 'extinct')
191 return self.rev() in obsmod.getrevs(self._repo, 'extinct')
192
192
193 def orphan(self):
193 def orphan(self):
194 """True if the changeset is not obsolete, but its ancestor is"""
194 """True if the changeset is not obsolete, but its ancestor is"""
195 return self.rev() in obsmod.getrevs(self._repo, 'orphan')
195 return self.rev() in obsmod.getrevs(self._repo, 'orphan')
196
196
197 def phasedivergent(self):
197 def phasedivergent(self):
198 """True if the changeset tries to be a successor of a public changeset
198 """True if the changeset tries to be a successor of a public changeset
199
199
200 Only non-public and non-obsolete changesets may be phase-divergent.
200 Only non-public and non-obsolete changesets may be phase-divergent.
201 """
201 """
202 return self.rev() in obsmod.getrevs(self._repo, 'phasedivergent')
202 return self.rev() in obsmod.getrevs(self._repo, 'phasedivergent')
203
203
204 def contentdivergent(self):
204 def contentdivergent(self):
205 """Is a successor of a changeset with multiple possible successor sets
205 """Is a successor of a changeset with multiple possible successor sets
206
206
207 Only non-public and non-obsolete changesets may be content-divergent.
207 Only non-public and non-obsolete changesets may be content-divergent.
208 """
208 """
209 return self.rev() in obsmod.getrevs(self._repo, 'contentdivergent')
209 return self.rev() in obsmod.getrevs(self._repo, 'contentdivergent')
210
210
211 def isunstable(self):
211 def isunstable(self):
212 """True if the changeset is either orphan, phase-divergent or
212 """True if the changeset is either orphan, phase-divergent or
213 content-divergent"""
213 content-divergent"""
214 return self.orphan() or self.phasedivergent() or self.contentdivergent()
214 return self.orphan() or self.phasedivergent() or self.contentdivergent()
215
215
216 def instabilities(self):
216 def instabilities(self):
217 """return the list of instabilities affecting this changeset.
217 """return the list of instabilities affecting this changeset.
218
218
219 Instabilities are returned as strings. possible values are:
219 Instabilities are returned as strings. possible values are:
220 - orphan,
220 - orphan,
221 - phase-divergent,
221 - phase-divergent,
222 - content-divergent.
222 - content-divergent.
223 """
223 """
224 instabilities = []
224 instabilities = []
225 if self.orphan():
225 if self.orphan():
226 instabilities.append('orphan')
226 instabilities.append('orphan')
227 if self.phasedivergent():
227 if self.phasedivergent():
228 instabilities.append('phase-divergent')
228 instabilities.append('phase-divergent')
229 if self.contentdivergent():
229 if self.contentdivergent():
230 instabilities.append('content-divergent')
230 instabilities.append('content-divergent')
231 return instabilities
231 return instabilities
232
232
233 def parents(self):
233 def parents(self):
234 """return contexts for each parent changeset"""
234 """return contexts for each parent changeset"""
235 return self._parents
235 return self._parents
236
236
237 def p1(self):
237 def p1(self):
238 return self._parents[0]
238 return self._parents[0]
239
239
240 def p2(self):
240 def p2(self):
241 parents = self._parents
241 parents = self._parents
242 if len(parents) == 2:
242 if len(parents) == 2:
243 return parents[1]
243 return parents[1]
244 return self._repo[nullrev]
244 return self._repo[nullrev]
245
245
246 def _fileinfo(self, path):
246 def _fileinfo(self, path):
247 if r'_manifest' in self.__dict__:
247 if r'_manifest' in self.__dict__:
248 try:
248 try:
249 return self._manifest[path], self._manifest.flags(path)
249 return self._manifest[path], self._manifest.flags(path)
250 except KeyError:
250 except KeyError:
251 raise error.ManifestLookupError(self._node, path,
251 raise error.ManifestLookupError(self._node, path,
252 _('not found in manifest'))
252 _('not found in manifest'))
253 if r'_manifestdelta' in self.__dict__ or path in self.files():
253 if r'_manifestdelta' in self.__dict__ or path in self.files():
254 if path in self._manifestdelta:
254 if path in self._manifestdelta:
255 return (self._manifestdelta[path],
255 return (self._manifestdelta[path],
256 self._manifestdelta.flags(path))
256 self._manifestdelta.flags(path))
257 mfl = self._repo.manifestlog
257 mfl = self._repo.manifestlog
258 try:
258 try:
259 node, flag = mfl[self._changeset.manifest].find(path)
259 node, flag = mfl[self._changeset.manifest].find(path)
260 except KeyError:
260 except KeyError:
261 raise error.ManifestLookupError(self._node, path,
261 raise error.ManifestLookupError(self._node, path,
262 _('not found in manifest'))
262 _('not found in manifest'))
263
263
264 return node, flag
264 return node, flag
265
265
266 def filenode(self, path):
266 def filenode(self, path):
267 return self._fileinfo(path)[0]
267 return self._fileinfo(path)[0]
268
268
269 def flags(self, path):
269 def flags(self, path):
270 try:
270 try:
271 return self._fileinfo(path)[1]
271 return self._fileinfo(path)[1]
272 except error.LookupError:
272 except error.LookupError:
273 return ''
273 return ''
274
274
275 def sub(self, path, allowcreate=True):
275 def sub(self, path, allowcreate=True):
276 '''return a subrepo for the stored revision of path, never wdir()'''
276 '''return a subrepo for the stored revision of path, never wdir()'''
277 return subrepo.subrepo(self, path, allowcreate=allowcreate)
277 return subrepo.subrepo(self, path, allowcreate=allowcreate)
278
278
279 def nullsub(self, path, pctx):
279 def nullsub(self, path, pctx):
280 return subrepo.nullsubrepo(self, path, pctx)
280 return subrepo.nullsubrepo(self, path, pctx)
281
281
282 def workingsub(self, path):
282 def workingsub(self, path):
283 '''return a subrepo for the stored revision, or wdir if this is a wdir
283 '''return a subrepo for the stored revision, or wdir if this is a wdir
284 context.
284 context.
285 '''
285 '''
286 return subrepo.subrepo(self, path, allowwdir=True)
286 return subrepo.subrepo(self, path, allowwdir=True)
287
287
288 def match(self, pats=None, include=None, exclude=None, default='glob',
288 def match(self, pats=None, include=None, exclude=None, default='glob',
289 listsubrepos=False, badfn=None):
289 listsubrepos=False, badfn=None):
290 r = self._repo
290 r = self._repo
291 return matchmod.match(r.root, r.getcwd(), pats,
291 return matchmod.match(r.root, r.getcwd(), pats,
292 include, exclude, default,
292 include, exclude, default,
293 auditor=r.nofsauditor, ctx=self,
293 auditor=r.nofsauditor, ctx=self,
294 listsubrepos=listsubrepos, badfn=badfn)
294 listsubrepos=listsubrepos, badfn=badfn)
295
295
296 def diff(self, ctx2=None, match=None, changes=None, opts=None,
296 def diff(self, ctx2=None, match=None, changes=None, opts=None,
297 losedatafn=None, pathfn=None, copy=None,
297 losedatafn=None, pathfn=None, copy=None,
298 copysourcematch=None, hunksfilterfn=None):
298 copysourcematch=None, hunksfilterfn=None):
299 """Returns a diff generator for the given contexts and matcher"""
299 """Returns a diff generator for the given contexts and matcher"""
300 if ctx2 is None:
300 if ctx2 is None:
301 ctx2 = self.p1()
301 ctx2 = self.p1()
302 if ctx2 is not None:
302 if ctx2 is not None:
303 ctx2 = self._repo[ctx2]
303 ctx2 = self._repo[ctx2]
304 return patch.diff(self._repo, ctx2, self, match=match, changes=changes,
304 return patch.diff(self._repo, ctx2, self, match=match, changes=changes,
305 opts=opts, losedatafn=losedatafn, pathfn=pathfn,
305 opts=opts, losedatafn=losedatafn, pathfn=pathfn,
306 copy=copy, copysourcematch=copysourcematch,
306 copy=copy, copysourcematch=copysourcematch,
307 hunksfilterfn=hunksfilterfn)
307 hunksfilterfn=hunksfilterfn)
308
308
309 def dirs(self):
309 def dirs(self):
310 return self._manifest.dirs()
310 return self._manifest.dirs()
311
311
312 def hasdir(self, dir):
312 def hasdir(self, dir):
313 return self._manifest.hasdir(dir)
313 return self._manifest.hasdir(dir)
314
314
315 def status(self, other=None, match=None, listignored=False,
315 def status(self, other=None, match=None, listignored=False,
316 listclean=False, listunknown=False, listsubrepos=False):
316 listclean=False, listunknown=False, listsubrepos=False):
317 """return status of files between two nodes or node and working
317 """return status of files between two nodes or node and working
318 directory.
318 directory.
319
319
320 If other is None, compare this node with working directory.
320 If other is None, compare this node with working directory.
321
321
322 returns (modified, added, removed, deleted, unknown, ignored, clean)
322 returns (modified, added, removed, deleted, unknown, ignored, clean)
323 """
323 """
324
324
325 ctx1 = self
325 ctx1 = self
326 ctx2 = self._repo[other]
326 ctx2 = self._repo[other]
327
327
328 # This next code block is, admittedly, fragile logic that tests for
328 # This next code block is, admittedly, fragile logic that tests for
329 # reversing the contexts and wouldn't need to exist if it weren't for
329 # reversing the contexts and wouldn't need to exist if it weren't for
330 # the fast (and common) code path of comparing the working directory
330 # the fast (and common) code path of comparing the working directory
331 # with its first parent.
331 # with its first parent.
332 #
332 #
333 # What we're aiming for here is the ability to call:
333 # What we're aiming for here is the ability to call:
334 #
334 #
335 # workingctx.status(parentctx)
335 # workingctx.status(parentctx)
336 #
336 #
337 # If we always built the manifest for each context and compared those,
337 # If we always built the manifest for each context and compared those,
338 # then we'd be done. But the special case of the above call means we
338 # then we'd be done. But the special case of the above call means we
339 # just copy the manifest of the parent.
339 # just copy the manifest of the parent.
340 reversed = False
340 reversed = False
341 if (not isinstance(ctx1, changectx)
341 if (not isinstance(ctx1, changectx)
342 and isinstance(ctx2, changectx)):
342 and isinstance(ctx2, changectx)):
343 reversed = True
343 reversed = True
344 ctx1, ctx2 = ctx2, ctx1
344 ctx1, ctx2 = ctx2, ctx1
345
345
346 match = self._repo.narrowmatch(match)
346 match = self._repo.narrowmatch(match)
347 match = ctx2._matchstatus(ctx1, match)
347 match = ctx2._matchstatus(ctx1, match)
348 r = scmutil.status([], [], [], [], [], [], [])
348 r = scmutil.status([], [], [], [], [], [], [])
349 r = ctx2._buildstatus(ctx1, r, match, listignored, listclean,
349 r = ctx2._buildstatus(ctx1, r, match, listignored, listclean,
350 listunknown)
350 listunknown)
351
351
352 if reversed:
352 if reversed:
353 # Reverse added and removed. Clear deleted, unknown and ignored as
353 # Reverse added and removed. Clear deleted, unknown and ignored as
354 # these make no sense to reverse.
354 # these make no sense to reverse.
355 r = scmutil.status(r.modified, r.removed, r.added, [], [], [],
355 r = scmutil.status(r.modified, r.removed, r.added, [], [], [],
356 r.clean)
356 r.clean)
357
357
358 if listsubrepos:
358 if listsubrepos:
359 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
359 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
360 try:
360 try:
361 rev2 = ctx2.subrev(subpath)
361 rev2 = ctx2.subrev(subpath)
362 except KeyError:
362 except KeyError:
363 # A subrepo that existed in node1 was deleted between
363 # A subrepo that existed in node1 was deleted between
364 # node1 and node2 (inclusive). Thus, ctx2's substate
364 # node1 and node2 (inclusive). Thus, ctx2's substate
365 # won't contain that subpath. The best we can do ignore it.
365 # won't contain that subpath. The best we can do ignore it.
366 rev2 = None
366 rev2 = None
367 submatch = matchmod.subdirmatcher(subpath, match)
367 submatch = matchmod.subdirmatcher(subpath, match)
368 s = sub.status(rev2, match=submatch, ignored=listignored,
368 s = sub.status(rev2, match=submatch, ignored=listignored,
369 clean=listclean, unknown=listunknown,
369 clean=listclean, unknown=listunknown,
370 listsubrepos=True)
370 listsubrepos=True)
371 for rfiles, sfiles in zip(r, s):
371 for rfiles, sfiles in zip(r, s):
372 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
372 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
373
373
374 for l in r:
374 for l in r:
375 l.sort()
375 l.sort()
376
376
377 return r
377 return r
378
378
379 class changectx(basectx):
379 class changectx(basectx):
380 """A changecontext object makes access to data related to a particular
380 """A changecontext object makes access to data related to a particular
381 changeset convenient. It represents a read-only context already present in
381 changeset convenient. It represents a read-only context already present in
382 the repo."""
382 the repo."""
383 def __init__(self, repo, rev, node):
383 def __init__(self, repo, rev, node):
384 super(changectx, self).__init__(repo)
384 super(changectx, self).__init__(repo)
385 self._rev = rev
385 self._rev = rev
386 self._node = node
386 self._node = node
387
387
388 def __hash__(self):
388 def __hash__(self):
389 try:
389 try:
390 return hash(self._rev)
390 return hash(self._rev)
391 except AttributeError:
391 except AttributeError:
392 return id(self)
392 return id(self)
393
393
394 def __nonzero__(self):
394 def __nonzero__(self):
395 return self._rev != nullrev
395 return self._rev != nullrev
396
396
397 __bool__ = __nonzero__
397 __bool__ = __nonzero__
398
398
399 @propertycache
399 @propertycache
400 def _changeset(self):
400 def _changeset(self):
401 return self._repo.changelog.changelogrevision(self.rev())
401 return self._repo.changelog.changelogrevision(self.rev())
402
402
403 @propertycache
403 @propertycache
404 def _manifest(self):
404 def _manifest(self):
405 return self._manifestctx.read()
405 return self._manifestctx.read()
406
406
407 @property
407 @property
408 def _manifestctx(self):
408 def _manifestctx(self):
409 return self._repo.manifestlog[self._changeset.manifest]
409 return self._repo.manifestlog[self._changeset.manifest]
410
410
411 @propertycache
411 @propertycache
412 def _manifestdelta(self):
412 def _manifestdelta(self):
413 return self._manifestctx.readdelta()
413 return self._manifestctx.readdelta()
414
414
415 @propertycache
415 @propertycache
416 def _parents(self):
416 def _parents(self):
417 repo = self._repo
417 repo = self._repo
418 p1, p2 = repo.changelog.parentrevs(self._rev)
418 p1, p2 = repo.changelog.parentrevs(self._rev)
419 if p2 == nullrev:
419 if p2 == nullrev:
420 return [repo[p1]]
420 return [repo[p1]]
421 return [repo[p1], repo[p2]]
421 return [repo[p1], repo[p2]]
422
422
423 def changeset(self):
423 def changeset(self):
424 c = self._changeset
424 c = self._changeset
425 return (
425 return (
426 c.manifest,
426 c.manifest,
427 c.user,
427 c.user,
428 c.date,
428 c.date,
429 c.files,
429 c.files,
430 c.description,
430 c.description,
431 c.extra,
431 c.extra,
432 )
432 )
433 def manifestnode(self):
433 def manifestnode(self):
434 return self._changeset.manifest
434 return self._changeset.manifest
435
435
436 def user(self):
436 def user(self):
437 return self._changeset.user
437 return self._changeset.user
438 def date(self):
438 def date(self):
439 return self._changeset.date
439 return self._changeset.date
440 def files(self):
440 def files(self):
441 return self._changeset.files
441 return self._changeset.files
442 @propertycache
442 @propertycache
443 def _copies(self):
443 def _copies(self):
444 source = self._repo.ui.config('experimental', 'copies.read-from')
444 source = self._repo.ui.config('experimental', 'copies.read-from')
445 p1copies = self._changeset.p1copies
445 p1copies = self._changeset.p1copies
446 p2copies = self._changeset.p2copies
446 p2copies = self._changeset.p2copies
447 # If config says to get copy metadata only from changeset, then return
447 # If config says to get copy metadata only from changeset, then return
448 # that, defaulting to {} if there was no copy metadata.
448 # that, defaulting to {} if there was no copy metadata.
449 # In compatibility mode, we return copy data from the changeset if
449 # In compatibility mode, we return copy data from the changeset if
450 # it was recorded there, and otherwise we fall back to getting it from
450 # it was recorded there, and otherwise we fall back to getting it from
451 # the filelogs (below).
451 # the filelogs (below).
452 if (source == 'changeset-only' or
452 if (source == 'changeset-only' or
453 (source == 'compatibility' and p1copies is not None)):
453 (source == 'compatibility' and p1copies is not None)):
454 return p1copies or {}, p2copies or {}
454 return p1copies or {}, p2copies or {}
455
455
456 # Otherwise (config said to read only from filelog, or we are in
456 # Otherwise (config said to read only from filelog, or we are in
457 # compatiblity mode and there is not data in the changeset), we get
457 # compatiblity mode and there is not data in the changeset), we get
458 # the copy metadata from the filelogs.
458 # the copy metadata from the filelogs.
459 p1copies = {}
459 p1copies = {}
460 p2copies = {}
460 p2copies = {}
461 p1 = self.p1()
461 p1 = self.p1()
462 p2 = self.p2()
462 p2 = self.p2()
463 narrowmatch = self._repo.narrowmatch()
463 narrowmatch = self._repo.narrowmatch()
464 for dst in self.files():
464 for dst in self.files():
465 if not narrowmatch(dst) or dst not in self:
465 if not narrowmatch(dst) or dst not in self:
466 continue
466 continue
467 copied = self[dst].renamed()
467 copied = self[dst].renamed()
468 if not copied:
468 if not copied:
469 continue
469 continue
470 src, srcnode = copied
470 src, srcnode = copied
471 if src in p1 and p1[src].filenode() == srcnode:
471 if src in p1 and p1[src].filenode() == srcnode:
472 p1copies[dst] = src
472 p1copies[dst] = src
473 elif src in p2 and p2[src].filenode() == srcnode:
473 elif src in p2 and p2[src].filenode() == srcnode:
474 p2copies[dst] = src
474 p2copies[dst] = src
475 return p1copies, p2copies
475 return p1copies, p2copies
476 def p1copies(self):
476 def p1copies(self):
477 return self._copies[0]
477 return self._copies[0]
478 def p2copies(self):
478 def p2copies(self):
479 return self._copies[1]
479 return self._copies[1]
480 def description(self):
480 def description(self):
481 return self._changeset.description
481 return self._changeset.description
482 def branch(self):
482 def branch(self):
483 return encoding.tolocal(self._changeset.extra.get("branch"))
483 return encoding.tolocal(self._changeset.extra.get("branch"))
484 def closesbranch(self):
484 def closesbranch(self):
485 return 'close' in self._changeset.extra
485 return 'close' in self._changeset.extra
486 def extra(self):
486 def extra(self):
487 """Return a dict of extra information."""
487 """Return a dict of extra information."""
488 return self._changeset.extra
488 return self._changeset.extra
489 def tags(self):
489 def tags(self):
490 """Return a list of byte tag names"""
490 """Return a list of byte tag names"""
491 return self._repo.nodetags(self._node)
491 return self._repo.nodetags(self._node)
492 def bookmarks(self):
492 def bookmarks(self):
493 """Return a list of byte bookmark names."""
493 """Return a list of byte bookmark names."""
494 return self._repo.nodebookmarks(self._node)
494 return self._repo.nodebookmarks(self._node)
495 def phase(self):
495 def phase(self):
496 return self._repo._phasecache.phase(self._repo, self._rev)
496 return self._repo._phasecache.phase(self._repo, self._rev)
497 def hidden(self):
497 def hidden(self):
498 return self._rev in repoview.filterrevs(self._repo, 'visible')
498 return self._rev in repoview.filterrevs(self._repo, 'visible')
499
499
500 def isinmemory(self):
500 def isinmemory(self):
501 return False
501 return False
502
502
503 def children(self):
503 def children(self):
504 """return list of changectx contexts for each child changeset.
504 """return list of changectx contexts for each child changeset.
505
505
506 This returns only the immediate child changesets. Use descendants() to
506 This returns only the immediate child changesets. Use descendants() to
507 recursively walk children.
507 recursively walk children.
508 """
508 """
509 c = self._repo.changelog.children(self._node)
509 c = self._repo.changelog.children(self._node)
510 return [self._repo[x] for x in c]
510 return [self._repo[x] for x in c]
511
511
512 def ancestors(self):
512 def ancestors(self):
513 for a in self._repo.changelog.ancestors([self._rev]):
513 for a in self._repo.changelog.ancestors([self._rev]):
514 yield self._repo[a]
514 yield self._repo[a]
515
515
516 def descendants(self):
516 def descendants(self):
517 """Recursively yield all children of the changeset.
517 """Recursively yield all children of the changeset.
518
518
519 For just the immediate children, use children()
519 For just the immediate children, use children()
520 """
520 """
521 for d in self._repo.changelog.descendants([self._rev]):
521 for d in self._repo.changelog.descendants([self._rev]):
522 yield self._repo[d]
522 yield self._repo[d]
523
523
524 def filectx(self, path, fileid=None, filelog=None):
524 def filectx(self, path, fileid=None, filelog=None):
525 """get a file context from this changeset"""
525 """get a file context from this changeset"""
526 if fileid is None:
526 if fileid is None:
527 fileid = self.filenode(path)
527 fileid = self.filenode(path)
528 return filectx(self._repo, path, fileid=fileid,
528 return filectx(self._repo, path, fileid=fileid,
529 changectx=self, filelog=filelog)
529 changectx=self, filelog=filelog)
530
530
531 def ancestor(self, c2, warn=False):
531 def ancestor(self, c2, warn=False):
532 """return the "best" ancestor context of self and c2
532 """return the "best" ancestor context of self and c2
533
533
534 If there are multiple candidates, it will show a message and check
534 If there are multiple candidates, it will show a message and check
535 merge.preferancestor configuration before falling back to the
535 merge.preferancestor configuration before falling back to the
536 revlog ancestor."""
536 revlog ancestor."""
537 # deal with workingctxs
537 # deal with workingctxs
538 n2 = c2._node
538 n2 = c2._node
539 if n2 is None:
539 if n2 is None:
540 n2 = c2._parents[0]._node
540 n2 = c2._parents[0]._node
541 cahs = self._repo.changelog.commonancestorsheads(self._node, n2)
541 cahs = self._repo.changelog.commonancestorsheads(self._node, n2)
542 if not cahs:
542 if not cahs:
543 anc = nullid
543 anc = nullid
544 elif len(cahs) == 1:
544 elif len(cahs) == 1:
545 anc = cahs[0]
545 anc = cahs[0]
546 else:
546 else:
547 # experimental config: merge.preferancestor
547 # experimental config: merge.preferancestor
548 for r in self._repo.ui.configlist('merge', 'preferancestor'):
548 for r in self._repo.ui.configlist('merge', 'preferancestor'):
549 try:
549 try:
550 ctx = scmutil.revsymbol(self._repo, r)
550 ctx = scmutil.revsymbol(self._repo, r)
551 except error.RepoLookupError:
551 except error.RepoLookupError:
552 continue
552 continue
553 anc = ctx.node()
553 anc = ctx.node()
554 if anc in cahs:
554 if anc in cahs:
555 break
555 break
556 else:
556 else:
557 anc = self._repo.changelog.ancestor(self._node, n2)
557 anc = self._repo.changelog.ancestor(self._node, n2)
558 if warn:
558 if warn:
559 self._repo.ui.status(
559 self._repo.ui.status(
560 (_("note: using %s as ancestor of %s and %s\n") %
560 (_("note: using %s as ancestor of %s and %s\n") %
561 (short(anc), short(self._node), short(n2))) +
561 (short(anc), short(self._node), short(n2))) +
562 ''.join(_(" alternatively, use --config "
562 ''.join(_(" alternatively, use --config "
563 "merge.preferancestor=%s\n") %
563 "merge.preferancestor=%s\n") %
564 short(n) for n in sorted(cahs) if n != anc))
564 short(n) for n in sorted(cahs) if n != anc))
565 return self._repo[anc]
565 return self._repo[anc]
566
566
567 def isancestorof(self, other):
567 def isancestorof(self, other):
568 """True if this changeset is an ancestor of other"""
568 """True if this changeset is an ancestor of other"""
569 return self._repo.changelog.isancestorrev(self._rev, other._rev)
569 return self._repo.changelog.isancestorrev(self._rev, other._rev)
570
570
571 def walk(self, match):
571 def walk(self, match):
572 '''Generates matching file names.'''
572 '''Generates matching file names.'''
573
573
574 # Wrap match.bad method to have message with nodeid
574 # Wrap match.bad method to have message with nodeid
575 def bad(fn, msg):
575 def bad(fn, msg):
576 # The manifest doesn't know about subrepos, so don't complain about
576 # The manifest doesn't know about subrepos, so don't complain about
577 # paths into valid subrepos.
577 # paths into valid subrepos.
578 if any(fn == s or fn.startswith(s + '/')
578 if any(fn == s or fn.startswith(s + '/')
579 for s in self.substate):
579 for s in self.substate):
580 return
580 return
581 match.bad(fn, _('no such file in rev %s') % self)
581 match.bad(fn, _('no such file in rev %s') % self)
582
582
583 m = matchmod.badmatch(self._repo.narrowmatch(match), bad)
583 m = matchmod.badmatch(self._repo.narrowmatch(match), bad)
584 return self._manifest.walk(m)
584 return self._manifest.walk(m)
585
585
586 def matches(self, match):
586 def matches(self, match):
587 return self.walk(match)
587 return self.walk(match)
588
588
589 class basefilectx(object):
589 class basefilectx(object):
590 """A filecontext object represents the common logic for its children:
590 """A filecontext object represents the common logic for its children:
591 filectx: read-only access to a filerevision that is already present
591 filectx: read-only access to a filerevision that is already present
592 in the repo,
592 in the repo,
593 workingfilectx: a filecontext that represents files from the working
593 workingfilectx: a filecontext that represents files from the working
594 directory,
594 directory,
595 memfilectx: a filecontext that represents files in-memory,
595 memfilectx: a filecontext that represents files in-memory,
596 """
596 """
597 @propertycache
597 @propertycache
598 def _filelog(self):
598 def _filelog(self):
599 return self._repo.file(self._path)
599 return self._repo.file(self._path)
600
600
601 @propertycache
601 @propertycache
602 def _changeid(self):
602 def _changeid(self):
603 if r'_changectx' in self.__dict__:
603 if r'_changectx' in self.__dict__:
604 return self._changectx.rev()
604 return self._changectx.rev()
605 elif r'_descendantrev' in self.__dict__:
605 elif r'_descendantrev' in self.__dict__:
606 # this file context was created from a revision with a known
606 # this file context was created from a revision with a known
607 # descendant, we can (lazily) correct for linkrev aliases
607 # descendant, we can (lazily) correct for linkrev aliases
608 return self._adjustlinkrev(self._descendantrev)
608 return self._adjustlinkrev(self._descendantrev)
609 else:
609 else:
610 return self._filelog.linkrev(self._filerev)
610 return self._filelog.linkrev(self._filerev)
611
611
612 @propertycache
612 @propertycache
613 def _filenode(self):
613 def _filenode(self):
614 if r'_fileid' in self.__dict__:
614 if r'_fileid' in self.__dict__:
615 return self._filelog.lookup(self._fileid)
615 return self._filelog.lookup(self._fileid)
616 else:
616 else:
617 return self._changectx.filenode(self._path)
617 return self._changectx.filenode(self._path)
618
618
619 @propertycache
619 @propertycache
620 def _filerev(self):
620 def _filerev(self):
621 return self._filelog.rev(self._filenode)
621 return self._filelog.rev(self._filenode)
622
622
623 @propertycache
623 @propertycache
624 def _repopath(self):
624 def _repopath(self):
625 return self._path
625 return self._path
626
626
627 def __nonzero__(self):
627 def __nonzero__(self):
628 try:
628 try:
629 self._filenode
629 self._filenode
630 return True
630 return True
631 except error.LookupError:
631 except error.LookupError:
632 # file is missing
632 # file is missing
633 return False
633 return False
634
634
635 __bool__ = __nonzero__
635 __bool__ = __nonzero__
636
636
637 def __bytes__(self):
637 def __bytes__(self):
638 try:
638 try:
639 return "%s@%s" % (self.path(), self._changectx)
639 return "%s@%s" % (self.path(), self._changectx)
640 except error.LookupError:
640 except error.LookupError:
641 return "%s@???" % self.path()
641 return "%s@???" % self.path()
642
642
643 __str__ = encoding.strmethod(__bytes__)
643 __str__ = encoding.strmethod(__bytes__)
644
644
645 def __repr__(self):
645 def __repr__(self):
646 return r"<%s %s>" % (type(self).__name__, str(self))
646 return r"<%s %s>" % (type(self).__name__, str(self))
647
647
648 def __hash__(self):
648 def __hash__(self):
649 try:
649 try:
650 return hash((self._path, self._filenode))
650 return hash((self._path, self._filenode))
651 except AttributeError:
651 except AttributeError:
652 return id(self)
652 return id(self)
653
653
654 def __eq__(self, other):
654 def __eq__(self, other):
655 try:
655 try:
656 return (type(self) == type(other) and self._path == other._path
656 return (type(self) == type(other) and self._path == other._path
657 and self._filenode == other._filenode)
657 and self._filenode == other._filenode)
658 except AttributeError:
658 except AttributeError:
659 return False
659 return False
660
660
661 def __ne__(self, other):
661 def __ne__(self, other):
662 return not (self == other)
662 return not (self == other)
663
663
664 def filerev(self):
664 def filerev(self):
665 return self._filerev
665 return self._filerev
666 def filenode(self):
666 def filenode(self):
667 return self._filenode
667 return self._filenode
668 @propertycache
668 @propertycache
669 def _flags(self):
669 def _flags(self):
670 return self._changectx.flags(self._path)
670 return self._changectx.flags(self._path)
671 def flags(self):
671 def flags(self):
672 return self._flags
672 return self._flags
673 def filelog(self):
673 def filelog(self):
674 return self._filelog
674 return self._filelog
675 def rev(self):
675 def rev(self):
676 return self._changeid
676 return self._changeid
677 def linkrev(self):
677 def linkrev(self):
678 return self._filelog.linkrev(self._filerev)
678 return self._filelog.linkrev(self._filerev)
679 def node(self):
679 def node(self):
680 return self._changectx.node()
680 return self._changectx.node()
681 def hex(self):
681 def hex(self):
682 return self._changectx.hex()
682 return self._changectx.hex()
683 def user(self):
683 def user(self):
684 return self._changectx.user()
684 return self._changectx.user()
685 def date(self):
685 def date(self):
686 return self._changectx.date()
686 return self._changectx.date()
687 def files(self):
687 def files(self):
688 return self._changectx.files()
688 return self._changectx.files()
689 def description(self):
689 def description(self):
690 return self._changectx.description()
690 return self._changectx.description()
691 def branch(self):
691 def branch(self):
692 return self._changectx.branch()
692 return self._changectx.branch()
693 def extra(self):
693 def extra(self):
694 return self._changectx.extra()
694 return self._changectx.extra()
695 def phase(self):
695 def phase(self):
696 return self._changectx.phase()
696 return self._changectx.phase()
697 def phasestr(self):
697 def phasestr(self):
698 return self._changectx.phasestr()
698 return self._changectx.phasestr()
699 def obsolete(self):
699 def obsolete(self):
700 return self._changectx.obsolete()
700 return self._changectx.obsolete()
701 def instabilities(self):
701 def instabilities(self):
702 return self._changectx.instabilities()
702 return self._changectx.instabilities()
703 def manifest(self):
703 def manifest(self):
704 return self._changectx.manifest()
704 return self._changectx.manifest()
705 def changectx(self):
705 def changectx(self):
706 return self._changectx
706 return self._changectx
707 def renamed(self):
707 def renamed(self):
708 return self._copied
708 return self._copied
709 def copysource(self):
709 def copysource(self):
710 return self._copied and self._copied[0]
710 return self._copied and self._copied[0]
711 def repo(self):
711 def repo(self):
712 return self._repo
712 return self._repo
713 def size(self):
713 def size(self):
714 return len(self.data())
714 return len(self.data())
715
715
716 def path(self):
716 def path(self):
717 return self._path
717 return self._path
718
718
719 def isbinary(self):
719 def isbinary(self):
720 try:
720 try:
721 return stringutil.binary(self.data())
721 return stringutil.binary(self.data())
722 except IOError:
722 except IOError:
723 return False
723 return False
724 def isexec(self):
724 def isexec(self):
725 return 'x' in self.flags()
725 return 'x' in self.flags()
726 def islink(self):
726 def islink(self):
727 return 'l' in self.flags()
727 return 'l' in self.flags()
728
728
729 def isabsent(self):
729 def isabsent(self):
730 """whether this filectx represents a file not in self._changectx
730 """whether this filectx represents a file not in self._changectx
731
731
732 This is mainly for merge code to detect change/delete conflicts. This is
732 This is mainly for merge code to detect change/delete conflicts. This is
733 expected to be True for all subclasses of basectx."""
733 expected to be True for all subclasses of basectx."""
734 return False
734 return False
735
735
736 _customcmp = False
736 _customcmp = False
737 def cmp(self, fctx):
737 def cmp(self, fctx):
738 """compare with other file context
738 """compare with other file context
739
739
740 returns True if different than fctx.
740 returns True if different than fctx.
741 """
741 """
742 if fctx._customcmp:
742 if fctx._customcmp:
743 return fctx.cmp(self)
743 return fctx.cmp(self)
744
744
745 if self._filenode is None:
745 if self._filenode is None:
746 raise error.ProgrammingError(
746 raise error.ProgrammingError(
747 'filectx.cmp() must be reimplemented if not backed by revlog')
747 'filectx.cmp() must be reimplemented if not backed by revlog')
748
748
749 if fctx._filenode is None:
749 if fctx._filenode is None:
750 if self._repo._encodefilterpats:
750 if self._repo._encodefilterpats:
751 # can't rely on size() because wdir content may be decoded
751 # can't rely on size() because wdir content may be decoded
752 return self._filelog.cmp(self._filenode, fctx.data())
752 return self._filelog.cmp(self._filenode, fctx.data())
753 if self.size() - 4 == fctx.size():
753 if self.size() - 4 == fctx.size():
754 # size() can match:
754 # size() can match:
755 # if file data starts with '\1\n', empty metadata block is
755 # if file data starts with '\1\n', empty metadata block is
756 # prepended, which adds 4 bytes to filelog.size().
756 # prepended, which adds 4 bytes to filelog.size().
757 return self._filelog.cmp(self._filenode, fctx.data())
757 return self._filelog.cmp(self._filenode, fctx.data())
758 if self.size() == fctx.size():
758 if self.size() == fctx.size():
759 # size() matches: need to compare content
759 # size() matches: need to compare content
760 return self._filelog.cmp(self._filenode, fctx.data())
760 return self._filelog.cmp(self._filenode, fctx.data())
761
761
762 # size() differs
762 # size() differs
763 return True
763 return True
764
764
765 def _adjustlinkrev(self, srcrev, inclusive=False, stoprev=None):
765 def _adjustlinkrev(self, srcrev, inclusive=False, stoprev=None):
766 """return the first ancestor of <srcrev> introducing <fnode>
766 """return the first ancestor of <srcrev> introducing <fnode>
767
767
768 If the linkrev of the file revision does not point to an ancestor of
768 If the linkrev of the file revision does not point to an ancestor of
769 srcrev, we'll walk down the ancestors until we find one introducing
769 srcrev, we'll walk down the ancestors until we find one introducing
770 this file revision.
770 this file revision.
771
771
772 :srcrev: the changeset revision we search ancestors from
772 :srcrev: the changeset revision we search ancestors from
773 :inclusive: if true, the src revision will also be checked
773 :inclusive: if true, the src revision will also be checked
774 :stoprev: an optional revision to stop the walk at. If no introduction
774 :stoprev: an optional revision to stop the walk at. If no introduction
775 of this file content could be found before this floor
775 of this file content could be found before this floor
776 revision, the function will returns "None" and stops its
776 revision, the function will returns "None" and stops its
777 iteration.
777 iteration.
778 """
778 """
779 repo = self._repo
779 repo = self._repo
780 cl = repo.unfiltered().changelog
780 cl = repo.unfiltered().changelog
781 mfl = repo.manifestlog
781 mfl = repo.manifestlog
782 # fetch the linkrev
782 # fetch the linkrev
783 lkr = self.linkrev()
783 lkr = self.linkrev()
784 if srcrev == lkr:
784 if srcrev == lkr:
785 return lkr
785 return lkr
786 # hack to reuse ancestor computation when searching for renames
786 # hack to reuse ancestor computation when searching for renames
787 memberanc = getattr(self, '_ancestrycontext', None)
787 memberanc = getattr(self, '_ancestrycontext', None)
788 iteranc = None
788 iteranc = None
789 if srcrev is None:
789 if srcrev is None:
790 # wctx case, used by workingfilectx during mergecopy
790 # wctx case, used by workingfilectx during mergecopy
791 revs = [p.rev() for p in self._repo[None].parents()]
791 revs = [p.rev() for p in self._repo[None].parents()]
792 inclusive = True # we skipped the real (revless) source
792 inclusive = True # we skipped the real (revless) source
793 else:
793 else:
794 revs = [srcrev]
794 revs = [srcrev]
795 if memberanc is None:
795 if memberanc is None:
796 memberanc = iteranc = cl.ancestors(revs, lkr,
796 memberanc = iteranc = cl.ancestors(revs, lkr,
797 inclusive=inclusive)
797 inclusive=inclusive)
798 # check if this linkrev is an ancestor of srcrev
798 # check if this linkrev is an ancestor of srcrev
799 if lkr not in memberanc:
799 if lkr not in memberanc:
800 if iteranc is None:
800 if iteranc is None:
801 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
801 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
802 fnode = self._filenode
802 fnode = self._filenode
803 path = self._path
803 path = self._path
804 for a in iteranc:
804 for a in iteranc:
805 if stoprev is not None and a < stoprev:
805 if stoprev is not None and a < stoprev:
806 return None
806 return None
807 ac = cl.read(a) # get changeset data (we avoid object creation)
807 ac = cl.read(a) # get changeset data (we avoid object creation)
808 if path in ac[3]: # checking the 'files' field.
808 if path in ac[3]: # checking the 'files' field.
809 # The file has been touched, check if the content is
809 # The file has been touched, check if the content is
810 # similar to the one we search for.
810 # similar to the one we search for.
811 if fnode == mfl[ac[0]].readfast().get(path):
811 if fnode == mfl[ac[0]].readfast().get(path):
812 return a
812 return a
813 # In theory, we should never get out of that loop without a result.
813 # In theory, we should never get out of that loop without a result.
814 # But if manifest uses a buggy file revision (not children of the
814 # But if manifest uses a buggy file revision (not children of the
815 # one it replaces) we could. Such a buggy situation will likely
815 # one it replaces) we could. Such a buggy situation will likely
816 # result is crash somewhere else at to some point.
816 # result is crash somewhere else at to some point.
817 return lkr
817 return lkr
818
818
819 def isintroducedafter(self, changelogrev):
819 def isintroducedafter(self, changelogrev):
820 """True if a filectx has been introduced after a given floor revision
820 """True if a filectx has been introduced after a given floor revision
821 """
821 """
822 if self.linkrev() >= changelogrev:
822 if self.linkrev() >= changelogrev:
823 return True
823 return True
824 introrev = self._introrev(stoprev=changelogrev)
824 introrev = self._introrev(stoprev=changelogrev)
825 if introrev is None:
825 if introrev is None:
826 return False
826 return False
827 return introrev >= changelogrev
827 return introrev >= changelogrev
828
828
829 def introrev(self):
829 def introrev(self):
830 """return the rev of the changeset which introduced this file revision
830 """return the rev of the changeset which introduced this file revision
831
831
832 This method is different from linkrev because it take into account the
832 This method is different from linkrev because it take into account the
833 changeset the filectx was created from. It ensures the returned
833 changeset the filectx was created from. It ensures the returned
834 revision is one of its ancestors. This prevents bugs from
834 revision is one of its ancestors. This prevents bugs from
835 'linkrev-shadowing' when a file revision is used by multiple
835 'linkrev-shadowing' when a file revision is used by multiple
836 changesets.
836 changesets.
837 """
837 """
838 return self._introrev()
838 return self._introrev()
839
839
840 def _introrev(self, stoprev=None):
840 def _introrev(self, stoprev=None):
841 """
841 """
842 Same as `introrev` but, with an extra argument to limit changelog
842 Same as `introrev` but, with an extra argument to limit changelog
843 iteration range in some internal usecase.
843 iteration range in some internal usecase.
844
844
845 If `stoprev` is set, the `introrev` will not be searched past that
845 If `stoprev` is set, the `introrev` will not be searched past that
846 `stoprev` revision and "None" might be returned. This is useful to
846 `stoprev` revision and "None" might be returned. This is useful to
847 limit the iteration range.
847 limit the iteration range.
848 """
848 """
849 toprev = None
849 toprev = None
850 attrs = vars(self)
850 attrs = vars(self)
851 if r'_changeid' in attrs:
851 if r'_changeid' in attrs:
852 # We have a cached value already
852 # We have a cached value already
853 toprev = self._changeid
853 toprev = self._changeid
854 elif r'_changectx' in attrs:
854 elif r'_changectx' in attrs:
855 # We know which changelog entry we are coming from
855 # We know which changelog entry we are coming from
856 toprev = self._changectx.rev()
856 toprev = self._changectx.rev()
857
857
858 if toprev is not None:
858 if toprev is not None:
859 return self._adjustlinkrev(toprev, inclusive=True, stoprev=stoprev)
859 return self._adjustlinkrev(toprev, inclusive=True, stoprev=stoprev)
860 elif r'_descendantrev' in attrs:
860 elif r'_descendantrev' in attrs:
861 introrev = self._adjustlinkrev(self._descendantrev, stoprev=stoprev)
861 introrev = self._adjustlinkrev(self._descendantrev, stoprev=stoprev)
862 # be nice and cache the result of the computation
862 # be nice and cache the result of the computation
863 if introrev is not None:
863 if introrev is not None:
864 self._changeid = introrev
864 self._changeid = introrev
865 return introrev
865 return introrev
866 else:
866 else:
867 return self.linkrev()
867 return self.linkrev()
868
868
869 def introfilectx(self):
869 def introfilectx(self):
870 """Return filectx having identical contents, but pointing to the
870 """Return filectx having identical contents, but pointing to the
871 changeset revision where this filectx was introduced"""
871 changeset revision where this filectx was introduced"""
872 introrev = self.introrev()
872 introrev = self.introrev()
873 if self.rev() == introrev:
873 if self.rev() == introrev:
874 return self
874 return self
875 return self.filectx(self.filenode(), changeid=introrev)
875 return self.filectx(self.filenode(), changeid=introrev)
876
876
877 def _parentfilectx(self, path, fileid, filelog):
877 def _parentfilectx(self, path, fileid, filelog):
878 """create parent filectx keeping ancestry info for _adjustlinkrev()"""
878 """create parent filectx keeping ancestry info for _adjustlinkrev()"""
879 fctx = filectx(self._repo, path, fileid=fileid, filelog=filelog)
879 fctx = filectx(self._repo, path, fileid=fileid, filelog=filelog)
880 if r'_changeid' in vars(self) or r'_changectx' in vars(self):
880 if r'_changeid' in vars(self) or r'_changectx' in vars(self):
881 # If self is associated with a changeset (probably explicitly
881 # If self is associated with a changeset (probably explicitly
882 # fed), ensure the created filectx is associated with a
882 # fed), ensure the created filectx is associated with a
883 # changeset that is an ancestor of self.changectx.
883 # changeset that is an ancestor of self.changectx.
884 # This lets us later use _adjustlinkrev to get a correct link.
884 # This lets us later use _adjustlinkrev to get a correct link.
885 fctx._descendantrev = self.rev()
885 fctx._descendantrev = self.rev()
886 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
886 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
887 elif r'_descendantrev' in vars(self):
887 elif r'_descendantrev' in vars(self):
888 # Otherwise propagate _descendantrev if we have one associated.
888 # Otherwise propagate _descendantrev if we have one associated.
889 fctx._descendantrev = self._descendantrev
889 fctx._descendantrev = self._descendantrev
890 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
890 fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
891 return fctx
891 return fctx
892
892
893 def parents(self):
893 def parents(self):
894 _path = self._path
894 _path = self._path
895 fl = self._filelog
895 fl = self._filelog
896 parents = self._filelog.parents(self._filenode)
896 parents = self._filelog.parents(self._filenode)
897 pl = [(_path, node, fl) for node in parents if node != nullid]
897 pl = [(_path, node, fl) for node in parents if node != nullid]
898
898
899 r = fl.renamed(self._filenode)
899 r = fl.renamed(self._filenode)
900 if r:
900 if r:
901 # - In the simple rename case, both parent are nullid, pl is empty.
901 # - In the simple rename case, both parent are nullid, pl is empty.
902 # - In case of merge, only one of the parent is null id and should
902 # - In case of merge, only one of the parent is null id and should
903 # be replaced with the rename information. This parent is -always-
903 # be replaced with the rename information. This parent is -always-
904 # the first one.
904 # the first one.
905 #
905 #
906 # As null id have always been filtered out in the previous list
906 # As null id have always been filtered out in the previous list
907 # comprehension, inserting to 0 will always result in "replacing
907 # comprehension, inserting to 0 will always result in "replacing
908 # first nullid parent with rename information.
908 # first nullid parent with rename information.
909 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
909 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
910
910
911 return [self._parentfilectx(path, fnode, l) for path, fnode, l in pl]
911 return [self._parentfilectx(path, fnode, l) for path, fnode, l in pl]
912
912
913 def p1(self):
913 def p1(self):
914 return self.parents()[0]
914 return self.parents()[0]
915
915
916 def p2(self):
916 def p2(self):
917 p = self.parents()
917 p = self.parents()
918 if len(p) == 2:
918 if len(p) == 2:
919 return p[1]
919 return p[1]
920 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
920 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
921
921
922 def annotate(self, follow=False, skiprevs=None, diffopts=None):
922 def annotate(self, follow=False, skiprevs=None, diffopts=None):
923 """Returns a list of annotateline objects for each line in the file
923 """Returns a list of annotateline objects for each line in the file
924
924
925 - line.fctx is the filectx of the node where that line was last changed
925 - line.fctx is the filectx of the node where that line was last changed
926 - line.lineno is the line number at the first appearance in the managed
926 - line.lineno is the line number at the first appearance in the managed
927 file
927 file
928 - line.text is the data on that line (including newline character)
928 - line.text is the data on that line (including newline character)
929 """
929 """
930 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
930 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
931
931
932 def parents(f):
932 def parents(f):
933 # Cut _descendantrev here to mitigate the penalty of lazy linkrev
933 # Cut _descendantrev here to mitigate the penalty of lazy linkrev
934 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
934 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog
935 # from the topmost introrev (= srcrev) down to p.linkrev() if it
935 # from the topmost introrev (= srcrev) down to p.linkrev() if it
936 # isn't an ancestor of the srcrev.
936 # isn't an ancestor of the srcrev.
937 f._changeid
937 f._changeid
938 pl = f.parents()
938 pl = f.parents()
939
939
940 # Don't return renamed parents if we aren't following.
940 # Don't return renamed parents if we aren't following.
941 if not follow:
941 if not follow:
942 pl = [p for p in pl if p.path() == f.path()]
942 pl = [p for p in pl if p.path() == f.path()]
943
943
944 # renamed filectx won't have a filelog yet, so set it
944 # renamed filectx won't have a filelog yet, so set it
945 # from the cache to save time
945 # from the cache to save time
946 for p in pl:
946 for p in pl:
947 if not r'_filelog' in p.__dict__:
947 if not r'_filelog' in p.__dict__:
948 p._filelog = getlog(p.path())
948 p._filelog = getlog(p.path())
949
949
950 return pl
950 return pl
951
951
952 # use linkrev to find the first changeset where self appeared
952 # use linkrev to find the first changeset where self appeared
953 base = self.introfilectx()
953 base = self.introfilectx()
954 if getattr(base, '_ancestrycontext', None) is None:
954 if getattr(base, '_ancestrycontext', None) is None:
955 cl = self._repo.changelog
955 cl = self._repo.changelog
956 if base.rev() is None:
956 if base.rev() is None:
957 # wctx is not inclusive, but works because _ancestrycontext
957 # wctx is not inclusive, but works because _ancestrycontext
958 # is used to test filelog revisions
958 # is used to test filelog revisions
959 ac = cl.ancestors([p.rev() for p in base.parents()],
959 ac = cl.ancestors([p.rev() for p in base.parents()],
960 inclusive=True)
960 inclusive=True)
961 else:
961 else:
962 ac = cl.ancestors([base.rev()], inclusive=True)
962 ac = cl.ancestors([base.rev()], inclusive=True)
963 base._ancestrycontext = ac
963 base._ancestrycontext = ac
964
964
965 return dagop.annotate(base, parents, skiprevs=skiprevs,
965 return dagop.annotate(base, parents, skiprevs=skiprevs,
966 diffopts=diffopts)
966 diffopts=diffopts)
967
967
968 def ancestors(self, followfirst=False):
968 def ancestors(self, followfirst=False):
969 visit = {}
969 visit = {}
970 c = self
970 c = self
971 if followfirst:
971 if followfirst:
972 cut = 1
972 cut = 1
973 else:
973 else:
974 cut = None
974 cut = None
975
975
976 while True:
976 while True:
977 for parent in c.parents()[:cut]:
977 for parent in c.parents()[:cut]:
978 visit[(parent.linkrev(), parent.filenode())] = parent
978 visit[(parent.linkrev(), parent.filenode())] = parent
979 if not visit:
979 if not visit:
980 break
980 break
981 c = visit.pop(max(visit))
981 c = visit.pop(max(visit))
982 yield c
982 yield c
983
983
984 def decodeddata(self):
984 def decodeddata(self):
985 """Returns `data()` after running repository decoding filters.
985 """Returns `data()` after running repository decoding filters.
986
986
987 This is often equivalent to how the data would be expressed on disk.
987 This is often equivalent to how the data would be expressed on disk.
988 """
988 """
989 return self._repo.wwritedata(self.path(), self.data())
989 return self._repo.wwritedata(self.path(), self.data())
990
990
991 class filectx(basefilectx):
991 class filectx(basefilectx):
992 """A filecontext object makes access to data related to a particular
992 """A filecontext object makes access to data related to a particular
993 filerevision convenient."""
993 filerevision convenient."""
994 def __init__(self, repo, path, changeid=None, fileid=None,
994 def __init__(self, repo, path, changeid=None, fileid=None,
995 filelog=None, changectx=None):
995 filelog=None, changectx=None):
996 """changeid must be a revision number, if specified.
996 """changeid must be a revision number, if specified.
997 fileid can be a file revision or node."""
997 fileid can be a file revision or node."""
998 self._repo = repo
998 self._repo = repo
999 self._path = path
999 self._path = path
1000
1000
1001 assert (changeid is not None
1001 assert (changeid is not None
1002 or fileid is not None
1002 or fileid is not None
1003 or changectx is not None), (
1003 or changectx is not None), (
1004 "bad args: changeid=%r, fileid=%r, changectx=%r"
1004 "bad args: changeid=%r, fileid=%r, changectx=%r"
1005 % (changeid, fileid, changectx))
1005 % (changeid, fileid, changectx))
1006
1006
1007 if filelog is not None:
1007 if filelog is not None:
1008 self._filelog = filelog
1008 self._filelog = filelog
1009
1009
1010 if changeid is not None:
1010 if changeid is not None:
1011 self._changeid = changeid
1011 self._changeid = changeid
1012 if changectx is not None:
1012 if changectx is not None:
1013 self._changectx = changectx
1013 self._changectx = changectx
1014 if fileid is not None:
1014 if fileid is not None:
1015 self._fileid = fileid
1015 self._fileid = fileid
1016
1016
1017 @propertycache
1017 @propertycache
1018 def _changectx(self):
1018 def _changectx(self):
1019 try:
1019 try:
1020 return self._repo[self._changeid]
1020 return self._repo[self._changeid]
1021 except error.FilteredRepoLookupError:
1021 except error.FilteredRepoLookupError:
1022 # Linkrev may point to any revision in the repository. When the
1022 # Linkrev may point to any revision in the repository. When the
1023 # repository is filtered this may lead to `filectx` trying to build
1023 # repository is filtered this may lead to `filectx` trying to build
1024 # `changectx` for filtered revision. In such case we fallback to
1024 # `changectx` for filtered revision. In such case we fallback to
1025 # creating `changectx` on the unfiltered version of the reposition.
1025 # creating `changectx` on the unfiltered version of the reposition.
1026 # This fallback should not be an issue because `changectx` from
1026 # This fallback should not be an issue because `changectx` from
1027 # `filectx` are not used in complex operations that care about
1027 # `filectx` are not used in complex operations that care about
1028 # filtering.
1028 # filtering.
1029 #
1029 #
1030 # This fallback is a cheap and dirty fix that prevent several
1030 # This fallback is a cheap and dirty fix that prevent several
1031 # crashes. It does not ensure the behavior is correct. However the
1031 # crashes. It does not ensure the behavior is correct. However the
1032 # behavior was not correct before filtering either and "incorrect
1032 # behavior was not correct before filtering either and "incorrect
1033 # behavior" is seen as better as "crash"
1033 # behavior" is seen as better as "crash"
1034 #
1034 #
1035 # Linkrevs have several serious troubles with filtering that are
1035 # Linkrevs have several serious troubles with filtering that are
1036 # complicated to solve. Proper handling of the issue here should be
1036 # complicated to solve. Proper handling of the issue here should be
1037 # considered when solving linkrev issue are on the table.
1037 # considered when solving linkrev issue are on the table.
1038 return self._repo.unfiltered()[self._changeid]
1038 return self._repo.unfiltered()[self._changeid]
1039
1039
1040 def filectx(self, fileid, changeid=None):
1040 def filectx(self, fileid, changeid=None):
1041 '''opens an arbitrary revision of the file without
1041 '''opens an arbitrary revision of the file without
1042 opening a new filelog'''
1042 opening a new filelog'''
1043 return filectx(self._repo, self._path, fileid=fileid,
1043 return filectx(self._repo, self._path, fileid=fileid,
1044 filelog=self._filelog, changeid=changeid)
1044 filelog=self._filelog, changeid=changeid)
1045
1045
1046 def rawdata(self):
1046 def rawdata(self):
1047 return self._filelog.revision(self._filenode, raw=True)
1047 return self._filelog.revision(self._filenode, raw=True)
1048
1048
1049 def rawflags(self):
1049 def rawflags(self):
1050 """low-level revlog flags"""
1050 """low-level revlog flags"""
1051 return self._filelog.flags(self._filerev)
1051 return self._filelog.flags(self._filerev)
1052
1052
1053 def data(self):
1053 def data(self):
1054 try:
1054 try:
1055 return self._filelog.read(self._filenode)
1055 return self._filelog.read(self._filenode)
1056 except error.CensoredNodeError:
1056 except error.CensoredNodeError:
1057 if self._repo.ui.config("censor", "policy") == "ignore":
1057 if self._repo.ui.config("censor", "policy") == "ignore":
1058 return ""
1058 return ""
1059 raise error.Abort(_("censored node: %s") % short(self._filenode),
1059 raise error.Abort(_("censored node: %s") % short(self._filenode),
1060 hint=_("set censor.policy to ignore errors"))
1060 hint=_("set censor.policy to ignore errors"))
1061
1061
1062 def size(self):
1062 def size(self):
1063 return self._filelog.size(self._filerev)
1063 return self._filelog.size(self._filerev)
1064
1064
1065 @propertycache
1065 @propertycache
1066 def _copied(self):
1066 def _copied(self):
1067 """check if file was actually renamed in this changeset revision
1067 """check if file was actually renamed in this changeset revision
1068
1068
1069 If rename logged in file revision, we report copy for changeset only
1069 If rename logged in file revision, we report copy for changeset only
1070 if file revisions linkrev points back to the changeset in question
1070 if file revisions linkrev points back to the changeset in question
1071 or both changeset parents contain different file revisions.
1071 or both changeset parents contain different file revisions.
1072 """
1072 """
1073
1073
1074 renamed = self._filelog.renamed(self._filenode)
1074 renamed = self._filelog.renamed(self._filenode)
1075 if not renamed:
1075 if not renamed:
1076 return None
1076 return None
1077
1077
1078 if self.rev() == self.linkrev():
1078 if self.rev() == self.linkrev():
1079 return renamed
1079 return renamed
1080
1080
1081 name = self.path()
1081 name = self.path()
1082 fnode = self._filenode
1082 fnode = self._filenode
1083 for p in self._changectx.parents():
1083 for p in self._changectx.parents():
1084 try:
1084 try:
1085 if fnode == p.filenode(name):
1085 if fnode == p.filenode(name):
1086 return None
1086 return None
1087 except error.LookupError:
1087 except error.LookupError:
1088 pass
1088 pass
1089 return renamed
1089 return renamed
1090
1090
1091 def children(self):
1091 def children(self):
1092 # hard for renames
1092 # hard for renames
1093 c = self._filelog.children(self._filenode)
1093 c = self._filelog.children(self._filenode)
1094 return [filectx(self._repo, self._path, fileid=x,
1094 return [filectx(self._repo, self._path, fileid=x,
1095 filelog=self._filelog) for x in c]
1095 filelog=self._filelog) for x in c]
1096
1096
1097 class committablectx(basectx):
1097 class committablectx(basectx):
1098 """A committablectx object provides common functionality for a context that
1098 """A committablectx object provides common functionality for a context that
1099 wants the ability to commit, e.g. workingctx or memctx."""
1099 wants the ability to commit, e.g. workingctx or memctx."""
1100 def __init__(self, repo, text="", user=None, date=None, extra=None,
1100 def __init__(self, repo, text="", user=None, date=None, extra=None,
1101 changes=None):
1101 changes=None):
1102 super(committablectx, self).__init__(repo)
1102 super(committablectx, self).__init__(repo)
1103 self._rev = None
1103 self._rev = None
1104 self._node = None
1104 self._node = None
1105 self._text = text
1105 self._text = text
1106 if date:
1106 if date:
1107 self._date = dateutil.parsedate(date)
1107 self._date = dateutil.parsedate(date)
1108 if user:
1108 if user:
1109 self._user = user
1109 self._user = user
1110 if changes:
1110 if changes:
1111 self._status = changes
1111 self._status = changes
1112
1112
1113 self._extra = {}
1113 self._extra = {}
1114 if extra:
1114 if extra:
1115 self._extra = extra.copy()
1115 self._extra = extra.copy()
1116 if 'branch' not in self._extra:
1116 if 'branch' not in self._extra:
1117 try:
1117 try:
1118 branch = encoding.fromlocal(self._repo.dirstate.branch())
1118 branch = encoding.fromlocal(self._repo.dirstate.branch())
1119 except UnicodeDecodeError:
1119 except UnicodeDecodeError:
1120 raise error.Abort(_('branch name not in UTF-8!'))
1120 raise error.Abort(_('branch name not in UTF-8!'))
1121 self._extra['branch'] = branch
1121 self._extra['branch'] = branch
1122 if self._extra['branch'] == '':
1122 if self._extra['branch'] == '':
1123 self._extra['branch'] = 'default'
1123 self._extra['branch'] = 'default'
1124
1124
1125 def __bytes__(self):
1125 def __bytes__(self):
1126 return bytes(self._parents[0]) + "+"
1126 return bytes(self._parents[0]) + "+"
1127
1127
1128 __str__ = encoding.strmethod(__bytes__)
1128 __str__ = encoding.strmethod(__bytes__)
1129
1129
1130 def __nonzero__(self):
1130 def __nonzero__(self):
1131 return True
1131 return True
1132
1132
1133 __bool__ = __nonzero__
1133 __bool__ = __nonzero__
1134
1134
1135 def _buildflagfunc(self):
1135 def _buildflagfunc(self):
1136 # Create a fallback function for getting file flags when the
1136 # Create a fallback function for getting file flags when the
1137 # filesystem doesn't support them
1137 # filesystem doesn't support them
1138
1138
1139 copiesget = self._repo.dirstate.copies().get
1139 copiesget = self._repo.dirstate.copies().get
1140 parents = self.parents()
1140 parents = self.parents()
1141 if len(parents) < 2:
1141 if len(parents) < 2:
1142 # when we have one parent, it's easy: copy from parent
1142 # when we have one parent, it's easy: copy from parent
1143 man = parents[0].manifest()
1143 man = parents[0].manifest()
1144 def func(f):
1144 def func(f):
1145 f = copiesget(f, f)
1145 f = copiesget(f, f)
1146 return man.flags(f)
1146 return man.flags(f)
1147 else:
1147 else:
1148 # merges are tricky: we try to reconstruct the unstored
1148 # merges are tricky: we try to reconstruct the unstored
1149 # result from the merge (issue1802)
1149 # result from the merge (issue1802)
1150 p1, p2 = parents
1150 p1, p2 = parents
1151 pa = p1.ancestor(p2)
1151 pa = p1.ancestor(p2)
1152 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
1152 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
1153
1153
1154 def func(f):
1154 def func(f):
1155 f = copiesget(f, f) # may be wrong for merges with copies
1155 f = copiesget(f, f) # may be wrong for merges with copies
1156 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
1156 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
1157 if fl1 == fl2:
1157 if fl1 == fl2:
1158 return fl1
1158 return fl1
1159 if fl1 == fla:
1159 if fl1 == fla:
1160 return fl2
1160 return fl2
1161 if fl2 == fla:
1161 if fl2 == fla:
1162 return fl1
1162 return fl1
1163 return '' # punt for conflicts
1163 return '' # punt for conflicts
1164
1164
1165 return func
1165 return func
1166
1166
1167 @propertycache
1167 @propertycache
1168 def _flagfunc(self):
1168 def _flagfunc(self):
1169 return self._repo.dirstate.flagfunc(self._buildflagfunc)
1169 return self._repo.dirstate.flagfunc(self._buildflagfunc)
1170
1170
1171 @propertycache
1171 @propertycache
1172 def _status(self):
1172 def _status(self):
1173 return self._repo.status()
1173 return self._repo.status()
1174
1174
1175 @propertycache
1175 @propertycache
1176 def _user(self):
1176 def _user(self):
1177 return self._repo.ui.username()
1177 return self._repo.ui.username()
1178
1178
1179 @propertycache
1179 @propertycache
1180 def _date(self):
1180 def _date(self):
1181 ui = self._repo.ui
1181 ui = self._repo.ui
1182 date = ui.configdate('devel', 'default-date')
1182 date = ui.configdate('devel', 'default-date')
1183 if date is None:
1183 if date is None:
1184 date = dateutil.makedate()
1184 date = dateutil.makedate()
1185 return date
1185 return date
1186
1186
1187 def subrev(self, subpath):
1187 def subrev(self, subpath):
1188 return None
1188 return None
1189
1189
1190 def manifestnode(self):
1190 def manifestnode(self):
1191 return None
1191 return None
1192 def user(self):
1192 def user(self):
1193 return self._user or self._repo.ui.username()
1193 return self._user or self._repo.ui.username()
1194 def date(self):
1194 def date(self):
1195 return self._date
1195 return self._date
1196 def description(self):
1196 def description(self):
1197 return self._text
1197 return self._text
1198 def files(self):
1198 def files(self):
1199 return sorted(self._status.modified + self._status.added +
1199 return sorted(self._status.modified + self._status.added +
1200 self._status.removed)
1200 self._status.removed)
1201 def modified(self):
1201 def modified(self):
1202 return self._status.modified
1202 return self._status.modified
1203 def added(self):
1203 def added(self):
1204 return self._status.added
1204 return self._status.added
1205 def removed(self):
1205 def removed(self):
1206 return self._status.removed
1206 return self._status.removed
1207 def deleted(self):
1207 def deleted(self):
1208 return self._status.deleted
1208 return self._status.deleted
1209 @propertycache
1209 @propertycache
1210 def _copies(self):
1210 def _copies(self):
1211 p1copies = {}
1211 p1copies = {}
1212 p2copies = {}
1212 p2copies = {}
1213 parents = self._repo.dirstate.parents()
1213 parents = self._repo.dirstate.parents()
1214 p1manifest = self._repo[parents[0]].manifest()
1214 p1manifest = self._repo[parents[0]].manifest()
1215 p2manifest = self._repo[parents[1]].manifest()
1215 p2manifest = self._repo[parents[1]].manifest()
1216 narrowmatch = self._repo.narrowmatch()
1216 narrowmatch = self._repo.narrowmatch()
1217 for dst, src in self._repo.dirstate.copies().items():
1217 for dst, src in self._repo.dirstate.copies().items():
1218 if not narrowmatch(dst):
1218 if not narrowmatch(dst):
1219 continue
1219 continue
1220 if src in p1manifest:
1220 if src in p1manifest:
1221 p1copies[dst] = src
1221 p1copies[dst] = src
1222 elif src in p2manifest:
1222 elif src in p2manifest:
1223 p2copies[dst] = src
1223 p2copies[dst] = src
1224 return p1copies, p2copies
1224 return p1copies, p2copies
1225 def p1copies(self):
1225 def p1copies(self):
1226 return self._copies[0]
1226 return self._copies[0]
1227 def p2copies(self):
1227 def p2copies(self):
1228 return self._copies[1]
1228 return self._copies[1]
1229 def branch(self):
1229 def branch(self):
1230 return encoding.tolocal(self._extra['branch'])
1230 return encoding.tolocal(self._extra['branch'])
1231 def closesbranch(self):
1231 def closesbranch(self):
1232 return 'close' in self._extra
1232 return 'close' in self._extra
1233 def extra(self):
1233 def extra(self):
1234 return self._extra
1234 return self._extra
1235
1235
1236 def isinmemory(self):
1236 def isinmemory(self):
1237 return False
1237 return False
1238
1238
1239 def tags(self):
1239 def tags(self):
1240 return []
1240 return []
1241
1241
1242 def bookmarks(self):
1242 def bookmarks(self):
1243 b = []
1243 b = []
1244 for p in self.parents():
1244 for p in self.parents():
1245 b.extend(p.bookmarks())
1245 b.extend(p.bookmarks())
1246 return b
1246 return b
1247
1247
1248 def phase(self):
1248 def phase(self):
1249 phase = phases.draft # default phase to draft
1249 phase = phases.draft # default phase to draft
1250 for p in self.parents():
1250 for p in self.parents():
1251 phase = max(phase, p.phase())
1251 phase = max(phase, p.phase())
1252 return phase
1252 return phase
1253
1253
1254 def hidden(self):
1254 def hidden(self):
1255 return False
1255 return False
1256
1256
1257 def children(self):
1257 def children(self):
1258 return []
1258 return []
1259
1259
1260 def flags(self, path):
1260 def flags(self, path):
1261 if r'_manifest' in self.__dict__:
1261 if r'_manifest' in self.__dict__:
1262 try:
1262 try:
1263 return self._manifest.flags(path)
1263 return self._manifest.flags(path)
1264 except KeyError:
1264 except KeyError:
1265 return ''
1265 return ''
1266
1266
1267 try:
1267 try:
1268 return self._flagfunc(path)
1268 return self._flagfunc(path)
1269 except OSError:
1269 except OSError:
1270 return ''
1270 return ''
1271
1271
1272 def ancestor(self, c2):
1272 def ancestor(self, c2):
1273 """return the "best" ancestor context of self and c2"""
1273 """return the "best" ancestor context of self and c2"""
1274 return self._parents[0].ancestor(c2) # punt on two parents for now
1274 return self._parents[0].ancestor(c2) # punt on two parents for now
1275
1275
1276 def walk(self, match):
1276 def walk(self, match):
1277 '''Generates matching file names.'''
1277 '''Generates matching file names.'''
1278 return sorted(self._repo.dirstate.walk(self._repo.narrowmatch(match),
1278 return sorted(self._repo.dirstate.walk(self._repo.narrowmatch(match),
1279 subrepos=sorted(self.substate),
1279 subrepos=sorted(self.substate),
1280 unknown=True, ignored=False))
1280 unknown=True, ignored=False))
1281
1281
1282 def matches(self, match):
1282 def matches(self, match):
1283 match = self._repo.narrowmatch(match)
1283 match = self._repo.narrowmatch(match)
1284 ds = self._repo.dirstate
1284 ds = self._repo.dirstate
1285 return sorted(f for f in ds.matches(match) if ds[f] != 'r')
1285 return sorted(f for f in ds.matches(match) if ds[f] != 'r')
1286
1286
1287 def ancestors(self):
1287 def ancestors(self):
1288 for p in self._parents:
1288 for p in self._parents:
1289 yield p
1289 yield p
1290 for a in self._repo.changelog.ancestors(
1290 for a in self._repo.changelog.ancestors(
1291 [p.rev() for p in self._parents]):
1291 [p.rev() for p in self._parents]):
1292 yield self._repo[a]
1292 yield self._repo[a]
1293
1293
1294 def markcommitted(self, node):
1294 def markcommitted(self, node):
1295 """Perform post-commit cleanup necessary after committing this ctx
1295 """Perform post-commit cleanup necessary after committing this ctx
1296
1296
1297 Specifically, this updates backing stores this working context
1297 Specifically, this updates backing stores this working context
1298 wraps to reflect the fact that the changes reflected by this
1298 wraps to reflect the fact that the changes reflected by this
1299 workingctx have been committed. For example, it marks
1299 workingctx have been committed. For example, it marks
1300 modified and added files as normal in the dirstate.
1300 modified and added files as normal in the dirstate.
1301
1301
1302 """
1302 """
1303
1303
1304 with self._repo.dirstate.parentchange():
1304 with self._repo.dirstate.parentchange():
1305 for f in self.modified() + self.added():
1305 for f in self.modified() + self.added():
1306 self._repo.dirstate.normal(f)
1306 self._repo.dirstate.normal(f)
1307 for f in self.removed():
1307 for f in self.removed():
1308 self._repo.dirstate.drop(f)
1308 self._repo.dirstate.drop(f)
1309 self._repo.dirstate.setparents(node)
1309 self._repo.dirstate.setparents(node)
1310
1310
1311 # write changes out explicitly, because nesting wlock at
1311 # write changes out explicitly, because nesting wlock at
1312 # runtime may prevent 'wlock.release()' in 'repo.commit()'
1312 # runtime may prevent 'wlock.release()' in 'repo.commit()'
1313 # from immediately doing so for subsequent changing files
1313 # from immediately doing so for subsequent changing files
1314 self._repo.dirstate.write(self._repo.currenttransaction())
1314 self._repo.dirstate.write(self._repo.currenttransaction())
1315
1315
1316 def dirty(self, missing=False, merge=True, branch=True):
1316 def dirty(self, missing=False, merge=True, branch=True):
1317 return False
1317 return False
1318
1318
1319 class workingctx(committablectx):
1319 class workingctx(committablectx):
1320 """A workingctx object makes access to data related to
1320 """A workingctx object makes access to data related to
1321 the current working directory convenient.
1321 the current working directory convenient.
1322 date - any valid date string or (unixtime, offset), or None.
1322 date - any valid date string or (unixtime, offset), or None.
1323 user - username string, or None.
1323 user - username string, or None.
1324 extra - a dictionary of extra values, or None.
1324 extra - a dictionary of extra values, or None.
1325 changes - a list of file lists as returned by localrepo.status()
1325 changes - a list of file lists as returned by localrepo.status()
1326 or None to use the repository status.
1326 or None to use the repository status.
1327 """
1327 """
1328 def __init__(self, repo, text="", user=None, date=None, extra=None,
1328 def __init__(self, repo, text="", user=None, date=None, extra=None,
1329 changes=None):
1329 changes=None):
1330 super(workingctx, self).__init__(repo, text, user, date, extra, changes)
1330 super(workingctx, self).__init__(repo, text, user, date, extra, changes)
1331
1331
1332 def __iter__(self):
1332 def __iter__(self):
1333 d = self._repo.dirstate
1333 d = self._repo.dirstate
1334 for f in d:
1334 for f in d:
1335 if d[f] != 'r':
1335 if d[f] != 'r':
1336 yield f
1336 yield f
1337
1337
1338 def __contains__(self, key):
1338 def __contains__(self, key):
1339 return self._repo.dirstate[key] not in "?r"
1339 return self._repo.dirstate[key] not in "?r"
1340
1340
1341 def hex(self):
1341 def hex(self):
1342 return wdirhex
1342 return wdirhex
1343
1343
1344 @propertycache
1344 @propertycache
1345 def _parents(self):
1345 def _parents(self):
1346 p = self._repo.dirstate.parents()
1346 p = self._repo.dirstate.parents()
1347 if p[1] == nullid:
1347 if p[1] == nullid:
1348 p = p[:-1]
1348 p = p[:-1]
1349 # use unfiltered repo to delay/avoid loading obsmarkers
1349 # use unfiltered repo to delay/avoid loading obsmarkers
1350 unfi = self._repo.unfiltered()
1350 unfi = self._repo.unfiltered()
1351 return [changectx(self._repo, unfi.changelog.rev(n), n) for n in p]
1351 return [changectx(self._repo, unfi.changelog.rev(n), n) for n in p]
1352
1352
1353 def _fileinfo(self, path):
1353 def _fileinfo(self, path):
1354 # populate __dict__['_manifest'] as workingctx has no _manifestdelta
1354 # populate __dict__['_manifest'] as workingctx has no _manifestdelta
1355 self._manifest
1355 self._manifest
1356 return super(workingctx, self)._fileinfo(path)
1356 return super(workingctx, self)._fileinfo(path)
1357
1357
1358 def filectx(self, path, filelog=None):
1358 def filectx(self, path, filelog=None):
1359 """get a file context from the working directory"""
1359 """get a file context from the working directory"""
1360 return workingfilectx(self._repo, path, workingctx=self,
1360 return workingfilectx(self._repo, path, workingctx=self,
1361 filelog=filelog)
1361 filelog=filelog)
1362
1362
1363 def dirty(self, missing=False, merge=True, branch=True):
1363 def dirty(self, missing=False, merge=True, branch=True):
1364 "check whether a working directory is modified"
1364 "check whether a working directory is modified"
1365 # check subrepos first
1365 # check subrepos first
1366 for s in sorted(self.substate):
1366 for s in sorted(self.substate):
1367 if self.sub(s).dirty(missing=missing):
1367 if self.sub(s).dirty(missing=missing):
1368 return True
1368 return True
1369 # check current working dir
1369 # check current working dir
1370 return ((merge and self.p2()) or
1370 return ((merge and self.p2()) or
1371 (branch and self.branch() != self.p1().branch()) or
1371 (branch and self.branch() != self.p1().branch()) or
1372 self.modified() or self.added() or self.removed() or
1372 self.modified() or self.added() or self.removed() or
1373 (missing and self.deleted()))
1373 (missing and self.deleted()))
1374
1374
1375 def add(self, list, prefix=""):
1375 def add(self, list, prefix=""):
1376 with self._repo.wlock():
1376 with self._repo.wlock():
1377 ui, ds = self._repo.ui, self._repo.dirstate
1377 ui, ds = self._repo.ui, self._repo.dirstate
1378 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1378 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1379 rejected = []
1379 rejected = []
1380 lstat = self._repo.wvfs.lstat
1380 lstat = self._repo.wvfs.lstat
1381 for f in list:
1381 for f in list:
1382 # ds.pathto() returns an absolute file when this is invoked from
1382 # ds.pathto() returns an absolute file when this is invoked from
1383 # the keyword extension. That gets flagged as non-portable on
1383 # the keyword extension. That gets flagged as non-portable on
1384 # Windows, since it contains the drive letter and colon.
1384 # Windows, since it contains the drive letter and colon.
1385 scmutil.checkportable(ui, os.path.join(prefix, f))
1385 scmutil.checkportable(ui, os.path.join(prefix, f))
1386 try:
1386 try:
1387 st = lstat(f)
1387 st = lstat(f)
1388 except OSError:
1388 except OSError:
1389 ui.warn(_("%s does not exist!\n") % uipath(f))
1389 ui.warn(_("%s does not exist!\n") % uipath(f))
1390 rejected.append(f)
1390 rejected.append(f)
1391 continue
1391 continue
1392 limit = ui.configbytes('ui', 'large-file-limit')
1392 limit = ui.configbytes('ui', 'large-file-limit')
1393 if limit != 0 and st.st_size > limit:
1393 if limit != 0 and st.st_size > limit:
1394 ui.warn(_("%s: up to %d MB of RAM may be required "
1394 ui.warn(_("%s: up to %d MB of RAM may be required "
1395 "to manage this file\n"
1395 "to manage this file\n"
1396 "(use 'hg revert %s' to cancel the "
1396 "(use 'hg revert %s' to cancel the "
1397 "pending addition)\n")
1397 "pending addition)\n")
1398 % (f, 3 * st.st_size // 1000000, uipath(f)))
1398 % (f, 3 * st.st_size // 1000000, uipath(f)))
1399 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1399 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1400 ui.warn(_("%s not added: only files and symlinks "
1400 ui.warn(_("%s not added: only files and symlinks "
1401 "supported currently\n") % uipath(f))
1401 "supported currently\n") % uipath(f))
1402 rejected.append(f)
1402 rejected.append(f)
1403 elif ds[f] in 'amn':
1403 elif ds[f] in 'amn':
1404 ui.warn(_("%s already tracked!\n") % uipath(f))
1404 ui.warn(_("%s already tracked!\n") % uipath(f))
1405 elif ds[f] == 'r':
1405 elif ds[f] == 'r':
1406 ds.normallookup(f)
1406 ds.normallookup(f)
1407 else:
1407 else:
1408 ds.add(f)
1408 ds.add(f)
1409 return rejected
1409 return rejected
1410
1410
1411 def forget(self, files, prefix=""):
1411 def forget(self, files, prefix=""):
1412 with self._repo.wlock():
1412 with self._repo.wlock():
1413 ds = self._repo.dirstate
1413 ds = self._repo.dirstate
1414 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1414 uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
1415 rejected = []
1415 rejected = []
1416 for f in files:
1416 for f in files:
1417 if f not in ds:
1417 if f not in ds:
1418 self._repo.ui.warn(_("%s not tracked!\n") % uipath(f))
1418 self._repo.ui.warn(_("%s not tracked!\n") % uipath(f))
1419 rejected.append(f)
1419 rejected.append(f)
1420 elif ds[f] != 'a':
1420 elif ds[f] != 'a':
1421 ds.remove(f)
1421 ds.remove(f)
1422 else:
1422 else:
1423 ds.drop(f)
1423 ds.drop(f)
1424 return rejected
1424 return rejected
1425
1425
1426 def copy(self, source, dest):
1426 def copy(self, source, dest):
1427 try:
1427 try:
1428 st = self._repo.wvfs.lstat(dest)
1428 st = self._repo.wvfs.lstat(dest)
1429 except OSError as err:
1429 except OSError as err:
1430 if err.errno != errno.ENOENT:
1430 if err.errno != errno.ENOENT:
1431 raise
1431 raise
1432 self._repo.ui.warn(_("%s does not exist!\n")
1432 self._repo.ui.warn(_("%s does not exist!\n")
1433 % self._repo.dirstate.pathto(dest))
1433 % self._repo.dirstate.pathto(dest))
1434 return
1434 return
1435 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1435 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
1436 self._repo.ui.warn(_("copy failed: %s is not a file or a "
1436 self._repo.ui.warn(_("copy failed: %s is not a file or a "
1437 "symbolic link\n")
1437 "symbolic link\n")
1438 % self._repo.dirstate.pathto(dest))
1438 % self._repo.dirstate.pathto(dest))
1439 else:
1439 else:
1440 with self._repo.wlock():
1440 with self._repo.wlock():
1441 ds = self._repo.dirstate
1441 ds = self._repo.dirstate
1442 if ds[dest] in '?':
1442 if ds[dest] in '?':
1443 ds.add(dest)
1443 ds.add(dest)
1444 elif ds[dest] in 'r':
1444 elif ds[dest] in 'r':
1445 ds.normallookup(dest)
1445 ds.normallookup(dest)
1446 ds.copy(source, dest)
1446 ds.copy(source, dest)
1447
1447
1448 def match(self, pats=None, include=None, exclude=None, default='glob',
1448 def match(self, pats=None, include=None, exclude=None, default='glob',
1449 listsubrepos=False, badfn=None):
1449 listsubrepos=False, badfn=None):
1450 r = self._repo
1450 r = self._repo
1451
1451
1452 # Only a case insensitive filesystem needs magic to translate user input
1452 # Only a case insensitive filesystem needs magic to translate user input
1453 # to actual case in the filesystem.
1453 # to actual case in the filesystem.
1454 icasefs = not util.fscasesensitive(r.root)
1454 icasefs = not util.fscasesensitive(r.root)
1455 return matchmod.match(r.root, r.getcwd(), pats, include, exclude,
1455 return matchmod.match(r.root, r.getcwd(), pats, include, exclude,
1456 default, auditor=r.auditor, ctx=self,
1456 default, auditor=r.auditor, ctx=self,
1457 listsubrepos=listsubrepos, badfn=badfn,
1457 listsubrepos=listsubrepos, badfn=badfn,
1458 icasefs=icasefs)
1458 icasefs=icasefs)
1459
1459
1460 def _filtersuspectsymlink(self, files):
1460 def _filtersuspectsymlink(self, files):
1461 if not files or self._repo.dirstate._checklink:
1461 if not files or self._repo.dirstate._checklink:
1462 return files
1462 return files
1463
1463
1464 # Symlink placeholders may get non-symlink-like contents
1464 # Symlink placeholders may get non-symlink-like contents
1465 # via user error or dereferencing by NFS or Samba servers,
1465 # via user error or dereferencing by NFS or Samba servers,
1466 # so we filter out any placeholders that don't look like a
1466 # so we filter out any placeholders that don't look like a
1467 # symlink
1467 # symlink
1468 sane = []
1468 sane = []
1469 for f in files:
1469 for f in files:
1470 if self.flags(f) == 'l':
1470 if self.flags(f) == 'l':
1471 d = self[f].data()
1471 d = self[f].data()
1472 if (d == '' or len(d) >= 1024 or '\n' in d
1472 if (d == '' or len(d) >= 1024 or '\n' in d
1473 or stringutil.binary(d)):
1473 or stringutil.binary(d)):
1474 self._repo.ui.debug('ignoring suspect symlink placeholder'
1474 self._repo.ui.debug('ignoring suspect symlink placeholder'
1475 ' "%s"\n' % f)
1475 ' "%s"\n' % f)
1476 continue
1476 continue
1477 sane.append(f)
1477 sane.append(f)
1478 return sane
1478 return sane
1479
1479
1480 def _checklookup(self, files):
1480 def _checklookup(self, files):
1481 # check for any possibly clean files
1481 # check for any possibly clean files
1482 if not files:
1482 if not files:
1483 return [], [], []
1483 return [], [], []
1484
1484
1485 modified = []
1485 modified = []
1486 deleted = []
1486 deleted = []
1487 fixup = []
1487 fixup = []
1488 pctx = self._parents[0]
1488 pctx = self._parents[0]
1489 # do a full compare of any files that might have changed
1489 # do a full compare of any files that might have changed
1490 for f in sorted(files):
1490 for f in sorted(files):
1491 try:
1491 try:
1492 # This will return True for a file that got replaced by a
1492 # This will return True for a file that got replaced by a
1493 # directory in the interim, but fixing that is pretty hard.
1493 # directory in the interim, but fixing that is pretty hard.
1494 if (f not in pctx or self.flags(f) != pctx.flags(f)
1494 if (f not in pctx or self.flags(f) != pctx.flags(f)
1495 or pctx[f].cmp(self[f])):
1495 or pctx[f].cmp(self[f])):
1496 modified.append(f)
1496 modified.append(f)
1497 else:
1497 else:
1498 fixup.append(f)
1498 fixup.append(f)
1499 except (IOError, OSError):
1499 except (IOError, OSError):
1500 # A file become inaccessible in between? Mark it as deleted,
1500 # A file become inaccessible in between? Mark it as deleted,
1501 # matching dirstate behavior (issue5584).
1501 # matching dirstate behavior (issue5584).
1502 # The dirstate has more complex behavior around whether a
1502 # The dirstate has more complex behavior around whether a
1503 # missing file matches a directory, etc, but we don't need to
1503 # missing file matches a directory, etc, but we don't need to
1504 # bother with that: if f has made it to this point, we're sure
1504 # bother with that: if f has made it to this point, we're sure
1505 # it's in the dirstate.
1505 # it's in the dirstate.
1506 deleted.append(f)
1506 deleted.append(f)
1507
1507
1508 return modified, deleted, fixup
1508 return modified, deleted, fixup
1509
1509
1510 def _poststatusfixup(self, status, fixup):
1510 def _poststatusfixup(self, status, fixup):
1511 """update dirstate for files that are actually clean"""
1511 """update dirstate for files that are actually clean"""
1512 poststatus = self._repo.postdsstatus()
1512 poststatus = self._repo.postdsstatus()
1513 if fixup or poststatus:
1513 if fixup or poststatus:
1514 try:
1514 try:
1515 oldid = self._repo.dirstate.identity()
1515 oldid = self._repo.dirstate.identity()
1516
1516
1517 # updating the dirstate is optional
1517 # updating the dirstate is optional
1518 # so we don't wait on the lock
1518 # so we don't wait on the lock
1519 # wlock can invalidate the dirstate, so cache normal _after_
1519 # wlock can invalidate the dirstate, so cache normal _after_
1520 # taking the lock
1520 # taking the lock
1521 with self._repo.wlock(False):
1521 with self._repo.wlock(False):
1522 if self._repo.dirstate.identity() == oldid:
1522 if self._repo.dirstate.identity() == oldid:
1523 if fixup:
1523 if fixup:
1524 normal = self._repo.dirstate.normal
1524 normal = self._repo.dirstate.normal
1525 for f in fixup:
1525 for f in fixup:
1526 normal(f)
1526 normal(f)
1527 # write changes out explicitly, because nesting
1527 # write changes out explicitly, because nesting
1528 # wlock at runtime may prevent 'wlock.release()'
1528 # wlock at runtime may prevent 'wlock.release()'
1529 # after this block from doing so for subsequent
1529 # after this block from doing so for subsequent
1530 # changing files
1530 # changing files
1531 tr = self._repo.currenttransaction()
1531 tr = self._repo.currenttransaction()
1532 self._repo.dirstate.write(tr)
1532 self._repo.dirstate.write(tr)
1533
1533
1534 if poststatus:
1534 if poststatus:
1535 for ps in poststatus:
1535 for ps in poststatus:
1536 ps(self, status)
1536 ps(self, status)
1537 else:
1537 else:
1538 # in this case, writing changes out breaks
1538 # in this case, writing changes out breaks
1539 # consistency, because .hg/dirstate was
1539 # consistency, because .hg/dirstate was
1540 # already changed simultaneously after last
1540 # already changed simultaneously after last
1541 # caching (see also issue5584 for detail)
1541 # caching (see also issue5584 for detail)
1542 self._repo.ui.debug('skip updating dirstate: '
1542 self._repo.ui.debug('skip updating dirstate: '
1543 'identity mismatch\n')
1543 'identity mismatch\n')
1544 except error.LockError:
1544 except error.LockError:
1545 pass
1545 pass
1546 finally:
1546 finally:
1547 # Even if the wlock couldn't be grabbed, clear out the list.
1547 # Even if the wlock couldn't be grabbed, clear out the list.
1548 self._repo.clearpostdsstatus()
1548 self._repo.clearpostdsstatus()
1549
1549
1550 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
1550 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
1551 '''Gets the status from the dirstate -- internal use only.'''
1551 '''Gets the status from the dirstate -- internal use only.'''
1552 subrepos = []
1552 subrepos = []
1553 if '.hgsub' in self:
1553 if '.hgsub' in self:
1554 subrepos = sorted(self.substate)
1554 subrepos = sorted(self.substate)
1555 cmp, s = self._repo.dirstate.status(match, subrepos, ignored=ignored,
1555 cmp, s = self._repo.dirstate.status(match, subrepos, ignored=ignored,
1556 clean=clean, unknown=unknown)
1556 clean=clean, unknown=unknown)
1557
1557
1558 # check for any possibly clean files
1558 # check for any possibly clean files
1559 fixup = []
1559 fixup = []
1560 if cmp:
1560 if cmp:
1561 modified2, deleted2, fixup = self._checklookup(cmp)
1561 modified2, deleted2, fixup = self._checklookup(cmp)
1562 s.modified.extend(modified2)
1562 s.modified.extend(modified2)
1563 s.deleted.extend(deleted2)
1563 s.deleted.extend(deleted2)
1564
1564
1565 if fixup and clean:
1565 if fixup and clean:
1566 s.clean.extend(fixup)
1566 s.clean.extend(fixup)
1567
1567
1568 self._poststatusfixup(s, fixup)
1568 self._poststatusfixup(s, fixup)
1569
1569
1570 if match.always():
1570 if match.always():
1571 # cache for performance
1571 # cache for performance
1572 if s.unknown or s.ignored or s.clean:
1572 if s.unknown or s.ignored or s.clean:
1573 # "_status" is cached with list*=False in the normal route
1573 # "_status" is cached with list*=False in the normal route
1574 self._status = scmutil.status(s.modified, s.added, s.removed,
1574 self._status = scmutil.status(s.modified, s.added, s.removed,
1575 s.deleted, [], [], [])
1575 s.deleted, [], [], [])
1576 else:
1576 else:
1577 self._status = s
1577 self._status = s
1578
1578
1579 return s
1579 return s
1580
1580
1581 @propertycache
1581 @propertycache
1582 def _manifest(self):
1582 def _manifest(self):
1583 """generate a manifest corresponding to the values in self._status
1583 """generate a manifest corresponding to the values in self._status
1584
1584
1585 This reuse the file nodeid from parent, but we use special node
1585 This reuse the file nodeid from parent, but we use special node
1586 identifiers for added and modified files. This is used by manifests
1586 identifiers for added and modified files. This is used by manifests
1587 merge to see that files are different and by update logic to avoid
1587 merge to see that files are different and by update logic to avoid
1588 deleting newly added files.
1588 deleting newly added files.
1589 """
1589 """
1590 return self._buildstatusmanifest(self._status)
1590 return self._buildstatusmanifest(self._status)
1591
1591
1592 def _buildstatusmanifest(self, status):
1592 def _buildstatusmanifest(self, status):
1593 """Builds a manifest that includes the given status results."""
1593 """Builds a manifest that includes the given status results."""
1594 parents = self.parents()
1594 parents = self.parents()
1595
1595
1596 man = parents[0].manifest().copy()
1596 man = parents[0].manifest().copy()
1597
1597
1598 ff = self._flagfunc
1598 ff = self._flagfunc
1599 for i, l in ((addednodeid, status.added),
1599 for i, l in ((addednodeid, status.added),
1600 (modifiednodeid, status.modified)):
1600 (modifiednodeid, status.modified)):
1601 for f in l:
1601 for f in l:
1602 man[f] = i
1602 man[f] = i
1603 try:
1603 try:
1604 man.setflag(f, ff(f))
1604 man.setflag(f, ff(f))
1605 except OSError:
1605 except OSError:
1606 pass
1606 pass
1607
1607
1608 for f in status.deleted + status.removed:
1608 for f in status.deleted + status.removed:
1609 if f in man:
1609 if f in man:
1610 del man[f]
1610 del man[f]
1611
1611
1612 return man
1612 return man
1613
1613
1614 def _buildstatus(self, other, s, match, listignored, listclean,
1614 def _buildstatus(self, other, s, match, listignored, listclean,
1615 listunknown):
1615 listunknown):
1616 """build a status with respect to another context
1616 """build a status with respect to another context
1617
1617
1618 This includes logic for maintaining the fast path of status when
1618 This includes logic for maintaining the fast path of status when
1619 comparing the working directory against its parent, which is to skip
1619 comparing the working directory against its parent, which is to skip
1620 building a new manifest if self (working directory) is not comparing
1620 building a new manifest if self (working directory) is not comparing
1621 against its parent (repo['.']).
1621 against its parent (repo['.']).
1622 """
1622 """
1623 s = self._dirstatestatus(match, listignored, listclean, listunknown)
1623 s = self._dirstatestatus(match, listignored, listclean, listunknown)
1624 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
1624 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
1625 # might have accidentally ended up with the entire contents of the file
1625 # might have accidentally ended up with the entire contents of the file
1626 # they are supposed to be linking to.
1626 # they are supposed to be linking to.
1627 s.modified[:] = self._filtersuspectsymlink(s.modified)
1627 s.modified[:] = self._filtersuspectsymlink(s.modified)
1628 if other != self._repo['.']:
1628 if other != self._repo['.']:
1629 s = super(workingctx, self)._buildstatus(other, s, match,
1629 s = super(workingctx, self)._buildstatus(other, s, match,
1630 listignored, listclean,
1630 listignored, listclean,
1631 listunknown)
1631 listunknown)
1632 return s
1632 return s
1633
1633
1634 def _matchstatus(self, other, match):
1634 def _matchstatus(self, other, match):
1635 """override the match method with a filter for directory patterns
1635 """override the match method with a filter for directory patterns
1636
1636
1637 We use inheritance to customize the match.bad method only in cases of
1637 We use inheritance to customize the match.bad method only in cases of
1638 workingctx since it belongs only to the working directory when
1638 workingctx since it belongs only to the working directory when
1639 comparing against the parent changeset.
1639 comparing against the parent changeset.
1640
1640
1641 If we aren't comparing against the working directory's parent, then we
1641 If we aren't comparing against the working directory's parent, then we
1642 just use the default match object sent to us.
1642 just use the default match object sent to us.
1643 """
1643 """
1644 if other != self._repo['.']:
1644 if other != self._repo['.']:
1645 def bad(f, msg):
1645 def bad(f, msg):
1646 # 'f' may be a directory pattern from 'match.files()',
1646 # 'f' may be a directory pattern from 'match.files()',
1647 # so 'f not in ctx1' is not enough
1647 # so 'f not in ctx1' is not enough
1648 if f not in other and not other.hasdir(f):
1648 if f not in other and not other.hasdir(f):
1649 self._repo.ui.warn('%s: %s\n' %
1649 self._repo.ui.warn('%s: %s\n' %
1650 (self._repo.dirstate.pathto(f), msg))
1650 (self._repo.dirstate.pathto(f), msg))
1651 match.bad = bad
1651 match.bad = bad
1652 return match
1652 return match
1653
1653
1654 def markcommitted(self, node):
1654 def markcommitted(self, node):
1655 super(workingctx, self).markcommitted(node)
1655 super(workingctx, self).markcommitted(node)
1656
1656
1657 sparse.aftercommit(self._repo, node)
1657 sparse.aftercommit(self._repo, node)
1658
1658
1659 class committablefilectx(basefilectx):
1659 class committablefilectx(basefilectx):
1660 """A committablefilectx provides common functionality for a file context
1660 """A committablefilectx provides common functionality for a file context
1661 that wants the ability to commit, e.g. workingfilectx or memfilectx."""
1661 that wants the ability to commit, e.g. workingfilectx or memfilectx."""
1662 def __init__(self, repo, path, filelog=None, ctx=None):
1662 def __init__(self, repo, path, filelog=None, ctx=None):
1663 self._repo = repo
1663 self._repo = repo
1664 self._path = path
1664 self._path = path
1665 self._changeid = None
1665 self._changeid = None
1666 self._filerev = self._filenode = None
1666 self._filerev = self._filenode = None
1667
1667
1668 if filelog is not None:
1668 if filelog is not None:
1669 self._filelog = filelog
1669 self._filelog = filelog
1670 if ctx:
1670 if ctx:
1671 self._changectx = ctx
1671 self._changectx = ctx
1672
1672
1673 def __nonzero__(self):
1673 def __nonzero__(self):
1674 return True
1674 return True
1675
1675
1676 __bool__ = __nonzero__
1676 __bool__ = __nonzero__
1677
1677
1678 def linkrev(self):
1678 def linkrev(self):
1679 # linked to self._changectx no matter if file is modified or not
1679 # linked to self._changectx no matter if file is modified or not
1680 return self.rev()
1680 return self.rev()
1681
1681
1682 def renamed(self):
1682 def renamed(self):
1683 path = self.copysource()
1683 path = self.copysource()
1684 if not path:
1684 if not path:
1685 return None
1685 return None
1686 return path, self._changectx._parents[0]._manifest.get(path, nullid)
1686 return path, self._changectx._parents[0]._manifest.get(path, nullid)
1687
1687
1688 def parents(self):
1688 def parents(self):
1689 '''return parent filectxs, following copies if necessary'''
1689 '''return parent filectxs, following copies if necessary'''
1690 def filenode(ctx, path):
1690 def filenode(ctx, path):
1691 return ctx._manifest.get(path, nullid)
1691 return ctx._manifest.get(path, nullid)
1692
1692
1693 path = self._path
1693 path = self._path
1694 fl = self._filelog
1694 fl = self._filelog
1695 pcl = self._changectx._parents
1695 pcl = self._changectx._parents
1696 renamed = self.renamed()
1696 renamed = self.renamed()
1697
1697
1698 if renamed:
1698 if renamed:
1699 pl = [renamed + (None,)]
1699 pl = [renamed + (None,)]
1700 else:
1700 else:
1701 pl = [(path, filenode(pcl[0], path), fl)]
1701 pl = [(path, filenode(pcl[0], path), fl)]
1702
1702
1703 for pc in pcl[1:]:
1703 for pc in pcl[1:]:
1704 pl.append((path, filenode(pc, path), fl))
1704 pl.append((path, filenode(pc, path), fl))
1705
1705
1706 return [self._parentfilectx(p, fileid=n, filelog=l)
1706 return [self._parentfilectx(p, fileid=n, filelog=l)
1707 for p, n, l in pl if n != nullid]
1707 for p, n, l in pl if n != nullid]
1708
1708
1709 def children(self):
1709 def children(self):
1710 return []
1710 return []
1711
1711
1712 class workingfilectx(committablefilectx):
1712 class workingfilectx(committablefilectx):
1713 """A workingfilectx object makes access to data related to a particular
1713 """A workingfilectx object makes access to data related to a particular
1714 file in the working directory convenient."""
1714 file in the working directory convenient."""
1715 def __init__(self, repo, path, filelog=None, workingctx=None):
1715 def __init__(self, repo, path, filelog=None, workingctx=None):
1716 super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
1716 super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
1717
1717
1718 @propertycache
1718 @propertycache
1719 def _changectx(self):
1719 def _changectx(self):
1720 return workingctx(self._repo)
1720 return workingctx(self._repo)
1721
1721
1722 def data(self):
1722 def data(self):
1723 return self._repo.wread(self._path)
1723 return self._repo.wread(self._path)
1724 def copysource(self):
1724 def copysource(self):
1725 return self._repo.dirstate.copied(self._path)
1725 return self._repo.dirstate.copied(self._path)
1726
1726
1727 def size(self):
1727 def size(self):
1728 return self._repo.wvfs.lstat(self._path).st_size
1728 return self._repo.wvfs.lstat(self._path).st_size
1729 def date(self):
1729 def date(self):
1730 t, tz = self._changectx.date()
1730 t, tz = self._changectx.date()
1731 try:
1731 try:
1732 return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz)
1732 return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz)
1733 except OSError as err:
1733 except OSError as err:
1734 if err.errno != errno.ENOENT:
1734 if err.errno != errno.ENOENT:
1735 raise
1735 raise
1736 return (t, tz)
1736 return (t, tz)
1737
1737
1738 def exists(self):
1738 def exists(self):
1739 return self._repo.wvfs.exists(self._path)
1739 return self._repo.wvfs.exists(self._path)
1740
1740
1741 def lexists(self):
1741 def lexists(self):
1742 return self._repo.wvfs.lexists(self._path)
1742 return self._repo.wvfs.lexists(self._path)
1743
1743
1744 def audit(self):
1744 def audit(self):
1745 return self._repo.wvfs.audit(self._path)
1745 return self._repo.wvfs.audit(self._path)
1746
1746
1747 def cmp(self, fctx):
1747 def cmp(self, fctx):
1748 """compare with other file context
1748 """compare with other file context
1749
1749
1750 returns True if different than fctx.
1750 returns True if different than fctx.
1751 """
1751 """
1752 # fctx should be a filectx (not a workingfilectx)
1752 # fctx should be a filectx (not a workingfilectx)
1753 # invert comparison to reuse the same code path
1753 # invert comparison to reuse the same code path
1754 return fctx.cmp(self)
1754 return fctx.cmp(self)
1755
1755
1756 def remove(self, ignoremissing=False):
1756 def remove(self, ignoremissing=False):
1757 """wraps unlink for a repo's working directory"""
1757 """wraps unlink for a repo's working directory"""
1758 rmdir = self._repo.ui.configbool('experimental', 'removeemptydirs')
1758 rmdir = self._repo.ui.configbool('experimental', 'removeemptydirs')
1759 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing,
1759 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing,
1760 rmdir=rmdir)
1760 rmdir=rmdir)
1761
1761
1762 def write(self, data, flags, backgroundclose=False, **kwargs):
1762 def write(self, data, flags, backgroundclose=False, **kwargs):
1763 """wraps repo.wwrite"""
1763 """wraps repo.wwrite"""
1764 self._repo.wwrite(self._path, data, flags,
1764 self._repo.wwrite(self._path, data, flags,
1765 backgroundclose=backgroundclose,
1765 backgroundclose=backgroundclose,
1766 **kwargs)
1766 **kwargs)
1767
1767
1768 def markcopied(self, src):
1768 def markcopied(self, src):
1769 """marks this file a copy of `src`"""
1769 """marks this file a copy of `src`"""
1770 if self._repo.dirstate[self._path] in "nma":
1770 if self._repo.dirstate[self._path] in "nma":
1771 self._repo.dirstate.copy(src, self._path)
1771 self._repo.dirstate.copy(src, self._path)
1772
1772
1773 def clearunknown(self):
1773 def clearunknown(self):
1774 """Removes conflicting items in the working directory so that
1774 """Removes conflicting items in the working directory so that
1775 ``write()`` can be called successfully.
1775 ``write()`` can be called successfully.
1776 """
1776 """
1777 wvfs = self._repo.wvfs
1777 wvfs = self._repo.wvfs
1778 f = self._path
1778 f = self._path
1779 wvfs.audit(f)
1779 wvfs.audit(f)
1780 if self._repo.ui.configbool('experimental', 'merge.checkpathconflicts'):
1780 if self._repo.ui.configbool('experimental', 'merge.checkpathconflicts'):
1781 # remove files under the directory as they should already be
1781 # remove files under the directory as they should already be
1782 # warned and backed up
1782 # warned and backed up
1783 if wvfs.isdir(f) and not wvfs.islink(f):
1783 if wvfs.isdir(f) and not wvfs.islink(f):
1784 wvfs.rmtree(f, forcibly=True)
1784 wvfs.rmtree(f, forcibly=True)
1785 for p in reversed(list(util.finddirs(f))):
1785 for p in reversed(list(util.finddirs(f))):
1786 if wvfs.isfileorlink(p):
1786 if wvfs.isfileorlink(p):
1787 wvfs.unlink(p)
1787 wvfs.unlink(p)
1788 break
1788 break
1789 else:
1789 else:
1790 # don't remove files if path conflicts are not processed
1790 # don't remove files if path conflicts are not processed
1791 if wvfs.isdir(f) and not wvfs.islink(f):
1791 if wvfs.isdir(f) and not wvfs.islink(f):
1792 wvfs.removedirs(f)
1792 wvfs.removedirs(f)
1793
1793
1794 def setflags(self, l, x):
1794 def setflags(self, l, x):
1795 self._repo.wvfs.setflags(self._path, l, x)
1795 self._repo.wvfs.setflags(self._path, l, x)
1796
1796
1797 class overlayworkingctx(committablectx):
1797 class overlayworkingctx(committablectx):
1798 """Wraps another mutable context with a write-back cache that can be
1798 """Wraps another mutable context with a write-back cache that can be
1799 converted into a commit context.
1799 converted into a commit context.
1800
1800
1801 self._cache[path] maps to a dict with keys: {
1801 self._cache[path] maps to a dict with keys: {
1802 'exists': bool?
1802 'exists': bool?
1803 'date': date?
1803 'date': date?
1804 'data': str?
1804 'data': str?
1805 'flags': str?
1805 'flags': str?
1806 'copied': str? (path or None)
1806 'copied': str? (path or None)
1807 }
1807 }
1808 If `exists` is True, `flags` must be non-None and 'date' is non-None. If it
1808 If `exists` is True, `flags` must be non-None and 'date' is non-None. If it
1809 is `False`, the file was deleted.
1809 is `False`, the file was deleted.
1810 """
1810 """
1811
1811
1812 def __init__(self, repo):
1812 def __init__(self, repo):
1813 super(overlayworkingctx, self).__init__(repo)
1813 super(overlayworkingctx, self).__init__(repo)
1814 self.clean()
1814 self.clean()
1815
1815
1816 def setbase(self, wrappedctx):
1816 def setbase(self, wrappedctx):
1817 self._wrappedctx = wrappedctx
1817 self._wrappedctx = wrappedctx
1818 self._parents = [wrappedctx]
1818 self._parents = [wrappedctx]
1819 # Drop old manifest cache as it is now out of date.
1819 # Drop old manifest cache as it is now out of date.
1820 # This is necessary when, e.g., rebasing several nodes with one
1820 # This is necessary when, e.g., rebasing several nodes with one
1821 # ``overlayworkingctx`` (e.g. with --collapse).
1821 # ``overlayworkingctx`` (e.g. with --collapse).
1822 util.clearcachedproperty(self, '_manifest')
1822 util.clearcachedproperty(self, '_manifest')
1823
1823
1824 def data(self, path):
1824 def data(self, path):
1825 if self.isdirty(path):
1825 if self.isdirty(path):
1826 if self._cache[path]['exists']:
1826 if self._cache[path]['exists']:
1827 if self._cache[path]['data']:
1827 if self._cache[path]['data'] is not None:
1828 return self._cache[path]['data']
1828 return self._cache[path]['data']
1829 else:
1829 else:
1830 # Must fallback here, too, because we only set flags.
1830 # Must fallback here, too, because we only set flags.
1831 return self._wrappedctx[path].data()
1831 return self._wrappedctx[path].data()
1832 else:
1832 else:
1833 raise error.ProgrammingError("No such file or directory: %s" %
1833 raise error.ProgrammingError("No such file or directory: %s" %
1834 path)
1834 path)
1835 else:
1835 else:
1836 return self._wrappedctx[path].data()
1836 return self._wrappedctx[path].data()
1837
1837
1838 @propertycache
1838 @propertycache
1839 def _manifest(self):
1839 def _manifest(self):
1840 parents = self.parents()
1840 parents = self.parents()
1841 man = parents[0].manifest().copy()
1841 man = parents[0].manifest().copy()
1842
1842
1843 flag = self._flagfunc
1843 flag = self._flagfunc
1844 for path in self.added():
1844 for path in self.added():
1845 man[path] = addednodeid
1845 man[path] = addednodeid
1846 man.setflag(path, flag(path))
1846 man.setflag(path, flag(path))
1847 for path in self.modified():
1847 for path in self.modified():
1848 man[path] = modifiednodeid
1848 man[path] = modifiednodeid
1849 man.setflag(path, flag(path))
1849 man.setflag(path, flag(path))
1850 for path in self.removed():
1850 for path in self.removed():
1851 del man[path]
1851 del man[path]
1852 return man
1852 return man
1853
1853
1854 @propertycache
1854 @propertycache
1855 def _flagfunc(self):
1855 def _flagfunc(self):
1856 def f(path):
1856 def f(path):
1857 return self._cache[path]['flags']
1857 return self._cache[path]['flags']
1858 return f
1858 return f
1859
1859
1860 def files(self):
1860 def files(self):
1861 return sorted(self.added() + self.modified() + self.removed())
1861 return sorted(self.added() + self.modified() + self.removed())
1862
1862
1863 def modified(self):
1863 def modified(self):
1864 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
1864 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
1865 self._existsinparent(f)]
1865 self._existsinparent(f)]
1866
1866
1867 def added(self):
1867 def added(self):
1868 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
1868 return [f for f in self._cache.keys() if self._cache[f]['exists'] and
1869 not self._existsinparent(f)]
1869 not self._existsinparent(f)]
1870
1870
1871 def removed(self):
1871 def removed(self):
1872 return [f for f in self._cache.keys() if
1872 return [f for f in self._cache.keys() if
1873 not self._cache[f]['exists'] and self._existsinparent(f)]
1873 not self._cache[f]['exists'] and self._existsinparent(f)]
1874
1874
1875 def p1copies(self):
1875 def p1copies(self):
1876 copies = self._repo._wrappedctx.p1copies().copy()
1876 copies = self._repo._wrappedctx.p1copies().copy()
1877 narrowmatch = self._repo.narrowmatch()
1877 narrowmatch = self._repo.narrowmatch()
1878 for f in self._cache.keys():
1878 for f in self._cache.keys():
1879 if not narrowmatch(f):
1879 if not narrowmatch(f):
1880 continue
1880 continue
1881 copies.pop(f, None) # delete if it exists
1881 copies.pop(f, None) # delete if it exists
1882 source = self._cache[f]['copied']
1882 source = self._cache[f]['copied']
1883 if source:
1883 if source:
1884 copies[f] = source
1884 copies[f] = source
1885 return copies
1885 return copies
1886
1886
1887 def p2copies(self):
1887 def p2copies(self):
1888 copies = self._repo._wrappedctx.p2copies().copy()
1888 copies = self._repo._wrappedctx.p2copies().copy()
1889 narrowmatch = self._repo.narrowmatch()
1889 narrowmatch = self._repo.narrowmatch()
1890 for f in self._cache.keys():
1890 for f in self._cache.keys():
1891 if not narrowmatch(f):
1891 if not narrowmatch(f):
1892 continue
1892 continue
1893 copies.pop(f, None) # delete if it exists
1893 copies.pop(f, None) # delete if it exists
1894 source = self._cache[f]['copied']
1894 source = self._cache[f]['copied']
1895 if source:
1895 if source:
1896 copies[f] = source
1896 copies[f] = source
1897 return copies
1897 return copies
1898
1898
1899 def isinmemory(self):
1899 def isinmemory(self):
1900 return True
1900 return True
1901
1901
1902 def filedate(self, path):
1902 def filedate(self, path):
1903 if self.isdirty(path):
1903 if self.isdirty(path):
1904 return self._cache[path]['date']
1904 return self._cache[path]['date']
1905 else:
1905 else:
1906 return self._wrappedctx[path].date()
1906 return self._wrappedctx[path].date()
1907
1907
1908 def markcopied(self, path, origin):
1908 def markcopied(self, path, origin):
1909 self._markdirty(path, exists=True, date=self.filedate(path),
1909 self._markdirty(path, exists=True, date=self.filedate(path),
1910 flags=self.flags(path), copied=origin)
1910 flags=self.flags(path), copied=origin)
1911
1911
1912 def copydata(self, path):
1912 def copydata(self, path):
1913 if self.isdirty(path):
1913 if self.isdirty(path):
1914 return self._cache[path]['copied']
1914 return self._cache[path]['copied']
1915 else:
1915 else:
1916 raise error.ProgrammingError('copydata() called on clean context')
1916 raise error.ProgrammingError('copydata() called on clean context')
1917
1917
1918 def flags(self, path):
1918 def flags(self, path):
1919 if self.isdirty(path):
1919 if self.isdirty(path):
1920 if self._cache[path]['exists']:
1920 if self._cache[path]['exists']:
1921 return self._cache[path]['flags']
1921 return self._cache[path]['flags']
1922 else:
1922 else:
1923 raise error.ProgrammingError("No such file or directory: %s" %
1923 raise error.ProgrammingError("No such file or directory: %s" %
1924 self._path)
1924 self._path)
1925 else:
1925 else:
1926 return self._wrappedctx[path].flags()
1926 return self._wrappedctx[path].flags()
1927
1927
1928 def __contains__(self, key):
1928 def __contains__(self, key):
1929 if key in self._cache:
1929 if key in self._cache:
1930 return self._cache[key]['exists']
1930 return self._cache[key]['exists']
1931 return key in self.p1()
1931 return key in self.p1()
1932
1932
1933 def _existsinparent(self, path):
1933 def _existsinparent(self, path):
1934 try:
1934 try:
1935 # ``commitctx` raises a ``ManifestLookupError`` if a path does not
1935 # ``commitctx` raises a ``ManifestLookupError`` if a path does not
1936 # exist, unlike ``workingctx``, which returns a ``workingfilectx``
1936 # exist, unlike ``workingctx``, which returns a ``workingfilectx``
1937 # with an ``exists()`` function.
1937 # with an ``exists()`` function.
1938 self._wrappedctx[path]
1938 self._wrappedctx[path]
1939 return True
1939 return True
1940 except error.ManifestLookupError:
1940 except error.ManifestLookupError:
1941 return False
1941 return False
1942
1942
1943 def _auditconflicts(self, path):
1943 def _auditconflicts(self, path):
1944 """Replicates conflict checks done by wvfs.write().
1944 """Replicates conflict checks done by wvfs.write().
1945
1945
1946 Since we never write to the filesystem and never call `applyupdates` in
1946 Since we never write to the filesystem and never call `applyupdates` in
1947 IMM, we'll never check that a path is actually writable -- e.g., because
1947 IMM, we'll never check that a path is actually writable -- e.g., because
1948 it adds `a/foo`, but `a` is actually a file in the other commit.
1948 it adds `a/foo`, but `a` is actually a file in the other commit.
1949 """
1949 """
1950 def fail(path, component):
1950 def fail(path, component):
1951 # p1() is the base and we're receiving "writes" for p2()'s
1951 # p1() is the base and we're receiving "writes" for p2()'s
1952 # files.
1952 # files.
1953 if 'l' in self.p1()[component].flags():
1953 if 'l' in self.p1()[component].flags():
1954 raise error.Abort("error: %s conflicts with symlink %s "
1954 raise error.Abort("error: %s conflicts with symlink %s "
1955 "in %d." % (path, component,
1955 "in %d." % (path, component,
1956 self.p1().rev()))
1956 self.p1().rev()))
1957 else:
1957 else:
1958 raise error.Abort("error: '%s' conflicts with file '%s' in "
1958 raise error.Abort("error: '%s' conflicts with file '%s' in "
1959 "%d." % (path, component,
1959 "%d." % (path, component,
1960 self.p1().rev()))
1960 self.p1().rev()))
1961
1961
1962 # Test that each new directory to be created to write this path from p2
1962 # Test that each new directory to be created to write this path from p2
1963 # is not a file in p1.
1963 # is not a file in p1.
1964 components = path.split('/')
1964 components = path.split('/')
1965 for i in pycompat.xrange(len(components)):
1965 for i in pycompat.xrange(len(components)):
1966 component = "/".join(components[0:i])
1966 component = "/".join(components[0:i])
1967 if component in self:
1967 if component in self:
1968 fail(path, component)
1968 fail(path, component)
1969
1969
1970 # Test the other direction -- that this path from p2 isn't a directory
1970 # Test the other direction -- that this path from p2 isn't a directory
1971 # in p1 (test that p1 doesn't have any paths matching `path/*`).
1971 # in p1 (test that p1 doesn't have any paths matching `path/*`).
1972 match = self.match([path], default=b'path')
1972 match = self.match([path], default=b'path')
1973 matches = self.p1().manifest().matches(match)
1973 matches = self.p1().manifest().matches(match)
1974 mfiles = matches.keys()
1974 mfiles = matches.keys()
1975 if len(mfiles) > 0:
1975 if len(mfiles) > 0:
1976 if len(mfiles) == 1 and mfiles[0] == path:
1976 if len(mfiles) == 1 and mfiles[0] == path:
1977 return
1977 return
1978 # omit the files which are deleted in current IMM wctx
1978 # omit the files which are deleted in current IMM wctx
1979 mfiles = [m for m in mfiles if m in self]
1979 mfiles = [m for m in mfiles if m in self]
1980 if not mfiles:
1980 if not mfiles:
1981 return
1981 return
1982 raise error.Abort("error: file '%s' cannot be written because "
1982 raise error.Abort("error: file '%s' cannot be written because "
1983 " '%s/' is a directory in %s (containing %d "
1983 " '%s/' is a directory in %s (containing %d "
1984 "entries: %s)"
1984 "entries: %s)"
1985 % (path, path, self.p1(), len(mfiles),
1985 % (path, path, self.p1(), len(mfiles),
1986 ', '.join(mfiles)))
1986 ', '.join(mfiles)))
1987
1987
1988 def write(self, path, data, flags='', **kwargs):
1988 def write(self, path, data, flags='', **kwargs):
1989 if data is None:
1989 if data is None:
1990 raise error.ProgrammingError("data must be non-None")
1990 raise error.ProgrammingError("data must be non-None")
1991 self._auditconflicts(path)
1991 self._auditconflicts(path)
1992 self._markdirty(path, exists=True, data=data, date=dateutil.makedate(),
1992 self._markdirty(path, exists=True, data=data, date=dateutil.makedate(),
1993 flags=flags)
1993 flags=flags)
1994
1994
1995 def setflags(self, path, l, x):
1995 def setflags(self, path, l, x):
1996 flag = ''
1996 flag = ''
1997 if l:
1997 if l:
1998 flag = 'l'
1998 flag = 'l'
1999 elif x:
1999 elif x:
2000 flag = 'x'
2000 flag = 'x'
2001 self._markdirty(path, exists=True, date=dateutil.makedate(),
2001 self._markdirty(path, exists=True, date=dateutil.makedate(),
2002 flags=flag)
2002 flags=flag)
2003
2003
2004 def remove(self, path):
2004 def remove(self, path):
2005 self._markdirty(path, exists=False)
2005 self._markdirty(path, exists=False)
2006
2006
2007 def exists(self, path):
2007 def exists(self, path):
2008 """exists behaves like `lexists`, but needs to follow symlinks and
2008 """exists behaves like `lexists`, but needs to follow symlinks and
2009 return False if they are broken.
2009 return False if they are broken.
2010 """
2010 """
2011 if self.isdirty(path):
2011 if self.isdirty(path):
2012 # If this path exists and is a symlink, "follow" it by calling
2012 # If this path exists and is a symlink, "follow" it by calling
2013 # exists on the destination path.
2013 # exists on the destination path.
2014 if (self._cache[path]['exists'] and
2014 if (self._cache[path]['exists'] and
2015 'l' in self._cache[path]['flags']):
2015 'l' in self._cache[path]['flags']):
2016 return self.exists(self._cache[path]['data'].strip())
2016 return self.exists(self._cache[path]['data'].strip())
2017 else:
2017 else:
2018 return self._cache[path]['exists']
2018 return self._cache[path]['exists']
2019
2019
2020 return self._existsinparent(path)
2020 return self._existsinparent(path)
2021
2021
2022 def lexists(self, path):
2022 def lexists(self, path):
2023 """lexists returns True if the path exists"""
2023 """lexists returns True if the path exists"""
2024 if self.isdirty(path):
2024 if self.isdirty(path):
2025 return self._cache[path]['exists']
2025 return self._cache[path]['exists']
2026
2026
2027 return self._existsinparent(path)
2027 return self._existsinparent(path)
2028
2028
2029 def size(self, path):
2029 def size(self, path):
2030 if self.isdirty(path):
2030 if self.isdirty(path):
2031 if self._cache[path]['exists']:
2031 if self._cache[path]['exists']:
2032 return len(self._cache[path]['data'])
2032 return len(self._cache[path]['data'])
2033 else:
2033 else:
2034 raise error.ProgrammingError("No such file or directory: %s" %
2034 raise error.ProgrammingError("No such file or directory: %s" %
2035 self._path)
2035 self._path)
2036 return self._wrappedctx[path].size()
2036 return self._wrappedctx[path].size()
2037
2037
2038 def tomemctx(self, text, branch=None, extra=None, date=None, parents=None,
2038 def tomemctx(self, text, branch=None, extra=None, date=None, parents=None,
2039 user=None, editor=None):
2039 user=None, editor=None):
2040 """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be
2040 """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be
2041 committed.
2041 committed.
2042
2042
2043 ``text`` is the commit message.
2043 ``text`` is the commit message.
2044 ``parents`` (optional) are rev numbers.
2044 ``parents`` (optional) are rev numbers.
2045 """
2045 """
2046 # Default parents to the wrapped contexts' if not passed.
2046 # Default parents to the wrapped contexts' if not passed.
2047 if parents is None:
2047 if parents is None:
2048 parents = self._wrappedctx.parents()
2048 parents = self._wrappedctx.parents()
2049 if len(parents) == 1:
2049 if len(parents) == 1:
2050 parents = (parents[0], None)
2050 parents = (parents[0], None)
2051
2051
2052 # ``parents`` is passed as rev numbers; convert to ``commitctxs``.
2052 # ``parents`` is passed as rev numbers; convert to ``commitctxs``.
2053 if parents[1] is None:
2053 if parents[1] is None:
2054 parents = (self._repo[parents[0]], None)
2054 parents = (self._repo[parents[0]], None)
2055 else:
2055 else:
2056 parents = (self._repo[parents[0]], self._repo[parents[1]])
2056 parents = (self._repo[parents[0]], self._repo[parents[1]])
2057
2057
2058 files = self._cache.keys()
2058 files = self._cache.keys()
2059 def getfile(repo, memctx, path):
2059 def getfile(repo, memctx, path):
2060 if self._cache[path]['exists']:
2060 if self._cache[path]['exists']:
2061 return memfilectx(repo, memctx, path,
2061 return memfilectx(repo, memctx, path,
2062 self._cache[path]['data'],
2062 self._cache[path]['data'],
2063 'l' in self._cache[path]['flags'],
2063 'l' in self._cache[path]['flags'],
2064 'x' in self._cache[path]['flags'],
2064 'x' in self._cache[path]['flags'],
2065 self._cache[path]['copied'])
2065 self._cache[path]['copied'])
2066 else:
2066 else:
2067 # Returning None, but including the path in `files`, is
2067 # Returning None, but including the path in `files`, is
2068 # necessary for memctx to register a deletion.
2068 # necessary for memctx to register a deletion.
2069 return None
2069 return None
2070 return memctx(self._repo, parents, text, files, getfile, date=date,
2070 return memctx(self._repo, parents, text, files, getfile, date=date,
2071 extra=extra, user=user, branch=branch, editor=editor)
2071 extra=extra, user=user, branch=branch, editor=editor)
2072
2072
2073 def isdirty(self, path):
2073 def isdirty(self, path):
2074 return path in self._cache
2074 return path in self._cache
2075
2075
2076 def isempty(self):
2076 def isempty(self):
2077 # We need to discard any keys that are actually clean before the empty
2077 # We need to discard any keys that are actually clean before the empty
2078 # commit check.
2078 # commit check.
2079 self._compact()
2079 self._compact()
2080 return len(self._cache) == 0
2080 return len(self._cache) == 0
2081
2081
2082 def clean(self):
2082 def clean(self):
2083 self._cache = {}
2083 self._cache = {}
2084
2084
2085 def _compact(self):
2085 def _compact(self):
2086 """Removes keys from the cache that are actually clean, by comparing
2086 """Removes keys from the cache that are actually clean, by comparing
2087 them with the underlying context.
2087 them with the underlying context.
2088
2088
2089 This can occur during the merge process, e.g. by passing --tool :local
2089 This can occur during the merge process, e.g. by passing --tool :local
2090 to resolve a conflict.
2090 to resolve a conflict.
2091 """
2091 """
2092 keys = []
2092 keys = []
2093 # This won't be perfect, but can help performance significantly when
2093 # This won't be perfect, but can help performance significantly when
2094 # using things like remotefilelog.
2094 # using things like remotefilelog.
2095 scmutil.prefetchfiles(
2095 scmutil.prefetchfiles(
2096 self.repo(), [self.p1().rev()],
2096 self.repo(), [self.p1().rev()],
2097 scmutil.matchfiles(self.repo(), self._cache.keys()))
2097 scmutil.matchfiles(self.repo(), self._cache.keys()))
2098
2098
2099 for path in self._cache.keys():
2099 for path in self._cache.keys():
2100 cache = self._cache[path]
2100 cache = self._cache[path]
2101 try:
2101 try:
2102 underlying = self._wrappedctx[path]
2102 underlying = self._wrappedctx[path]
2103 if (underlying.data() == cache['data'] and
2103 if (underlying.data() == cache['data'] and
2104 underlying.flags() == cache['flags']):
2104 underlying.flags() == cache['flags']):
2105 keys.append(path)
2105 keys.append(path)
2106 except error.ManifestLookupError:
2106 except error.ManifestLookupError:
2107 # Path not in the underlying manifest (created).
2107 # Path not in the underlying manifest (created).
2108 continue
2108 continue
2109
2109
2110 for path in keys:
2110 for path in keys:
2111 del self._cache[path]
2111 del self._cache[path]
2112 return keys
2112 return keys
2113
2113
2114 def _markdirty(self, path, exists, data=None, date=None, flags='',
2114 def _markdirty(self, path, exists, data=None, date=None, flags='',
2115 copied=None):
2115 copied=None):
2116 # data not provided, let's see if we already have some; if not, let's
2116 # data not provided, let's see if we already have some; if not, let's
2117 # grab it from our underlying context, so that we always have data if
2117 # grab it from our underlying context, so that we always have data if
2118 # the file is marked as existing.
2118 # the file is marked as existing.
2119 if exists and data is None:
2119 if exists and data is None:
2120 oldentry = self._cache.get(path) or {}
2120 oldentry = self._cache.get(path) or {}
2121 data = oldentry.get('data') or self._wrappedctx[path].data()
2121 data = oldentry.get('data') or self._wrappedctx[path].data()
2122
2122
2123 self._cache[path] = {
2123 self._cache[path] = {
2124 'exists': exists,
2124 'exists': exists,
2125 'data': data,
2125 'data': data,
2126 'date': date,
2126 'date': date,
2127 'flags': flags,
2127 'flags': flags,
2128 'copied': copied,
2128 'copied': copied,
2129 }
2129 }
2130
2130
2131 def filectx(self, path, filelog=None):
2131 def filectx(self, path, filelog=None):
2132 return overlayworkingfilectx(self._repo, path, parent=self,
2132 return overlayworkingfilectx(self._repo, path, parent=self,
2133 filelog=filelog)
2133 filelog=filelog)
2134
2134
2135 class overlayworkingfilectx(committablefilectx):
2135 class overlayworkingfilectx(committablefilectx):
2136 """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory
2136 """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory
2137 cache, which can be flushed through later by calling ``flush()``."""
2137 cache, which can be flushed through later by calling ``flush()``."""
2138
2138
2139 def __init__(self, repo, path, filelog=None, parent=None):
2139 def __init__(self, repo, path, filelog=None, parent=None):
2140 super(overlayworkingfilectx, self).__init__(repo, path, filelog,
2140 super(overlayworkingfilectx, self).__init__(repo, path, filelog,
2141 parent)
2141 parent)
2142 self._repo = repo
2142 self._repo = repo
2143 self._parent = parent
2143 self._parent = parent
2144 self._path = path
2144 self._path = path
2145
2145
2146 def cmp(self, fctx):
2146 def cmp(self, fctx):
2147 return self.data() != fctx.data()
2147 return self.data() != fctx.data()
2148
2148
2149 def changectx(self):
2149 def changectx(self):
2150 return self._parent
2150 return self._parent
2151
2151
2152 def data(self):
2152 def data(self):
2153 return self._parent.data(self._path)
2153 return self._parent.data(self._path)
2154
2154
2155 def date(self):
2155 def date(self):
2156 return self._parent.filedate(self._path)
2156 return self._parent.filedate(self._path)
2157
2157
2158 def exists(self):
2158 def exists(self):
2159 return self.lexists()
2159 return self.lexists()
2160
2160
2161 def lexists(self):
2161 def lexists(self):
2162 return self._parent.exists(self._path)
2162 return self._parent.exists(self._path)
2163
2163
2164 def copysource(self):
2164 def copysource(self):
2165 return self._parent.copydata(self._path)
2165 return self._parent.copydata(self._path)
2166
2166
2167 def size(self):
2167 def size(self):
2168 return self._parent.size(self._path)
2168 return self._parent.size(self._path)
2169
2169
2170 def markcopied(self, origin):
2170 def markcopied(self, origin):
2171 self._parent.markcopied(self._path, origin)
2171 self._parent.markcopied(self._path, origin)
2172
2172
2173 def audit(self):
2173 def audit(self):
2174 pass
2174 pass
2175
2175
2176 def flags(self):
2176 def flags(self):
2177 return self._parent.flags(self._path)
2177 return self._parent.flags(self._path)
2178
2178
2179 def setflags(self, islink, isexec):
2179 def setflags(self, islink, isexec):
2180 return self._parent.setflags(self._path, islink, isexec)
2180 return self._parent.setflags(self._path, islink, isexec)
2181
2181
2182 def write(self, data, flags, backgroundclose=False, **kwargs):
2182 def write(self, data, flags, backgroundclose=False, **kwargs):
2183 return self._parent.write(self._path, data, flags, **kwargs)
2183 return self._parent.write(self._path, data, flags, **kwargs)
2184
2184
2185 def remove(self, ignoremissing=False):
2185 def remove(self, ignoremissing=False):
2186 return self._parent.remove(self._path)
2186 return self._parent.remove(self._path)
2187
2187
2188 def clearunknown(self):
2188 def clearunknown(self):
2189 pass
2189 pass
2190
2190
2191 class workingcommitctx(workingctx):
2191 class workingcommitctx(workingctx):
2192 """A workingcommitctx object makes access to data related to
2192 """A workingcommitctx object makes access to data related to
2193 the revision being committed convenient.
2193 the revision being committed convenient.
2194
2194
2195 This hides changes in the working directory, if they aren't
2195 This hides changes in the working directory, if they aren't
2196 committed in this context.
2196 committed in this context.
2197 """
2197 """
2198 def __init__(self, repo, changes,
2198 def __init__(self, repo, changes,
2199 text="", user=None, date=None, extra=None):
2199 text="", user=None, date=None, extra=None):
2200 super(workingcommitctx, self).__init__(repo, text, user, date, extra,
2200 super(workingcommitctx, self).__init__(repo, text, user, date, extra,
2201 changes)
2201 changes)
2202
2202
2203 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
2203 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
2204 """Return matched files only in ``self._status``
2204 """Return matched files only in ``self._status``
2205
2205
2206 Uncommitted files appear "clean" via this context, even if
2206 Uncommitted files appear "clean" via this context, even if
2207 they aren't actually so in the working directory.
2207 they aren't actually so in the working directory.
2208 """
2208 """
2209 if clean:
2209 if clean:
2210 clean = [f for f in self._manifest if f not in self._changedset]
2210 clean = [f for f in self._manifest if f not in self._changedset]
2211 else:
2211 else:
2212 clean = []
2212 clean = []
2213 return scmutil.status([f for f in self._status.modified if match(f)],
2213 return scmutil.status([f for f in self._status.modified if match(f)],
2214 [f for f in self._status.added if match(f)],
2214 [f for f in self._status.added if match(f)],
2215 [f for f in self._status.removed if match(f)],
2215 [f for f in self._status.removed if match(f)],
2216 [], [], [], clean)
2216 [], [], [], clean)
2217
2217
2218 @propertycache
2218 @propertycache
2219 def _changedset(self):
2219 def _changedset(self):
2220 """Return the set of files changed in this context
2220 """Return the set of files changed in this context
2221 """
2221 """
2222 changed = set(self._status.modified)
2222 changed = set(self._status.modified)
2223 changed.update(self._status.added)
2223 changed.update(self._status.added)
2224 changed.update(self._status.removed)
2224 changed.update(self._status.removed)
2225 return changed
2225 return changed
2226
2226
2227 def makecachingfilectxfn(func):
2227 def makecachingfilectxfn(func):
2228 """Create a filectxfn that caches based on the path.
2228 """Create a filectxfn that caches based on the path.
2229
2229
2230 We can't use util.cachefunc because it uses all arguments as the cache
2230 We can't use util.cachefunc because it uses all arguments as the cache
2231 key and this creates a cycle since the arguments include the repo and
2231 key and this creates a cycle since the arguments include the repo and
2232 memctx.
2232 memctx.
2233 """
2233 """
2234 cache = {}
2234 cache = {}
2235
2235
2236 def getfilectx(repo, memctx, path):
2236 def getfilectx(repo, memctx, path):
2237 if path not in cache:
2237 if path not in cache:
2238 cache[path] = func(repo, memctx, path)
2238 cache[path] = func(repo, memctx, path)
2239 return cache[path]
2239 return cache[path]
2240
2240
2241 return getfilectx
2241 return getfilectx
2242
2242
2243 def memfilefromctx(ctx):
2243 def memfilefromctx(ctx):
2244 """Given a context return a memfilectx for ctx[path]
2244 """Given a context return a memfilectx for ctx[path]
2245
2245
2246 This is a convenience method for building a memctx based on another
2246 This is a convenience method for building a memctx based on another
2247 context.
2247 context.
2248 """
2248 """
2249 def getfilectx(repo, memctx, path):
2249 def getfilectx(repo, memctx, path):
2250 fctx = ctx[path]
2250 fctx = ctx[path]
2251 copysource = fctx.copysource()
2251 copysource = fctx.copysource()
2252 return memfilectx(repo, memctx, path, fctx.data(),
2252 return memfilectx(repo, memctx, path, fctx.data(),
2253 islink=fctx.islink(), isexec=fctx.isexec(),
2253 islink=fctx.islink(), isexec=fctx.isexec(),
2254 copysource=copysource)
2254 copysource=copysource)
2255
2255
2256 return getfilectx
2256 return getfilectx
2257
2257
2258 def memfilefrompatch(patchstore):
2258 def memfilefrompatch(patchstore):
2259 """Given a patch (e.g. patchstore object) return a memfilectx
2259 """Given a patch (e.g. patchstore object) return a memfilectx
2260
2260
2261 This is a convenience method for building a memctx based on a patchstore.
2261 This is a convenience method for building a memctx based on a patchstore.
2262 """
2262 """
2263 def getfilectx(repo, memctx, path):
2263 def getfilectx(repo, memctx, path):
2264 data, mode, copysource = patchstore.getfile(path)
2264 data, mode, copysource = patchstore.getfile(path)
2265 if data is None:
2265 if data is None:
2266 return None
2266 return None
2267 islink, isexec = mode
2267 islink, isexec = mode
2268 return memfilectx(repo, memctx, path, data, islink=islink,
2268 return memfilectx(repo, memctx, path, data, islink=islink,
2269 isexec=isexec, copysource=copysource)
2269 isexec=isexec, copysource=copysource)
2270
2270
2271 return getfilectx
2271 return getfilectx
2272
2272
2273 class memctx(committablectx):
2273 class memctx(committablectx):
2274 """Use memctx to perform in-memory commits via localrepo.commitctx().
2274 """Use memctx to perform in-memory commits via localrepo.commitctx().
2275
2275
2276 Revision information is supplied at initialization time while
2276 Revision information is supplied at initialization time while
2277 related files data and is made available through a callback
2277 related files data and is made available through a callback
2278 mechanism. 'repo' is the current localrepo, 'parents' is a
2278 mechanism. 'repo' is the current localrepo, 'parents' is a
2279 sequence of two parent revisions identifiers (pass None for every
2279 sequence of two parent revisions identifiers (pass None for every
2280 missing parent), 'text' is the commit message and 'files' lists
2280 missing parent), 'text' is the commit message and 'files' lists
2281 names of files touched by the revision (normalized and relative to
2281 names of files touched by the revision (normalized and relative to
2282 repository root).
2282 repository root).
2283
2283
2284 filectxfn(repo, memctx, path) is a callable receiving the
2284 filectxfn(repo, memctx, path) is a callable receiving the
2285 repository, the current memctx object and the normalized path of
2285 repository, the current memctx object and the normalized path of
2286 requested file, relative to repository root. It is fired by the
2286 requested file, relative to repository root. It is fired by the
2287 commit function for every file in 'files', but calls order is
2287 commit function for every file in 'files', but calls order is
2288 undefined. If the file is available in the revision being
2288 undefined. If the file is available in the revision being
2289 committed (updated or added), filectxfn returns a memfilectx
2289 committed (updated or added), filectxfn returns a memfilectx
2290 object. If the file was removed, filectxfn return None for recent
2290 object. If the file was removed, filectxfn return None for recent
2291 Mercurial. Moved files are represented by marking the source file
2291 Mercurial. Moved files are represented by marking the source file
2292 removed and the new file added with copy information (see
2292 removed and the new file added with copy information (see
2293 memfilectx).
2293 memfilectx).
2294
2294
2295 user receives the committer name and defaults to current
2295 user receives the committer name and defaults to current
2296 repository username, date is the commit date in any format
2296 repository username, date is the commit date in any format
2297 supported by dateutil.parsedate() and defaults to current date, extra
2297 supported by dateutil.parsedate() and defaults to current date, extra
2298 is a dictionary of metadata or is left empty.
2298 is a dictionary of metadata or is left empty.
2299 """
2299 """
2300
2300
2301 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
2301 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
2302 # Extensions that need to retain compatibility across Mercurial 3.1 can use
2302 # Extensions that need to retain compatibility across Mercurial 3.1 can use
2303 # this field to determine what to do in filectxfn.
2303 # this field to determine what to do in filectxfn.
2304 _returnnoneformissingfiles = True
2304 _returnnoneformissingfiles = True
2305
2305
2306 def __init__(self, repo, parents, text, files, filectxfn, user=None,
2306 def __init__(self, repo, parents, text, files, filectxfn, user=None,
2307 date=None, extra=None, branch=None, editor=False):
2307 date=None, extra=None, branch=None, editor=False):
2308 super(memctx, self).__init__(repo, text, user, date, extra)
2308 super(memctx, self).__init__(repo, text, user, date, extra)
2309 self._rev = None
2309 self._rev = None
2310 self._node = None
2310 self._node = None
2311 parents = [(p or nullid) for p in parents]
2311 parents = [(p or nullid) for p in parents]
2312 p1, p2 = parents
2312 p1, p2 = parents
2313 self._parents = [self._repo[p] for p in (p1, p2)]
2313 self._parents = [self._repo[p] for p in (p1, p2)]
2314 files = sorted(set(files))
2314 files = sorted(set(files))
2315 self._files = files
2315 self._files = files
2316 if branch is not None:
2316 if branch is not None:
2317 self._extra['branch'] = encoding.fromlocal(branch)
2317 self._extra['branch'] = encoding.fromlocal(branch)
2318 self.substate = {}
2318 self.substate = {}
2319
2319
2320 if isinstance(filectxfn, patch.filestore):
2320 if isinstance(filectxfn, patch.filestore):
2321 filectxfn = memfilefrompatch(filectxfn)
2321 filectxfn = memfilefrompatch(filectxfn)
2322 elif not callable(filectxfn):
2322 elif not callable(filectxfn):
2323 # if store is not callable, wrap it in a function
2323 # if store is not callable, wrap it in a function
2324 filectxfn = memfilefromctx(filectxfn)
2324 filectxfn = memfilefromctx(filectxfn)
2325
2325
2326 # memoizing increases performance for e.g. vcs convert scenarios.
2326 # memoizing increases performance for e.g. vcs convert scenarios.
2327 self._filectxfn = makecachingfilectxfn(filectxfn)
2327 self._filectxfn = makecachingfilectxfn(filectxfn)
2328
2328
2329 if editor:
2329 if editor:
2330 self._text = editor(self._repo, self, [])
2330 self._text = editor(self._repo, self, [])
2331 self._repo.savecommitmessage(self._text)
2331 self._repo.savecommitmessage(self._text)
2332
2332
2333 def filectx(self, path, filelog=None):
2333 def filectx(self, path, filelog=None):
2334 """get a file context from the working directory
2334 """get a file context from the working directory
2335
2335
2336 Returns None if file doesn't exist and should be removed."""
2336 Returns None if file doesn't exist and should be removed."""
2337 return self._filectxfn(self._repo, self, path)
2337 return self._filectxfn(self._repo, self, path)
2338
2338
2339 def commit(self):
2339 def commit(self):
2340 """commit context to the repo"""
2340 """commit context to the repo"""
2341 return self._repo.commitctx(self)
2341 return self._repo.commitctx(self)
2342
2342
2343 @propertycache
2343 @propertycache
2344 def _manifest(self):
2344 def _manifest(self):
2345 """generate a manifest based on the return values of filectxfn"""
2345 """generate a manifest based on the return values of filectxfn"""
2346
2346
2347 # keep this simple for now; just worry about p1
2347 # keep this simple for now; just worry about p1
2348 pctx = self._parents[0]
2348 pctx = self._parents[0]
2349 man = pctx.manifest().copy()
2349 man = pctx.manifest().copy()
2350
2350
2351 for f in self._status.modified:
2351 for f in self._status.modified:
2352 man[f] = modifiednodeid
2352 man[f] = modifiednodeid
2353
2353
2354 for f in self._status.added:
2354 for f in self._status.added:
2355 man[f] = addednodeid
2355 man[f] = addednodeid
2356
2356
2357 for f in self._status.removed:
2357 for f in self._status.removed:
2358 if f in man:
2358 if f in man:
2359 del man[f]
2359 del man[f]
2360
2360
2361 return man
2361 return man
2362
2362
2363 @propertycache
2363 @propertycache
2364 def _status(self):
2364 def _status(self):
2365 """Calculate exact status from ``files`` specified at construction
2365 """Calculate exact status from ``files`` specified at construction
2366 """
2366 """
2367 man1 = self.p1().manifest()
2367 man1 = self.p1().manifest()
2368 p2 = self._parents[1]
2368 p2 = self._parents[1]
2369 # "1 < len(self._parents)" can't be used for checking
2369 # "1 < len(self._parents)" can't be used for checking
2370 # existence of the 2nd parent, because "memctx._parents" is
2370 # existence of the 2nd parent, because "memctx._parents" is
2371 # explicitly initialized by the list, of which length is 2.
2371 # explicitly initialized by the list, of which length is 2.
2372 if p2.node() != nullid:
2372 if p2.node() != nullid:
2373 man2 = p2.manifest()
2373 man2 = p2.manifest()
2374 managing = lambda f: f in man1 or f in man2
2374 managing = lambda f: f in man1 or f in man2
2375 else:
2375 else:
2376 managing = lambda f: f in man1
2376 managing = lambda f: f in man1
2377
2377
2378 modified, added, removed = [], [], []
2378 modified, added, removed = [], [], []
2379 for f in self._files:
2379 for f in self._files:
2380 if not managing(f):
2380 if not managing(f):
2381 added.append(f)
2381 added.append(f)
2382 elif self[f]:
2382 elif self[f]:
2383 modified.append(f)
2383 modified.append(f)
2384 else:
2384 else:
2385 removed.append(f)
2385 removed.append(f)
2386
2386
2387 return scmutil.status(modified, added, removed, [], [], [], [])
2387 return scmutil.status(modified, added, removed, [], [], [], [])
2388
2388
2389 class memfilectx(committablefilectx):
2389 class memfilectx(committablefilectx):
2390 """memfilectx represents an in-memory file to commit.
2390 """memfilectx represents an in-memory file to commit.
2391
2391
2392 See memctx and committablefilectx for more details.
2392 See memctx and committablefilectx for more details.
2393 """
2393 """
2394 def __init__(self, repo, changectx, path, data, islink=False,
2394 def __init__(self, repo, changectx, path, data, islink=False,
2395 isexec=False, copysource=None):
2395 isexec=False, copysource=None):
2396 """
2396 """
2397 path is the normalized file path relative to repository root.
2397 path is the normalized file path relative to repository root.
2398 data is the file content as a string.
2398 data is the file content as a string.
2399 islink is True if the file is a symbolic link.
2399 islink is True if the file is a symbolic link.
2400 isexec is True if the file is executable.
2400 isexec is True if the file is executable.
2401 copied is the source file path if current file was copied in the
2401 copied is the source file path if current file was copied in the
2402 revision being committed, or None."""
2402 revision being committed, or None."""
2403 super(memfilectx, self).__init__(repo, path, None, changectx)
2403 super(memfilectx, self).__init__(repo, path, None, changectx)
2404 self._data = data
2404 self._data = data
2405 if islink:
2405 if islink:
2406 self._flags = 'l'
2406 self._flags = 'l'
2407 elif isexec:
2407 elif isexec:
2408 self._flags = 'x'
2408 self._flags = 'x'
2409 else:
2409 else:
2410 self._flags = ''
2410 self._flags = ''
2411 self._copysource = copysource
2411 self._copysource = copysource
2412
2412
2413 def copysource(self):
2413 def copysource(self):
2414 return self._copysource
2414 return self._copysource
2415
2415
2416 def cmp(self, fctx):
2416 def cmp(self, fctx):
2417 return self.data() != fctx.data()
2417 return self.data() != fctx.data()
2418
2418
2419 def data(self):
2419 def data(self):
2420 return self._data
2420 return self._data
2421
2421
2422 def remove(self, ignoremissing=False):
2422 def remove(self, ignoremissing=False):
2423 """wraps unlink for a repo's working directory"""
2423 """wraps unlink for a repo's working directory"""
2424 # need to figure out what to do here
2424 # need to figure out what to do here
2425 del self._changectx[self._path]
2425 del self._changectx[self._path]
2426
2426
2427 def write(self, data, flags, **kwargs):
2427 def write(self, data, flags, **kwargs):
2428 """wraps repo.wwrite"""
2428 """wraps repo.wwrite"""
2429 self._data = data
2429 self._data = data
2430
2430
2431
2431
2432 class metadataonlyctx(committablectx):
2432 class metadataonlyctx(committablectx):
2433 """Like memctx but it's reusing the manifest of different commit.
2433 """Like memctx but it's reusing the manifest of different commit.
2434 Intended to be used by lightweight operations that are creating
2434 Intended to be used by lightweight operations that are creating
2435 metadata-only changes.
2435 metadata-only changes.
2436
2436
2437 Revision information is supplied at initialization time. 'repo' is the
2437 Revision information is supplied at initialization time. 'repo' is the
2438 current localrepo, 'ctx' is original revision which manifest we're reuisng
2438 current localrepo, 'ctx' is original revision which manifest we're reuisng
2439 'parents' is a sequence of two parent revisions identifiers (pass None for
2439 'parents' is a sequence of two parent revisions identifiers (pass None for
2440 every missing parent), 'text' is the commit.
2440 every missing parent), 'text' is the commit.
2441
2441
2442 user receives the committer name and defaults to current repository
2442 user receives the committer name and defaults to current repository
2443 username, date is the commit date in any format supported by
2443 username, date is the commit date in any format supported by
2444 dateutil.parsedate() and defaults to current date, extra is a dictionary of
2444 dateutil.parsedate() and defaults to current date, extra is a dictionary of
2445 metadata or is left empty.
2445 metadata or is left empty.
2446 """
2446 """
2447 def __init__(self, repo, originalctx, parents=None, text=None, user=None,
2447 def __init__(self, repo, originalctx, parents=None, text=None, user=None,
2448 date=None, extra=None, editor=False):
2448 date=None, extra=None, editor=False):
2449 if text is None:
2449 if text is None:
2450 text = originalctx.description()
2450 text = originalctx.description()
2451 super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
2451 super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
2452 self._rev = None
2452 self._rev = None
2453 self._node = None
2453 self._node = None
2454 self._originalctx = originalctx
2454 self._originalctx = originalctx
2455 self._manifestnode = originalctx.manifestnode()
2455 self._manifestnode = originalctx.manifestnode()
2456 if parents is None:
2456 if parents is None:
2457 parents = originalctx.parents()
2457 parents = originalctx.parents()
2458 else:
2458 else:
2459 parents = [repo[p] for p in parents if p is not None]
2459 parents = [repo[p] for p in parents if p is not None]
2460 parents = parents[:]
2460 parents = parents[:]
2461 while len(parents) < 2:
2461 while len(parents) < 2:
2462 parents.append(repo[nullid])
2462 parents.append(repo[nullid])
2463 p1, p2 = self._parents = parents
2463 p1, p2 = self._parents = parents
2464
2464
2465 # sanity check to ensure that the reused manifest parents are
2465 # sanity check to ensure that the reused manifest parents are
2466 # manifests of our commit parents
2466 # manifests of our commit parents
2467 mp1, mp2 = self.manifestctx().parents
2467 mp1, mp2 = self.manifestctx().parents
2468 if p1 != nullid and p1.manifestnode() != mp1:
2468 if p1 != nullid and p1.manifestnode() != mp1:
2469 raise RuntimeError(r"can't reuse the manifest: its p1 "
2469 raise RuntimeError(r"can't reuse the manifest: its p1 "
2470 r"doesn't match the new ctx p1")
2470 r"doesn't match the new ctx p1")
2471 if p2 != nullid and p2.manifestnode() != mp2:
2471 if p2 != nullid and p2.manifestnode() != mp2:
2472 raise RuntimeError(r"can't reuse the manifest: "
2472 raise RuntimeError(r"can't reuse the manifest: "
2473 r"its p2 doesn't match the new ctx p2")
2473 r"its p2 doesn't match the new ctx p2")
2474
2474
2475 self._files = originalctx.files()
2475 self._files = originalctx.files()
2476 self.substate = {}
2476 self.substate = {}
2477
2477
2478 if editor:
2478 if editor:
2479 self._text = editor(self._repo, self, [])
2479 self._text = editor(self._repo, self, [])
2480 self._repo.savecommitmessage(self._text)
2480 self._repo.savecommitmessage(self._text)
2481
2481
2482 def manifestnode(self):
2482 def manifestnode(self):
2483 return self._manifestnode
2483 return self._manifestnode
2484
2484
2485 @property
2485 @property
2486 def _manifestctx(self):
2486 def _manifestctx(self):
2487 return self._repo.manifestlog[self._manifestnode]
2487 return self._repo.manifestlog[self._manifestnode]
2488
2488
2489 def filectx(self, path, filelog=None):
2489 def filectx(self, path, filelog=None):
2490 return self._originalctx.filectx(path, filelog=filelog)
2490 return self._originalctx.filectx(path, filelog=filelog)
2491
2491
2492 def commit(self):
2492 def commit(self):
2493 """commit context to the repo"""
2493 """commit context to the repo"""
2494 return self._repo.commitctx(self)
2494 return self._repo.commitctx(self)
2495
2495
2496 @property
2496 @property
2497 def _manifest(self):
2497 def _manifest(self):
2498 return self._originalctx.manifest()
2498 return self._originalctx.manifest()
2499
2499
2500 @propertycache
2500 @propertycache
2501 def _status(self):
2501 def _status(self):
2502 """Calculate exact status from ``files`` specified in the ``origctx``
2502 """Calculate exact status from ``files`` specified in the ``origctx``
2503 and parents manifests.
2503 and parents manifests.
2504 """
2504 """
2505 man1 = self.p1().manifest()
2505 man1 = self.p1().manifest()
2506 p2 = self._parents[1]
2506 p2 = self._parents[1]
2507 # "1 < len(self._parents)" can't be used for checking
2507 # "1 < len(self._parents)" can't be used for checking
2508 # existence of the 2nd parent, because "metadataonlyctx._parents" is
2508 # existence of the 2nd parent, because "metadataonlyctx._parents" is
2509 # explicitly initialized by the list, of which length is 2.
2509 # explicitly initialized by the list, of which length is 2.
2510 if p2.node() != nullid:
2510 if p2.node() != nullid:
2511 man2 = p2.manifest()
2511 man2 = p2.manifest()
2512 managing = lambda f: f in man1 or f in man2
2512 managing = lambda f: f in man1 or f in man2
2513 else:
2513 else:
2514 managing = lambda f: f in man1
2514 managing = lambda f: f in man1
2515
2515
2516 modified, added, removed = [], [], []
2516 modified, added, removed = [], [], []
2517 for f in self._files:
2517 for f in self._files:
2518 if not managing(f):
2518 if not managing(f):
2519 added.append(f)
2519 added.append(f)
2520 elif f in self:
2520 elif f in self:
2521 modified.append(f)
2521 modified.append(f)
2522 else:
2522 else:
2523 removed.append(f)
2523 removed.append(f)
2524
2524
2525 return scmutil.status(modified, added, removed, [], [], [], [])
2525 return scmutil.status(modified, added, removed, [], [], [], [])
2526
2526
2527 class arbitraryfilectx(object):
2527 class arbitraryfilectx(object):
2528 """Allows you to use filectx-like functions on a file in an arbitrary
2528 """Allows you to use filectx-like functions on a file in an arbitrary
2529 location on disk, possibly not in the working directory.
2529 location on disk, possibly not in the working directory.
2530 """
2530 """
2531 def __init__(self, path, repo=None):
2531 def __init__(self, path, repo=None):
2532 # Repo is optional because contrib/simplemerge uses this class.
2532 # Repo is optional because contrib/simplemerge uses this class.
2533 self._repo = repo
2533 self._repo = repo
2534 self._path = path
2534 self._path = path
2535
2535
2536 def cmp(self, fctx):
2536 def cmp(self, fctx):
2537 # filecmp follows symlinks whereas `cmp` should not, so skip the fast
2537 # filecmp follows symlinks whereas `cmp` should not, so skip the fast
2538 # path if either side is a symlink.
2538 # path if either side is a symlink.
2539 symlinks = ('l' in self.flags() or 'l' in fctx.flags())
2539 symlinks = ('l' in self.flags() or 'l' in fctx.flags())
2540 if not symlinks and isinstance(fctx, workingfilectx) and self._repo:
2540 if not symlinks and isinstance(fctx, workingfilectx) and self._repo:
2541 # Add a fast-path for merge if both sides are disk-backed.
2541 # Add a fast-path for merge if both sides are disk-backed.
2542 # Note that filecmp uses the opposite return values (True if same)
2542 # Note that filecmp uses the opposite return values (True if same)
2543 # from our cmp functions (True if different).
2543 # from our cmp functions (True if different).
2544 return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path()))
2544 return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path()))
2545 return self.data() != fctx.data()
2545 return self.data() != fctx.data()
2546
2546
2547 def path(self):
2547 def path(self):
2548 return self._path
2548 return self._path
2549
2549
2550 def flags(self):
2550 def flags(self):
2551 return ''
2551 return ''
2552
2552
2553 def data(self):
2553 def data(self):
2554 return util.readfile(self._path)
2554 return util.readfile(self._path)
2555
2555
2556 def decodeddata(self):
2556 def decodeddata(self):
2557 with open(self._path, "rb") as f:
2557 with open(self._path, "rb") as f:
2558 return f.read()
2558 return f.read()
2559
2559
2560 def remove(self):
2560 def remove(self):
2561 util.unlink(self._path)
2561 util.unlink(self._path)
2562
2562
2563 def write(self, data, flags, **kwargs):
2563 def write(self, data, flags, **kwargs):
2564 assert not flags
2564 assert not flags
2565 with open(self._path, "wb") as f:
2565 with open(self._path, "wb") as f:
2566 f.write(data)
2566 f.write(data)
@@ -1,2698 +1,2695 b''
1 # exchange.py - utility to exchange data between repos.
1 # exchange.py - utility to exchange data between repos.
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import collections
10 import collections
11 import hashlib
11 import hashlib
12
12
13 from .i18n import _
13 from .i18n import _
14 from .node import (
14 from .node import (
15 bin,
15 bin,
16 hex,
16 hex,
17 nullid,
17 nullid,
18 nullrev,
18 nullrev,
19 )
19 )
20 from .thirdparty import (
20 from .thirdparty import (
21 attr,
21 attr,
22 )
22 )
23 from . import (
23 from . import (
24 bookmarks as bookmod,
24 bookmarks as bookmod,
25 bundle2,
25 bundle2,
26 changegroup,
26 changegroup,
27 discovery,
27 discovery,
28 error,
28 error,
29 exchangev2,
29 exchangev2,
30 lock as lockmod,
30 lock as lockmod,
31 logexchange,
31 logexchange,
32 narrowspec,
32 narrowspec,
33 obsolete,
33 obsolete,
34 phases,
34 phases,
35 pushkey,
35 pushkey,
36 pycompat,
36 pycompat,
37 repository,
37 repository,
38 scmutil,
38 scmutil,
39 sslutil,
39 sslutil,
40 streamclone,
40 streamclone,
41 url as urlmod,
41 url as urlmod,
42 util,
42 util,
43 wireprototypes,
43 wireprototypes,
44 )
44 )
45 from .utils import (
45 from .utils import (
46 stringutil,
46 stringutil,
47 )
47 )
48
48
49 urlerr = util.urlerr
49 urlerr = util.urlerr
50 urlreq = util.urlreq
50 urlreq = util.urlreq
51
51
52 _NARROWACL_SECTION = 'narrowhgacl'
52 _NARROWACL_SECTION = 'narrowacl'
53
53
54 # Maps bundle version human names to changegroup versions.
54 # Maps bundle version human names to changegroup versions.
55 _bundlespeccgversions = {'v1': '01',
55 _bundlespeccgversions = {'v1': '01',
56 'v2': '02',
56 'v2': '02',
57 'packed1': 's1',
57 'packed1': 's1',
58 'bundle2': '02', #legacy
58 'bundle2': '02', #legacy
59 }
59 }
60
60
61 # Maps bundle version with content opts to choose which part to bundle
61 # Maps bundle version with content opts to choose which part to bundle
62 _bundlespeccontentopts = {
62 _bundlespeccontentopts = {
63 'v1': {
63 'v1': {
64 'changegroup': True,
64 'changegroup': True,
65 'cg.version': '01',
65 'cg.version': '01',
66 'obsolescence': False,
66 'obsolescence': False,
67 'phases': False,
67 'phases': False,
68 'tagsfnodescache': False,
68 'tagsfnodescache': False,
69 'revbranchcache': False
69 'revbranchcache': False
70 },
70 },
71 'v2': {
71 'v2': {
72 'changegroup': True,
72 'changegroup': True,
73 'cg.version': '02',
73 'cg.version': '02',
74 'obsolescence': False,
74 'obsolescence': False,
75 'phases': False,
75 'phases': False,
76 'tagsfnodescache': True,
76 'tagsfnodescache': True,
77 'revbranchcache': True
77 'revbranchcache': True
78 },
78 },
79 'packed1' : {
79 'packed1' : {
80 'cg.version': 's1'
80 'cg.version': 's1'
81 }
81 }
82 }
82 }
83 _bundlespeccontentopts['bundle2'] = _bundlespeccontentopts['v2']
83 _bundlespeccontentopts['bundle2'] = _bundlespeccontentopts['v2']
84
84
85 _bundlespecvariants = {"streamv2": {"changegroup": False, "streamv2": True,
85 _bundlespecvariants = {"streamv2": {"changegroup": False, "streamv2": True,
86 "tagsfnodescache": False,
86 "tagsfnodescache": False,
87 "revbranchcache": False}}
87 "revbranchcache": False}}
88
88
89 # Compression engines allowed in version 1. THIS SHOULD NEVER CHANGE.
89 # Compression engines allowed in version 1. THIS SHOULD NEVER CHANGE.
90 _bundlespecv1compengines = {'gzip', 'bzip2', 'none'}
90 _bundlespecv1compengines = {'gzip', 'bzip2', 'none'}
91
91
92 @attr.s
92 @attr.s
93 class bundlespec(object):
93 class bundlespec(object):
94 compression = attr.ib()
94 compression = attr.ib()
95 wirecompression = attr.ib()
95 wirecompression = attr.ib()
96 version = attr.ib()
96 version = attr.ib()
97 wireversion = attr.ib()
97 wireversion = attr.ib()
98 params = attr.ib()
98 params = attr.ib()
99 contentopts = attr.ib()
99 contentopts = attr.ib()
100
100
101 def parsebundlespec(repo, spec, strict=True):
101 def parsebundlespec(repo, spec, strict=True):
102 """Parse a bundle string specification into parts.
102 """Parse a bundle string specification into parts.
103
103
104 Bundle specifications denote a well-defined bundle/exchange format.
104 Bundle specifications denote a well-defined bundle/exchange format.
105 The content of a given specification should not change over time in
105 The content of a given specification should not change over time in
106 order to ensure that bundles produced by a newer version of Mercurial are
106 order to ensure that bundles produced by a newer version of Mercurial are
107 readable from an older version.
107 readable from an older version.
108
108
109 The string currently has the form:
109 The string currently has the form:
110
110
111 <compression>-<type>[;<parameter0>[;<parameter1>]]
111 <compression>-<type>[;<parameter0>[;<parameter1>]]
112
112
113 Where <compression> is one of the supported compression formats
113 Where <compression> is one of the supported compression formats
114 and <type> is (currently) a version string. A ";" can follow the type and
114 and <type> is (currently) a version string. A ";" can follow the type and
115 all text afterwards is interpreted as URI encoded, ";" delimited key=value
115 all text afterwards is interpreted as URI encoded, ";" delimited key=value
116 pairs.
116 pairs.
117
117
118 If ``strict`` is True (the default) <compression> is required. Otherwise,
118 If ``strict`` is True (the default) <compression> is required. Otherwise,
119 it is optional.
119 it is optional.
120
120
121 Returns a bundlespec object of (compression, version, parameters).
121 Returns a bundlespec object of (compression, version, parameters).
122 Compression will be ``None`` if not in strict mode and a compression isn't
122 Compression will be ``None`` if not in strict mode and a compression isn't
123 defined.
123 defined.
124
124
125 An ``InvalidBundleSpecification`` is raised when the specification is
125 An ``InvalidBundleSpecification`` is raised when the specification is
126 not syntactically well formed.
126 not syntactically well formed.
127
127
128 An ``UnsupportedBundleSpecification`` is raised when the compression or
128 An ``UnsupportedBundleSpecification`` is raised when the compression or
129 bundle type/version is not recognized.
129 bundle type/version is not recognized.
130
130
131 Note: this function will likely eventually return a more complex data
131 Note: this function will likely eventually return a more complex data
132 structure, including bundle2 part information.
132 structure, including bundle2 part information.
133 """
133 """
134 def parseparams(s):
134 def parseparams(s):
135 if ';' not in s:
135 if ';' not in s:
136 return s, {}
136 return s, {}
137
137
138 params = {}
138 params = {}
139 version, paramstr = s.split(';', 1)
139 version, paramstr = s.split(';', 1)
140
140
141 for p in paramstr.split(';'):
141 for p in paramstr.split(';'):
142 if '=' not in p:
142 if '=' not in p:
143 raise error.InvalidBundleSpecification(
143 raise error.InvalidBundleSpecification(
144 _('invalid bundle specification: '
144 _('invalid bundle specification: '
145 'missing "=" in parameter: %s') % p)
145 'missing "=" in parameter: %s') % p)
146
146
147 key, value = p.split('=', 1)
147 key, value = p.split('=', 1)
148 key = urlreq.unquote(key)
148 key = urlreq.unquote(key)
149 value = urlreq.unquote(value)
149 value = urlreq.unquote(value)
150 params[key] = value
150 params[key] = value
151
151
152 return version, params
152 return version, params
153
153
154
154
155 if strict and '-' not in spec:
155 if strict and '-' not in spec:
156 raise error.InvalidBundleSpecification(
156 raise error.InvalidBundleSpecification(
157 _('invalid bundle specification; '
157 _('invalid bundle specification; '
158 'must be prefixed with compression: %s') % spec)
158 'must be prefixed with compression: %s') % spec)
159
159
160 if '-' in spec:
160 if '-' in spec:
161 compression, version = spec.split('-', 1)
161 compression, version = spec.split('-', 1)
162
162
163 if compression not in util.compengines.supportedbundlenames:
163 if compression not in util.compengines.supportedbundlenames:
164 raise error.UnsupportedBundleSpecification(
164 raise error.UnsupportedBundleSpecification(
165 _('%s compression is not supported') % compression)
165 _('%s compression is not supported') % compression)
166
166
167 version, params = parseparams(version)
167 version, params = parseparams(version)
168
168
169 if version not in _bundlespeccgversions:
169 if version not in _bundlespeccgversions:
170 raise error.UnsupportedBundleSpecification(
170 raise error.UnsupportedBundleSpecification(
171 _('%s is not a recognized bundle version') % version)
171 _('%s is not a recognized bundle version') % version)
172 else:
172 else:
173 # Value could be just the compression or just the version, in which
173 # Value could be just the compression or just the version, in which
174 # case some defaults are assumed (but only when not in strict mode).
174 # case some defaults are assumed (but only when not in strict mode).
175 assert not strict
175 assert not strict
176
176
177 spec, params = parseparams(spec)
177 spec, params = parseparams(spec)
178
178
179 if spec in util.compengines.supportedbundlenames:
179 if spec in util.compengines.supportedbundlenames:
180 compression = spec
180 compression = spec
181 version = 'v1'
181 version = 'v1'
182 # Generaldelta repos require v2.
182 # Generaldelta repos require v2.
183 if 'generaldelta' in repo.requirements:
183 if 'generaldelta' in repo.requirements:
184 version = 'v2'
184 version = 'v2'
185 # Modern compression engines require v2.
185 # Modern compression engines require v2.
186 if compression not in _bundlespecv1compengines:
186 if compression not in _bundlespecv1compengines:
187 version = 'v2'
187 version = 'v2'
188 elif spec in _bundlespeccgversions:
188 elif spec in _bundlespeccgversions:
189 if spec == 'packed1':
189 if spec == 'packed1':
190 compression = 'none'
190 compression = 'none'
191 else:
191 else:
192 compression = 'bzip2'
192 compression = 'bzip2'
193 version = spec
193 version = spec
194 else:
194 else:
195 raise error.UnsupportedBundleSpecification(
195 raise error.UnsupportedBundleSpecification(
196 _('%s is not a recognized bundle specification') % spec)
196 _('%s is not a recognized bundle specification') % spec)
197
197
198 # Bundle version 1 only supports a known set of compression engines.
198 # Bundle version 1 only supports a known set of compression engines.
199 if version == 'v1' and compression not in _bundlespecv1compengines:
199 if version == 'v1' and compression not in _bundlespecv1compengines:
200 raise error.UnsupportedBundleSpecification(
200 raise error.UnsupportedBundleSpecification(
201 _('compression engine %s is not supported on v1 bundles') %
201 _('compression engine %s is not supported on v1 bundles') %
202 compression)
202 compression)
203
203
204 # The specification for packed1 can optionally declare the data formats
204 # The specification for packed1 can optionally declare the data formats
205 # required to apply it. If we see this metadata, compare against what the
205 # required to apply it. If we see this metadata, compare against what the
206 # repo supports and error if the bundle isn't compatible.
206 # repo supports and error if the bundle isn't compatible.
207 if version == 'packed1' and 'requirements' in params:
207 if version == 'packed1' and 'requirements' in params:
208 requirements = set(params['requirements'].split(','))
208 requirements = set(params['requirements'].split(','))
209 missingreqs = requirements - repo.supportedformats
209 missingreqs = requirements - repo.supportedformats
210 if missingreqs:
210 if missingreqs:
211 raise error.UnsupportedBundleSpecification(
211 raise error.UnsupportedBundleSpecification(
212 _('missing support for repository features: %s') %
212 _('missing support for repository features: %s') %
213 ', '.join(sorted(missingreqs)))
213 ', '.join(sorted(missingreqs)))
214
214
215 # Compute contentopts based on the version
215 # Compute contentopts based on the version
216 contentopts = _bundlespeccontentopts.get(version, {}).copy()
216 contentopts = _bundlespeccontentopts.get(version, {}).copy()
217
217
218 # Process the variants
218 # Process the variants
219 if "stream" in params and params["stream"] == "v2":
219 if "stream" in params and params["stream"] == "v2":
220 variant = _bundlespecvariants["streamv2"]
220 variant = _bundlespecvariants["streamv2"]
221 contentopts.update(variant)
221 contentopts.update(variant)
222
222
223 engine = util.compengines.forbundlename(compression)
223 engine = util.compengines.forbundlename(compression)
224 compression, wirecompression = engine.bundletype()
224 compression, wirecompression = engine.bundletype()
225 wireversion = _bundlespeccgversions[version]
225 wireversion = _bundlespeccgversions[version]
226
226
227 return bundlespec(compression, wirecompression, version, wireversion,
227 return bundlespec(compression, wirecompression, version, wireversion,
228 params, contentopts)
228 params, contentopts)
229
229
230 def readbundle(ui, fh, fname, vfs=None):
230 def readbundle(ui, fh, fname, vfs=None):
231 header = changegroup.readexactly(fh, 4)
231 header = changegroup.readexactly(fh, 4)
232
232
233 alg = None
233 alg = None
234 if not fname:
234 if not fname:
235 fname = "stream"
235 fname = "stream"
236 if not header.startswith('HG') and header.startswith('\0'):
236 if not header.startswith('HG') and header.startswith('\0'):
237 fh = changegroup.headerlessfixup(fh, header)
237 fh = changegroup.headerlessfixup(fh, header)
238 header = "HG10"
238 header = "HG10"
239 alg = 'UN'
239 alg = 'UN'
240 elif vfs:
240 elif vfs:
241 fname = vfs.join(fname)
241 fname = vfs.join(fname)
242
242
243 magic, version = header[0:2], header[2:4]
243 magic, version = header[0:2], header[2:4]
244
244
245 if magic != 'HG':
245 if magic != 'HG':
246 raise error.Abort(_('%s: not a Mercurial bundle') % fname)
246 raise error.Abort(_('%s: not a Mercurial bundle') % fname)
247 if version == '10':
247 if version == '10':
248 if alg is None:
248 if alg is None:
249 alg = changegroup.readexactly(fh, 2)
249 alg = changegroup.readexactly(fh, 2)
250 return changegroup.cg1unpacker(fh, alg)
250 return changegroup.cg1unpacker(fh, alg)
251 elif version.startswith('2'):
251 elif version.startswith('2'):
252 return bundle2.getunbundler(ui, fh, magicstring=magic + version)
252 return bundle2.getunbundler(ui, fh, magicstring=magic + version)
253 elif version == 'S1':
253 elif version == 'S1':
254 return streamclone.streamcloneapplier(fh)
254 return streamclone.streamcloneapplier(fh)
255 else:
255 else:
256 raise error.Abort(_('%s: unknown bundle version %s') % (fname, version))
256 raise error.Abort(_('%s: unknown bundle version %s') % (fname, version))
257
257
258 def getbundlespec(ui, fh):
258 def getbundlespec(ui, fh):
259 """Infer the bundlespec from a bundle file handle.
259 """Infer the bundlespec from a bundle file handle.
260
260
261 The input file handle is seeked and the original seek position is not
261 The input file handle is seeked and the original seek position is not
262 restored.
262 restored.
263 """
263 """
264 def speccompression(alg):
264 def speccompression(alg):
265 try:
265 try:
266 return util.compengines.forbundletype(alg).bundletype()[0]
266 return util.compengines.forbundletype(alg).bundletype()[0]
267 except KeyError:
267 except KeyError:
268 return None
268 return None
269
269
270 b = readbundle(ui, fh, None)
270 b = readbundle(ui, fh, None)
271 if isinstance(b, changegroup.cg1unpacker):
271 if isinstance(b, changegroup.cg1unpacker):
272 alg = b._type
272 alg = b._type
273 if alg == '_truncatedBZ':
273 if alg == '_truncatedBZ':
274 alg = 'BZ'
274 alg = 'BZ'
275 comp = speccompression(alg)
275 comp = speccompression(alg)
276 if not comp:
276 if not comp:
277 raise error.Abort(_('unknown compression algorithm: %s') % alg)
277 raise error.Abort(_('unknown compression algorithm: %s') % alg)
278 return '%s-v1' % comp
278 return '%s-v1' % comp
279 elif isinstance(b, bundle2.unbundle20):
279 elif isinstance(b, bundle2.unbundle20):
280 if 'Compression' in b.params:
280 if 'Compression' in b.params:
281 comp = speccompression(b.params['Compression'])
281 comp = speccompression(b.params['Compression'])
282 if not comp:
282 if not comp:
283 raise error.Abort(_('unknown compression algorithm: %s') % comp)
283 raise error.Abort(_('unknown compression algorithm: %s') % comp)
284 else:
284 else:
285 comp = 'none'
285 comp = 'none'
286
286
287 version = None
287 version = None
288 for part in b.iterparts():
288 for part in b.iterparts():
289 if part.type == 'changegroup':
289 if part.type == 'changegroup':
290 version = part.params['version']
290 version = part.params['version']
291 if version in ('01', '02'):
291 if version in ('01', '02'):
292 version = 'v2'
292 version = 'v2'
293 else:
293 else:
294 raise error.Abort(_('changegroup version %s does not have '
294 raise error.Abort(_('changegroup version %s does not have '
295 'a known bundlespec') % version,
295 'a known bundlespec') % version,
296 hint=_('try upgrading your Mercurial '
296 hint=_('try upgrading your Mercurial '
297 'client'))
297 'client'))
298 elif part.type == 'stream2' and version is None:
298 elif part.type == 'stream2' and version is None:
299 # A stream2 part requires to be part of a v2 bundle
299 # A stream2 part requires to be part of a v2 bundle
300 requirements = urlreq.unquote(part.params['requirements'])
300 requirements = urlreq.unquote(part.params['requirements'])
301 splitted = requirements.split()
301 splitted = requirements.split()
302 params = bundle2._formatrequirementsparams(splitted)
302 params = bundle2._formatrequirementsparams(splitted)
303 return 'none-v2;stream=v2;%s' % params
303 return 'none-v2;stream=v2;%s' % params
304
304
305 if not version:
305 if not version:
306 raise error.Abort(_('could not identify changegroup version in '
306 raise error.Abort(_('could not identify changegroup version in '
307 'bundle'))
307 'bundle'))
308
308
309 return '%s-%s' % (comp, version)
309 return '%s-%s' % (comp, version)
310 elif isinstance(b, streamclone.streamcloneapplier):
310 elif isinstance(b, streamclone.streamcloneapplier):
311 requirements = streamclone.readbundle1header(fh)[2]
311 requirements = streamclone.readbundle1header(fh)[2]
312 formatted = bundle2._formatrequirementsparams(requirements)
312 formatted = bundle2._formatrequirementsparams(requirements)
313 return 'none-packed1;%s' % formatted
313 return 'none-packed1;%s' % formatted
314 else:
314 else:
315 raise error.Abort(_('unknown bundle type: %s') % b)
315 raise error.Abort(_('unknown bundle type: %s') % b)
316
316
317 def _computeoutgoing(repo, heads, common):
317 def _computeoutgoing(repo, heads, common):
318 """Computes which revs are outgoing given a set of common
318 """Computes which revs are outgoing given a set of common
319 and a set of heads.
319 and a set of heads.
320
320
321 This is a separate function so extensions can have access to
321 This is a separate function so extensions can have access to
322 the logic.
322 the logic.
323
323
324 Returns a discovery.outgoing object.
324 Returns a discovery.outgoing object.
325 """
325 """
326 cl = repo.changelog
326 cl = repo.changelog
327 if common:
327 if common:
328 hasnode = cl.hasnode
328 hasnode = cl.hasnode
329 common = [n for n in common if hasnode(n)]
329 common = [n for n in common if hasnode(n)]
330 else:
330 else:
331 common = [nullid]
331 common = [nullid]
332 if not heads:
332 if not heads:
333 heads = cl.heads()
333 heads = cl.heads()
334 return discovery.outgoing(repo, common, heads)
334 return discovery.outgoing(repo, common, heads)
335
335
336 def _checkpublish(pushop):
336 def _checkpublish(pushop):
337 repo = pushop.repo
337 repo = pushop.repo
338 ui = repo.ui
338 ui = repo.ui
339 behavior = ui.config('experimental', 'auto-publish')
339 behavior = ui.config('experimental', 'auto-publish')
340 if pushop.publish or behavior not in ('warn', 'confirm', 'abort'):
340 if pushop.publish or behavior not in ('warn', 'confirm', 'abort'):
341 return
341 return
342 remotephases = listkeys(pushop.remote, 'phases')
342 remotephases = listkeys(pushop.remote, 'phases')
343 if not remotephases.get('publishing', False):
343 if not remotephases.get('publishing', False):
344 return
344 return
345
345
346 if pushop.revs is None:
346 if pushop.revs is None:
347 published = repo.filtered('served').revs('not public()')
347 published = repo.filtered('served').revs('not public()')
348 else:
348 else:
349 published = repo.revs('::%ln - public()', pushop.revs)
349 published = repo.revs('::%ln - public()', pushop.revs)
350 if published:
350 if published:
351 if behavior == 'warn':
351 if behavior == 'warn':
352 ui.warn(_('%i changesets about to be published\n')
352 ui.warn(_('%i changesets about to be published\n')
353 % len(published))
353 % len(published))
354 elif behavior == 'confirm':
354 elif behavior == 'confirm':
355 if ui.promptchoice(_('push and publish %i changesets (yn)?'
355 if ui.promptchoice(_('push and publish %i changesets (yn)?'
356 '$$ &Yes $$ &No') % len(published)):
356 '$$ &Yes $$ &No') % len(published)):
357 raise error.Abort(_('user quit'))
357 raise error.Abort(_('user quit'))
358 elif behavior == 'abort':
358 elif behavior == 'abort':
359 msg = _('push would publish %i changesets') % len(published)
359 msg = _('push would publish %i changesets') % len(published)
360 hint = _("use --publish or adjust 'experimental.auto-publish'"
360 hint = _("use --publish or adjust 'experimental.auto-publish'"
361 " config")
361 " config")
362 raise error.Abort(msg, hint=hint)
362 raise error.Abort(msg, hint=hint)
363
363
364 def _forcebundle1(op):
364 def _forcebundle1(op):
365 """return true if a pull/push must use bundle1
365 """return true if a pull/push must use bundle1
366
366
367 This function is used to allow testing of the older bundle version"""
367 This function is used to allow testing of the older bundle version"""
368 ui = op.repo.ui
368 ui = op.repo.ui
369 # The goal is this config is to allow developer to choose the bundle
369 # The goal is this config is to allow developer to choose the bundle
370 # version used during exchanged. This is especially handy during test.
370 # version used during exchanged. This is especially handy during test.
371 # Value is a list of bundle version to be picked from, highest version
371 # Value is a list of bundle version to be picked from, highest version
372 # should be used.
372 # should be used.
373 #
373 #
374 # developer config: devel.legacy.exchange
374 # developer config: devel.legacy.exchange
375 exchange = ui.configlist('devel', 'legacy.exchange')
375 exchange = ui.configlist('devel', 'legacy.exchange')
376 forcebundle1 = 'bundle2' not in exchange and 'bundle1' in exchange
376 forcebundle1 = 'bundle2' not in exchange and 'bundle1' in exchange
377 return forcebundle1 or not op.remote.capable('bundle2')
377 return forcebundle1 or not op.remote.capable('bundle2')
378
378
379 class pushoperation(object):
379 class pushoperation(object):
380 """A object that represent a single push operation
380 """A object that represent a single push operation
381
381
382 Its purpose is to carry push related state and very common operations.
382 Its purpose is to carry push related state and very common operations.
383
383
384 A new pushoperation should be created at the beginning of each push and
384 A new pushoperation should be created at the beginning of each push and
385 discarded afterward.
385 discarded afterward.
386 """
386 """
387
387
388 def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
388 def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
389 bookmarks=(), publish=False, pushvars=None):
389 bookmarks=(), publish=False, pushvars=None):
390 # repo we push from
390 # repo we push from
391 self.repo = repo
391 self.repo = repo
392 self.ui = repo.ui
392 self.ui = repo.ui
393 # repo we push to
393 # repo we push to
394 self.remote = remote
394 self.remote = remote
395 # force option provided
395 # force option provided
396 self.force = force
396 self.force = force
397 # revs to be pushed (None is "all")
397 # revs to be pushed (None is "all")
398 self.revs = revs
398 self.revs = revs
399 # bookmark explicitly pushed
399 # bookmark explicitly pushed
400 self.bookmarks = bookmarks
400 self.bookmarks = bookmarks
401 # allow push of new branch
401 # allow push of new branch
402 self.newbranch = newbranch
402 self.newbranch = newbranch
403 # step already performed
403 # step already performed
404 # (used to check what steps have been already performed through bundle2)
404 # (used to check what steps have been already performed through bundle2)
405 self.stepsdone = set()
405 self.stepsdone = set()
406 # Integer version of the changegroup push result
406 # Integer version of the changegroup push result
407 # - None means nothing to push
407 # - None means nothing to push
408 # - 0 means HTTP error
408 # - 0 means HTTP error
409 # - 1 means we pushed and remote head count is unchanged *or*
409 # - 1 means we pushed and remote head count is unchanged *or*
410 # we have outgoing changesets but refused to push
410 # we have outgoing changesets but refused to push
411 # - other values as described by addchangegroup()
411 # - other values as described by addchangegroup()
412 self.cgresult = None
412 self.cgresult = None
413 # Boolean value for the bookmark push
413 # Boolean value for the bookmark push
414 self.bkresult = None
414 self.bkresult = None
415 # discover.outgoing object (contains common and outgoing data)
415 # discover.outgoing object (contains common and outgoing data)
416 self.outgoing = None
416 self.outgoing = None
417 # all remote topological heads before the push
417 # all remote topological heads before the push
418 self.remoteheads = None
418 self.remoteheads = None
419 # Details of the remote branch pre and post push
419 # Details of the remote branch pre and post push
420 #
420 #
421 # mapping: {'branch': ([remoteheads],
421 # mapping: {'branch': ([remoteheads],
422 # [newheads],
422 # [newheads],
423 # [unsyncedheads],
423 # [unsyncedheads],
424 # [discardedheads])}
424 # [discardedheads])}
425 # - branch: the branch name
425 # - branch: the branch name
426 # - remoteheads: the list of remote heads known locally
426 # - remoteheads: the list of remote heads known locally
427 # None if the branch is new
427 # None if the branch is new
428 # - newheads: the new remote heads (known locally) with outgoing pushed
428 # - newheads: the new remote heads (known locally) with outgoing pushed
429 # - unsyncedheads: the list of remote heads unknown locally.
429 # - unsyncedheads: the list of remote heads unknown locally.
430 # - discardedheads: the list of remote heads made obsolete by the push
430 # - discardedheads: the list of remote heads made obsolete by the push
431 self.pushbranchmap = None
431 self.pushbranchmap = None
432 # testable as a boolean indicating if any nodes are missing locally.
432 # testable as a boolean indicating if any nodes are missing locally.
433 self.incoming = None
433 self.incoming = None
434 # summary of the remote phase situation
434 # summary of the remote phase situation
435 self.remotephases = None
435 self.remotephases = None
436 # phases changes that must be pushed along side the changesets
436 # phases changes that must be pushed along side the changesets
437 self.outdatedphases = None
437 self.outdatedphases = None
438 # phases changes that must be pushed if changeset push fails
438 # phases changes that must be pushed if changeset push fails
439 self.fallbackoutdatedphases = None
439 self.fallbackoutdatedphases = None
440 # outgoing obsmarkers
440 # outgoing obsmarkers
441 self.outobsmarkers = set()
441 self.outobsmarkers = set()
442 # outgoing bookmarks
442 # outgoing bookmarks
443 self.outbookmarks = []
443 self.outbookmarks = []
444 # transaction manager
444 # transaction manager
445 self.trmanager = None
445 self.trmanager = None
446 # map { pushkey partid -> callback handling failure}
446 # map { pushkey partid -> callback handling failure}
447 # used to handle exception from mandatory pushkey part failure
447 # used to handle exception from mandatory pushkey part failure
448 self.pkfailcb = {}
448 self.pkfailcb = {}
449 # an iterable of pushvars or None
449 # an iterable of pushvars or None
450 self.pushvars = pushvars
450 self.pushvars = pushvars
451 # publish pushed changesets
451 # publish pushed changesets
452 self.publish = publish
452 self.publish = publish
453
453
454 @util.propertycache
454 @util.propertycache
455 def futureheads(self):
455 def futureheads(self):
456 """future remote heads if the changeset push succeeds"""
456 """future remote heads if the changeset push succeeds"""
457 return self.outgoing.missingheads
457 return self.outgoing.missingheads
458
458
459 @util.propertycache
459 @util.propertycache
460 def fallbackheads(self):
460 def fallbackheads(self):
461 """future remote heads if the changeset push fails"""
461 """future remote heads if the changeset push fails"""
462 if self.revs is None:
462 if self.revs is None:
463 # not target to push, all common are relevant
463 # not target to push, all common are relevant
464 return self.outgoing.commonheads
464 return self.outgoing.commonheads
465 unfi = self.repo.unfiltered()
465 unfi = self.repo.unfiltered()
466 # I want cheads = heads(::missingheads and ::commonheads)
466 # I want cheads = heads(::missingheads and ::commonheads)
467 # (missingheads is revs with secret changeset filtered out)
467 # (missingheads is revs with secret changeset filtered out)
468 #
468 #
469 # This can be expressed as:
469 # This can be expressed as:
470 # cheads = ( (missingheads and ::commonheads)
470 # cheads = ( (missingheads and ::commonheads)
471 # + (commonheads and ::missingheads))"
471 # + (commonheads and ::missingheads))"
472 # )
472 # )
473 #
473 #
474 # while trying to push we already computed the following:
474 # while trying to push we already computed the following:
475 # common = (::commonheads)
475 # common = (::commonheads)
476 # missing = ((commonheads::missingheads) - commonheads)
476 # missing = ((commonheads::missingheads) - commonheads)
477 #
477 #
478 # We can pick:
478 # We can pick:
479 # * missingheads part of common (::commonheads)
479 # * missingheads part of common (::commonheads)
480 common = self.outgoing.common
480 common = self.outgoing.common
481 nm = self.repo.changelog.nodemap
481 nm = self.repo.changelog.nodemap
482 cheads = [node for node in self.revs if nm[node] in common]
482 cheads = [node for node in self.revs if nm[node] in common]
483 # and
483 # and
484 # * commonheads parents on missing
484 # * commonheads parents on missing
485 revset = unfi.set('%ln and parents(roots(%ln))',
485 revset = unfi.set('%ln and parents(roots(%ln))',
486 self.outgoing.commonheads,
486 self.outgoing.commonheads,
487 self.outgoing.missing)
487 self.outgoing.missing)
488 cheads.extend(c.node() for c in revset)
488 cheads.extend(c.node() for c in revset)
489 return cheads
489 return cheads
490
490
491 @property
491 @property
492 def commonheads(self):
492 def commonheads(self):
493 """set of all common heads after changeset bundle push"""
493 """set of all common heads after changeset bundle push"""
494 if self.cgresult:
494 if self.cgresult:
495 return self.futureheads
495 return self.futureheads
496 else:
496 else:
497 return self.fallbackheads
497 return self.fallbackheads
498
498
499 # mapping of message used when pushing bookmark
499 # mapping of message used when pushing bookmark
500 bookmsgmap = {'update': (_("updating bookmark %s\n"),
500 bookmsgmap = {'update': (_("updating bookmark %s\n"),
501 _('updating bookmark %s failed!\n')),
501 _('updating bookmark %s failed!\n')),
502 'export': (_("exporting bookmark %s\n"),
502 'export': (_("exporting bookmark %s\n"),
503 _('exporting bookmark %s failed!\n')),
503 _('exporting bookmark %s failed!\n')),
504 'delete': (_("deleting remote bookmark %s\n"),
504 'delete': (_("deleting remote bookmark %s\n"),
505 _('deleting remote bookmark %s failed!\n')),
505 _('deleting remote bookmark %s failed!\n')),
506 }
506 }
507
507
508
508
509 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=(),
509 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=(),
510 publish=False, opargs=None):
510 publish=False, opargs=None):
511 '''Push outgoing changesets (limited by revs) from a local
511 '''Push outgoing changesets (limited by revs) from a local
512 repository to remote. Return an integer:
512 repository to remote. Return an integer:
513 - None means nothing to push
513 - None means nothing to push
514 - 0 means HTTP error
514 - 0 means HTTP error
515 - 1 means we pushed and remote head count is unchanged *or*
515 - 1 means we pushed and remote head count is unchanged *or*
516 we have outgoing changesets but refused to push
516 we have outgoing changesets but refused to push
517 - other values as described by addchangegroup()
517 - other values as described by addchangegroup()
518 '''
518 '''
519 if opargs is None:
519 if opargs is None:
520 opargs = {}
520 opargs = {}
521 pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks,
521 pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks,
522 publish, **pycompat.strkwargs(opargs))
522 publish, **pycompat.strkwargs(opargs))
523 if pushop.remote.local():
523 if pushop.remote.local():
524 missing = (set(pushop.repo.requirements)
524 missing = (set(pushop.repo.requirements)
525 - pushop.remote.local().supported)
525 - pushop.remote.local().supported)
526 if missing:
526 if missing:
527 msg = _("required features are not"
527 msg = _("required features are not"
528 " supported in the destination:"
528 " supported in the destination:"
529 " %s") % (', '.join(sorted(missing)))
529 " %s") % (', '.join(sorted(missing)))
530 raise error.Abort(msg)
530 raise error.Abort(msg)
531
531
532 if not pushop.remote.canpush():
532 if not pushop.remote.canpush():
533 raise error.Abort(_("destination does not support push"))
533 raise error.Abort(_("destination does not support push"))
534
534
535 if not pushop.remote.capable('unbundle'):
535 if not pushop.remote.capable('unbundle'):
536 raise error.Abort(_('cannot push: destination does not support the '
536 raise error.Abort(_('cannot push: destination does not support the '
537 'unbundle wire protocol command'))
537 'unbundle wire protocol command'))
538
538
539 # get lock as we might write phase data
539 # get lock as we might write phase data
540 wlock = lock = None
540 wlock = lock = None
541 try:
541 try:
542 # bundle2 push may receive a reply bundle touching bookmarks or other
542 # bundle2 push may receive a reply bundle touching bookmarks or other
543 # things requiring the wlock. Take it now to ensure proper ordering.
543 # things requiring the wlock. Take it now to ensure proper ordering.
544 maypushback = pushop.ui.configbool('experimental', 'bundle2.pushback')
544 maypushback = pushop.ui.configbool('experimental', 'bundle2.pushback')
545 if (not _forcebundle1(pushop)) and maypushback:
545 if (not _forcebundle1(pushop)) and maypushback:
546 wlock = pushop.repo.wlock()
546 wlock = pushop.repo.wlock()
547 lock = pushop.repo.lock()
547 lock = pushop.repo.lock()
548 pushop.trmanager = transactionmanager(pushop.repo,
548 pushop.trmanager = transactionmanager(pushop.repo,
549 'push-response',
549 'push-response',
550 pushop.remote.url())
550 pushop.remote.url())
551 except error.LockUnavailable as err:
551 except error.LockUnavailable as err:
552 # source repo cannot be locked.
552 # source repo cannot be locked.
553 # We do not abort the push, but just disable the local phase
553 # We do not abort the push, but just disable the local phase
554 # synchronisation.
554 # synchronisation.
555 msg = ('cannot lock source repository: %s\n'
555 msg = ('cannot lock source repository: %s\n'
556 % stringutil.forcebytestr(err))
556 % stringutil.forcebytestr(err))
557 pushop.ui.debug(msg)
557 pushop.ui.debug(msg)
558
558
559 with wlock or util.nullcontextmanager():
559 with wlock or util.nullcontextmanager():
560 with lock or util.nullcontextmanager():
560 with lock or util.nullcontextmanager():
561 with pushop.trmanager or util.nullcontextmanager():
561 with pushop.trmanager or util.nullcontextmanager():
562 pushop.repo.checkpush(pushop)
562 pushop.repo.checkpush(pushop)
563 _checkpublish(pushop)
563 _checkpublish(pushop)
564 _pushdiscovery(pushop)
564 _pushdiscovery(pushop)
565 if not _forcebundle1(pushop):
565 if not _forcebundle1(pushop):
566 _pushbundle2(pushop)
566 _pushbundle2(pushop)
567 _pushchangeset(pushop)
567 _pushchangeset(pushop)
568 _pushsyncphase(pushop)
568 _pushsyncphase(pushop)
569 _pushobsolete(pushop)
569 _pushobsolete(pushop)
570 _pushbookmark(pushop)
570 _pushbookmark(pushop)
571
571
572 if repo.ui.configbool('experimental', 'remotenames'):
572 if repo.ui.configbool('experimental', 'remotenames'):
573 logexchange.pullremotenames(repo, remote)
573 logexchange.pullremotenames(repo, remote)
574
574
575 return pushop
575 return pushop
576
576
577 # list of steps to perform discovery before push
577 # list of steps to perform discovery before push
578 pushdiscoveryorder = []
578 pushdiscoveryorder = []
579
579
580 # Mapping between step name and function
580 # Mapping between step name and function
581 #
581 #
582 # This exists to help extensions wrap steps if necessary
582 # This exists to help extensions wrap steps if necessary
583 pushdiscoverymapping = {}
583 pushdiscoverymapping = {}
584
584
585 def pushdiscovery(stepname):
585 def pushdiscovery(stepname):
586 """decorator for function performing discovery before push
586 """decorator for function performing discovery before push
587
587
588 The function is added to the step -> function mapping and appended to the
588 The function is added to the step -> function mapping and appended to the
589 list of steps. Beware that decorated function will be added in order (this
589 list of steps. Beware that decorated function will be added in order (this
590 may matter).
590 may matter).
591
591
592 You can only use this decorator for a new step, if you want to wrap a step
592 You can only use this decorator for a new step, if you want to wrap a step
593 from an extension, change the pushdiscovery dictionary directly."""
593 from an extension, change the pushdiscovery dictionary directly."""
594 def dec(func):
594 def dec(func):
595 assert stepname not in pushdiscoverymapping
595 assert stepname not in pushdiscoverymapping
596 pushdiscoverymapping[stepname] = func
596 pushdiscoverymapping[stepname] = func
597 pushdiscoveryorder.append(stepname)
597 pushdiscoveryorder.append(stepname)
598 return func
598 return func
599 return dec
599 return dec
600
600
601 def _pushdiscovery(pushop):
601 def _pushdiscovery(pushop):
602 """Run all discovery steps"""
602 """Run all discovery steps"""
603 for stepname in pushdiscoveryorder:
603 for stepname in pushdiscoveryorder:
604 step = pushdiscoverymapping[stepname]
604 step = pushdiscoverymapping[stepname]
605 step(pushop)
605 step(pushop)
606
606
607 @pushdiscovery('changeset')
607 @pushdiscovery('changeset')
608 def _pushdiscoverychangeset(pushop):
608 def _pushdiscoverychangeset(pushop):
609 """discover the changeset that need to be pushed"""
609 """discover the changeset that need to be pushed"""
610 fci = discovery.findcommonincoming
610 fci = discovery.findcommonincoming
611 if pushop.revs:
611 if pushop.revs:
612 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force,
612 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force,
613 ancestorsof=pushop.revs)
613 ancestorsof=pushop.revs)
614 else:
614 else:
615 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force)
615 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force)
616 common, inc, remoteheads = commoninc
616 common, inc, remoteheads = commoninc
617 fco = discovery.findcommonoutgoing
617 fco = discovery.findcommonoutgoing
618 outgoing = fco(pushop.repo, pushop.remote, onlyheads=pushop.revs,
618 outgoing = fco(pushop.repo, pushop.remote, onlyheads=pushop.revs,
619 commoninc=commoninc, force=pushop.force)
619 commoninc=commoninc, force=pushop.force)
620 pushop.outgoing = outgoing
620 pushop.outgoing = outgoing
621 pushop.remoteheads = remoteheads
621 pushop.remoteheads = remoteheads
622 pushop.incoming = inc
622 pushop.incoming = inc
623
623
624 @pushdiscovery('phase')
624 @pushdiscovery('phase')
625 def _pushdiscoveryphase(pushop):
625 def _pushdiscoveryphase(pushop):
626 """discover the phase that needs to be pushed
626 """discover the phase that needs to be pushed
627
627
628 (computed for both success and failure case for changesets push)"""
628 (computed for both success and failure case for changesets push)"""
629 outgoing = pushop.outgoing
629 outgoing = pushop.outgoing
630 unfi = pushop.repo.unfiltered()
630 unfi = pushop.repo.unfiltered()
631 remotephases = listkeys(pushop.remote, 'phases')
631 remotephases = listkeys(pushop.remote, 'phases')
632
632
633 if (pushop.ui.configbool('ui', '_usedassubrepo')
633 if (pushop.ui.configbool('ui', '_usedassubrepo')
634 and remotephases # server supports phases
634 and remotephases # server supports phases
635 and not pushop.outgoing.missing # no changesets to be pushed
635 and not pushop.outgoing.missing # no changesets to be pushed
636 and remotephases.get('publishing', False)):
636 and remotephases.get('publishing', False)):
637 # When:
637 # When:
638 # - this is a subrepo push
638 # - this is a subrepo push
639 # - and remote support phase
639 # - and remote support phase
640 # - and no changeset are to be pushed
640 # - and no changeset are to be pushed
641 # - and remote is publishing
641 # - and remote is publishing
642 # We may be in issue 3781 case!
642 # We may be in issue 3781 case!
643 # We drop the possible phase synchronisation done by
643 # We drop the possible phase synchronisation done by
644 # courtesy to publish changesets possibly locally draft
644 # courtesy to publish changesets possibly locally draft
645 # on the remote.
645 # on the remote.
646 pushop.outdatedphases = []
646 pushop.outdatedphases = []
647 pushop.fallbackoutdatedphases = []
647 pushop.fallbackoutdatedphases = []
648 return
648 return
649
649
650 pushop.remotephases = phases.remotephasessummary(pushop.repo,
650 pushop.remotephases = phases.remotephasessummary(pushop.repo,
651 pushop.fallbackheads,
651 pushop.fallbackheads,
652 remotephases)
652 remotephases)
653 droots = pushop.remotephases.draftroots
653 droots = pushop.remotephases.draftroots
654
654
655 extracond = ''
655 extracond = ''
656 if not pushop.remotephases.publishing:
656 if not pushop.remotephases.publishing:
657 extracond = ' and public()'
657 extracond = ' and public()'
658 revset = 'heads((%%ln::%%ln) %s)' % extracond
658 revset = 'heads((%%ln::%%ln) %s)' % extracond
659 # Get the list of all revs draft on remote by public here.
659 # Get the list of all revs draft on remote by public here.
660 # XXX Beware that revset break if droots is not strictly
660 # XXX Beware that revset break if droots is not strictly
661 # XXX root we may want to ensure it is but it is costly
661 # XXX root we may want to ensure it is but it is costly
662 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
662 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
663 if not pushop.remotephases.publishing and pushop.publish:
663 if not pushop.remotephases.publishing and pushop.publish:
664 future = list(unfi.set('%ln and (not public() or %ln::)',
664 future = list(unfi.set('%ln and (not public() or %ln::)',
665 pushop.futureheads, droots))
665 pushop.futureheads, droots))
666 elif not outgoing.missing:
666 elif not outgoing.missing:
667 future = fallback
667 future = fallback
668 else:
668 else:
669 # adds changeset we are going to push as draft
669 # adds changeset we are going to push as draft
670 #
670 #
671 # should not be necessary for publishing server, but because of an
671 # should not be necessary for publishing server, but because of an
672 # issue fixed in xxxxx we have to do it anyway.
672 # issue fixed in xxxxx we have to do it anyway.
673 fdroots = list(unfi.set('roots(%ln + %ln::)',
673 fdroots = list(unfi.set('roots(%ln + %ln::)',
674 outgoing.missing, droots))
674 outgoing.missing, droots))
675 fdroots = [f.node() for f in fdroots]
675 fdroots = [f.node() for f in fdroots]
676 future = list(unfi.set(revset, fdroots, pushop.futureheads))
676 future = list(unfi.set(revset, fdroots, pushop.futureheads))
677 pushop.outdatedphases = future
677 pushop.outdatedphases = future
678 pushop.fallbackoutdatedphases = fallback
678 pushop.fallbackoutdatedphases = fallback
679
679
680 @pushdiscovery('obsmarker')
680 @pushdiscovery('obsmarker')
681 def _pushdiscoveryobsmarkers(pushop):
681 def _pushdiscoveryobsmarkers(pushop):
682 if not obsolete.isenabled(pushop.repo, obsolete.exchangeopt):
682 if not obsolete.isenabled(pushop.repo, obsolete.exchangeopt):
683 return
683 return
684
684
685 if not pushop.repo.obsstore:
685 if not pushop.repo.obsstore:
686 return
686 return
687
687
688 if 'obsolete' not in listkeys(pushop.remote, 'namespaces'):
688 if 'obsolete' not in listkeys(pushop.remote, 'namespaces'):
689 return
689 return
690
690
691 repo = pushop.repo
691 repo = pushop.repo
692 # very naive computation, that can be quite expensive on big repo.
692 # very naive computation, that can be quite expensive on big repo.
693 # However: evolution is currently slow on them anyway.
693 # However: evolution is currently slow on them anyway.
694 nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads))
694 nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads))
695 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
695 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
696
696
697 @pushdiscovery('bookmarks')
697 @pushdiscovery('bookmarks')
698 def _pushdiscoverybookmarks(pushop):
698 def _pushdiscoverybookmarks(pushop):
699 ui = pushop.ui
699 ui = pushop.ui
700 repo = pushop.repo.unfiltered()
700 repo = pushop.repo.unfiltered()
701 remote = pushop.remote
701 remote = pushop.remote
702 ui.debug("checking for updated bookmarks\n")
702 ui.debug("checking for updated bookmarks\n")
703 ancestors = ()
703 ancestors = ()
704 if pushop.revs:
704 if pushop.revs:
705 revnums = pycompat.maplist(repo.changelog.rev, pushop.revs)
705 revnums = pycompat.maplist(repo.changelog.rev, pushop.revs)
706 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
706 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
707
707
708 remotebookmark = listkeys(remote, 'bookmarks')
708 remotebookmark = listkeys(remote, 'bookmarks')
709
709
710 explicit = {repo._bookmarks.expandname(bookmark)
710 explicit = {repo._bookmarks.expandname(bookmark)
711 for bookmark in pushop.bookmarks}
711 for bookmark in pushop.bookmarks}
712
712
713 remotebookmark = bookmod.unhexlifybookmarks(remotebookmark)
713 remotebookmark = bookmod.unhexlifybookmarks(remotebookmark)
714 comp = bookmod.comparebookmarks(repo, repo._bookmarks, remotebookmark)
714 comp = bookmod.comparebookmarks(repo, repo._bookmarks, remotebookmark)
715
715
716 def safehex(x):
716 def safehex(x):
717 if x is None:
717 if x is None:
718 return x
718 return x
719 return hex(x)
719 return hex(x)
720
720
721 def hexifycompbookmarks(bookmarks):
721 def hexifycompbookmarks(bookmarks):
722 return [(b, safehex(scid), safehex(dcid))
722 return [(b, safehex(scid), safehex(dcid))
723 for (b, scid, dcid) in bookmarks]
723 for (b, scid, dcid) in bookmarks]
724
724
725 comp = [hexifycompbookmarks(marks) for marks in comp]
725 comp = [hexifycompbookmarks(marks) for marks in comp]
726 return _processcompared(pushop, ancestors, explicit, remotebookmark, comp)
726 return _processcompared(pushop, ancestors, explicit, remotebookmark, comp)
727
727
728 def _processcompared(pushop, pushed, explicit, remotebms, comp):
728 def _processcompared(pushop, pushed, explicit, remotebms, comp):
729 """take decision on bookmark to pull from the remote bookmark
729 """take decision on bookmark to pull from the remote bookmark
730
730
731 Exist to help extensions who want to alter this behavior.
731 Exist to help extensions who want to alter this behavior.
732 """
732 """
733 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp
733 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp
734
734
735 repo = pushop.repo
735 repo = pushop.repo
736
736
737 for b, scid, dcid in advsrc:
737 for b, scid, dcid in advsrc:
738 if b in explicit:
738 if b in explicit:
739 explicit.remove(b)
739 explicit.remove(b)
740 if not pushed or repo[scid].rev() in pushed:
740 if not pushed or repo[scid].rev() in pushed:
741 pushop.outbookmarks.append((b, dcid, scid))
741 pushop.outbookmarks.append((b, dcid, scid))
742 # search added bookmark
742 # search added bookmark
743 for b, scid, dcid in addsrc:
743 for b, scid, dcid in addsrc:
744 if b in explicit:
744 if b in explicit:
745 explicit.remove(b)
745 explicit.remove(b)
746 pushop.outbookmarks.append((b, '', scid))
746 pushop.outbookmarks.append((b, '', scid))
747 # search for overwritten bookmark
747 # search for overwritten bookmark
748 for b, scid, dcid in list(advdst) + list(diverge) + list(differ):
748 for b, scid, dcid in list(advdst) + list(diverge) + list(differ):
749 if b in explicit:
749 if b in explicit:
750 explicit.remove(b)
750 explicit.remove(b)
751 pushop.outbookmarks.append((b, dcid, scid))
751 pushop.outbookmarks.append((b, dcid, scid))
752 # search for bookmark to delete
752 # search for bookmark to delete
753 for b, scid, dcid in adddst:
753 for b, scid, dcid in adddst:
754 if b in explicit:
754 if b in explicit:
755 explicit.remove(b)
755 explicit.remove(b)
756 # treat as "deleted locally"
756 # treat as "deleted locally"
757 pushop.outbookmarks.append((b, dcid, ''))
757 pushop.outbookmarks.append((b, dcid, ''))
758 # identical bookmarks shouldn't get reported
758 # identical bookmarks shouldn't get reported
759 for b, scid, dcid in same:
759 for b, scid, dcid in same:
760 if b in explicit:
760 if b in explicit:
761 explicit.remove(b)
761 explicit.remove(b)
762
762
763 if explicit:
763 if explicit:
764 explicit = sorted(explicit)
764 explicit = sorted(explicit)
765 # we should probably list all of them
765 # we should probably list all of them
766 pushop.ui.warn(_('bookmark %s does not exist on the local '
766 pushop.ui.warn(_('bookmark %s does not exist on the local '
767 'or remote repository!\n') % explicit[0])
767 'or remote repository!\n') % explicit[0])
768 pushop.bkresult = 2
768 pushop.bkresult = 2
769
769
770 pushop.outbookmarks.sort()
770 pushop.outbookmarks.sort()
771
771
772 def _pushcheckoutgoing(pushop):
772 def _pushcheckoutgoing(pushop):
773 outgoing = pushop.outgoing
773 outgoing = pushop.outgoing
774 unfi = pushop.repo.unfiltered()
774 unfi = pushop.repo.unfiltered()
775 if not outgoing.missing:
775 if not outgoing.missing:
776 # nothing to push
776 # nothing to push
777 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
777 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
778 return False
778 return False
779 # something to push
779 # something to push
780 if not pushop.force:
780 if not pushop.force:
781 # if repo.obsstore == False --> no obsolete
781 # if repo.obsstore == False --> no obsolete
782 # then, save the iteration
782 # then, save the iteration
783 if unfi.obsstore:
783 if unfi.obsstore:
784 # this message are here for 80 char limit reason
784 # this message are here for 80 char limit reason
785 mso = _("push includes obsolete changeset: %s!")
785 mso = _("push includes obsolete changeset: %s!")
786 mspd = _("push includes phase-divergent changeset: %s!")
786 mspd = _("push includes phase-divergent changeset: %s!")
787 mscd = _("push includes content-divergent changeset: %s!")
787 mscd = _("push includes content-divergent changeset: %s!")
788 mst = {"orphan": _("push includes orphan changeset: %s!"),
788 mst = {"orphan": _("push includes orphan changeset: %s!"),
789 "phase-divergent": mspd,
789 "phase-divergent": mspd,
790 "content-divergent": mscd}
790 "content-divergent": mscd}
791 # If we are to push if there is at least one
791 # If we are to push if there is at least one
792 # obsolete or unstable changeset in missing, at
792 # obsolete or unstable changeset in missing, at
793 # least one of the missinghead will be obsolete or
793 # least one of the missinghead will be obsolete or
794 # unstable. So checking heads only is ok
794 # unstable. So checking heads only is ok
795 for node in outgoing.missingheads:
795 for node in outgoing.missingheads:
796 ctx = unfi[node]
796 ctx = unfi[node]
797 if ctx.obsolete():
797 if ctx.obsolete():
798 raise error.Abort(mso % ctx)
798 raise error.Abort(mso % ctx)
799 elif ctx.isunstable():
799 elif ctx.isunstable():
800 # TODO print more than one instability in the abort
800 # TODO print more than one instability in the abort
801 # message
801 # message
802 raise error.Abort(mst[ctx.instabilities()[0]] % ctx)
802 raise error.Abort(mst[ctx.instabilities()[0]] % ctx)
803
803
804 discovery.checkheads(pushop)
804 discovery.checkheads(pushop)
805 return True
805 return True
806
806
807 # List of names of steps to perform for an outgoing bundle2, order matters.
807 # List of names of steps to perform for an outgoing bundle2, order matters.
808 b2partsgenorder = []
808 b2partsgenorder = []
809
809
810 # Mapping between step name and function
810 # Mapping between step name and function
811 #
811 #
812 # This exists to help extensions wrap steps if necessary
812 # This exists to help extensions wrap steps if necessary
813 b2partsgenmapping = {}
813 b2partsgenmapping = {}
814
814
815 def b2partsgenerator(stepname, idx=None):
815 def b2partsgenerator(stepname, idx=None):
816 """decorator for function generating bundle2 part
816 """decorator for function generating bundle2 part
817
817
818 The function is added to the step -> function mapping and appended to the
818 The function is added to the step -> function mapping and appended to the
819 list of steps. Beware that decorated functions will be added in order
819 list of steps. Beware that decorated functions will be added in order
820 (this may matter).
820 (this may matter).
821
821
822 You can only use this decorator for new steps, if you want to wrap a step
822 You can only use this decorator for new steps, if you want to wrap a step
823 from an extension, attack the b2partsgenmapping dictionary directly."""
823 from an extension, attack the b2partsgenmapping dictionary directly."""
824 def dec(func):
824 def dec(func):
825 assert stepname not in b2partsgenmapping
825 assert stepname not in b2partsgenmapping
826 b2partsgenmapping[stepname] = func
826 b2partsgenmapping[stepname] = func
827 if idx is None:
827 if idx is None:
828 b2partsgenorder.append(stepname)
828 b2partsgenorder.append(stepname)
829 else:
829 else:
830 b2partsgenorder.insert(idx, stepname)
830 b2partsgenorder.insert(idx, stepname)
831 return func
831 return func
832 return dec
832 return dec
833
833
834 def _pushb2ctxcheckheads(pushop, bundler):
834 def _pushb2ctxcheckheads(pushop, bundler):
835 """Generate race condition checking parts
835 """Generate race condition checking parts
836
836
837 Exists as an independent function to aid extensions
837 Exists as an independent function to aid extensions
838 """
838 """
839 # * 'force' do not check for push race,
839 # * 'force' do not check for push race,
840 # * if we don't push anything, there are nothing to check.
840 # * if we don't push anything, there are nothing to check.
841 if not pushop.force and pushop.outgoing.missingheads:
841 if not pushop.force and pushop.outgoing.missingheads:
842 allowunrelated = 'related' in bundler.capabilities.get('checkheads', ())
842 allowunrelated = 'related' in bundler.capabilities.get('checkheads', ())
843 emptyremote = pushop.pushbranchmap is None
843 emptyremote = pushop.pushbranchmap is None
844 if not allowunrelated or emptyremote:
844 if not allowunrelated or emptyremote:
845 bundler.newpart('check:heads', data=iter(pushop.remoteheads))
845 bundler.newpart('check:heads', data=iter(pushop.remoteheads))
846 else:
846 else:
847 affected = set()
847 affected = set()
848 for branch, heads in pushop.pushbranchmap.iteritems():
848 for branch, heads in pushop.pushbranchmap.iteritems():
849 remoteheads, newheads, unsyncedheads, discardedheads = heads
849 remoteheads, newheads, unsyncedheads, discardedheads = heads
850 if remoteheads is not None:
850 if remoteheads is not None:
851 remote = set(remoteheads)
851 remote = set(remoteheads)
852 affected |= set(discardedheads) & remote
852 affected |= set(discardedheads) & remote
853 affected |= remote - set(newheads)
853 affected |= remote - set(newheads)
854 if affected:
854 if affected:
855 data = iter(sorted(affected))
855 data = iter(sorted(affected))
856 bundler.newpart('check:updated-heads', data=data)
856 bundler.newpart('check:updated-heads', data=data)
857
857
858 def _pushing(pushop):
858 def _pushing(pushop):
859 """return True if we are pushing anything"""
859 """return True if we are pushing anything"""
860 return bool(pushop.outgoing.missing
860 return bool(pushop.outgoing.missing
861 or pushop.outdatedphases
861 or pushop.outdatedphases
862 or pushop.outobsmarkers
862 or pushop.outobsmarkers
863 or pushop.outbookmarks)
863 or pushop.outbookmarks)
864
864
865 @b2partsgenerator('check-bookmarks')
865 @b2partsgenerator('check-bookmarks')
866 def _pushb2checkbookmarks(pushop, bundler):
866 def _pushb2checkbookmarks(pushop, bundler):
867 """insert bookmark move checking"""
867 """insert bookmark move checking"""
868 if not _pushing(pushop) or pushop.force:
868 if not _pushing(pushop) or pushop.force:
869 return
869 return
870 b2caps = bundle2.bundle2caps(pushop.remote)
870 b2caps = bundle2.bundle2caps(pushop.remote)
871 hasbookmarkcheck = 'bookmarks' in b2caps
871 hasbookmarkcheck = 'bookmarks' in b2caps
872 if not (pushop.outbookmarks and hasbookmarkcheck):
872 if not (pushop.outbookmarks and hasbookmarkcheck):
873 return
873 return
874 data = []
874 data = []
875 for book, old, new in pushop.outbookmarks:
875 for book, old, new in pushop.outbookmarks:
876 old = bin(old)
876 old = bin(old)
877 data.append((book, old))
877 data.append((book, old))
878 checkdata = bookmod.binaryencode(data)
878 checkdata = bookmod.binaryencode(data)
879 bundler.newpart('check:bookmarks', data=checkdata)
879 bundler.newpart('check:bookmarks', data=checkdata)
880
880
881 @b2partsgenerator('check-phases')
881 @b2partsgenerator('check-phases')
882 def _pushb2checkphases(pushop, bundler):
882 def _pushb2checkphases(pushop, bundler):
883 """insert phase move checking"""
883 """insert phase move checking"""
884 if not _pushing(pushop) or pushop.force:
884 if not _pushing(pushop) or pushop.force:
885 return
885 return
886 b2caps = bundle2.bundle2caps(pushop.remote)
886 b2caps = bundle2.bundle2caps(pushop.remote)
887 hasphaseheads = 'heads' in b2caps.get('phases', ())
887 hasphaseheads = 'heads' in b2caps.get('phases', ())
888 if pushop.remotephases is not None and hasphaseheads:
888 if pushop.remotephases is not None and hasphaseheads:
889 # check that the remote phase has not changed
889 # check that the remote phase has not changed
890 checks = [[] for p in phases.allphases]
890 checks = [[] for p in phases.allphases]
891 checks[phases.public].extend(pushop.remotephases.publicheads)
891 checks[phases.public].extend(pushop.remotephases.publicheads)
892 checks[phases.draft].extend(pushop.remotephases.draftroots)
892 checks[phases.draft].extend(pushop.remotephases.draftroots)
893 if any(checks):
893 if any(checks):
894 for nodes in checks:
894 for nodes in checks:
895 nodes.sort()
895 nodes.sort()
896 checkdata = phases.binaryencode(checks)
896 checkdata = phases.binaryencode(checks)
897 bundler.newpart('check:phases', data=checkdata)
897 bundler.newpart('check:phases', data=checkdata)
898
898
899 @b2partsgenerator('changeset')
899 @b2partsgenerator('changeset')
900 def _pushb2ctx(pushop, bundler):
900 def _pushb2ctx(pushop, bundler):
901 """handle changegroup push through bundle2
901 """handle changegroup push through bundle2
902
902
903 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
903 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
904 """
904 """
905 if 'changesets' in pushop.stepsdone:
905 if 'changesets' in pushop.stepsdone:
906 return
906 return
907 pushop.stepsdone.add('changesets')
907 pushop.stepsdone.add('changesets')
908 # Send known heads to the server for race detection.
908 # Send known heads to the server for race detection.
909 if not _pushcheckoutgoing(pushop):
909 if not _pushcheckoutgoing(pushop):
910 return
910 return
911 pushop.repo.prepushoutgoinghooks(pushop)
911 pushop.repo.prepushoutgoinghooks(pushop)
912
912
913 _pushb2ctxcheckheads(pushop, bundler)
913 _pushb2ctxcheckheads(pushop, bundler)
914
914
915 b2caps = bundle2.bundle2caps(pushop.remote)
915 b2caps = bundle2.bundle2caps(pushop.remote)
916 version = '01'
916 version = '01'
917 cgversions = b2caps.get('changegroup')
917 cgversions = b2caps.get('changegroup')
918 if cgversions: # 3.1 and 3.2 ship with an empty value
918 if cgversions: # 3.1 and 3.2 ship with an empty value
919 cgversions = [v for v in cgversions
919 cgversions = [v for v in cgversions
920 if v in changegroup.supportedoutgoingversions(
920 if v in changegroup.supportedoutgoingversions(
921 pushop.repo)]
921 pushop.repo)]
922 if not cgversions:
922 if not cgversions:
923 raise error.Abort(_('no common changegroup version'))
923 raise error.Abort(_('no common changegroup version'))
924 version = max(cgversions)
924 version = max(cgversions)
925 cgstream = changegroup.makestream(pushop.repo, pushop.outgoing, version,
925 cgstream = changegroup.makestream(pushop.repo, pushop.outgoing, version,
926 'push')
926 'push')
927 cgpart = bundler.newpart('changegroup', data=cgstream)
927 cgpart = bundler.newpart('changegroup', data=cgstream)
928 if cgversions:
928 if cgversions:
929 cgpart.addparam('version', version)
929 cgpart.addparam('version', version)
930 if 'treemanifest' in pushop.repo.requirements:
930 if 'treemanifest' in pushop.repo.requirements:
931 cgpart.addparam('treemanifest', '1')
931 cgpart.addparam('treemanifest', '1')
932 def handlereply(op):
932 def handlereply(op):
933 """extract addchangegroup returns from server reply"""
933 """extract addchangegroup returns from server reply"""
934 cgreplies = op.records.getreplies(cgpart.id)
934 cgreplies = op.records.getreplies(cgpart.id)
935 assert len(cgreplies['changegroup']) == 1
935 assert len(cgreplies['changegroup']) == 1
936 pushop.cgresult = cgreplies['changegroup'][0]['return']
936 pushop.cgresult = cgreplies['changegroup'][0]['return']
937 return handlereply
937 return handlereply
938
938
939 @b2partsgenerator('phase')
939 @b2partsgenerator('phase')
940 def _pushb2phases(pushop, bundler):
940 def _pushb2phases(pushop, bundler):
941 """handle phase push through bundle2"""
941 """handle phase push through bundle2"""
942 if 'phases' in pushop.stepsdone:
942 if 'phases' in pushop.stepsdone:
943 return
943 return
944 b2caps = bundle2.bundle2caps(pushop.remote)
944 b2caps = bundle2.bundle2caps(pushop.remote)
945 ui = pushop.repo.ui
945 ui = pushop.repo.ui
946
946
947 legacyphase = 'phases' in ui.configlist('devel', 'legacy.exchange')
947 legacyphase = 'phases' in ui.configlist('devel', 'legacy.exchange')
948 haspushkey = 'pushkey' in b2caps
948 haspushkey = 'pushkey' in b2caps
949 hasphaseheads = 'heads' in b2caps.get('phases', ())
949 hasphaseheads = 'heads' in b2caps.get('phases', ())
950
950
951 if hasphaseheads and not legacyphase:
951 if hasphaseheads and not legacyphase:
952 return _pushb2phaseheads(pushop, bundler)
952 return _pushb2phaseheads(pushop, bundler)
953 elif haspushkey:
953 elif haspushkey:
954 return _pushb2phasespushkey(pushop, bundler)
954 return _pushb2phasespushkey(pushop, bundler)
955
955
956 def _pushb2phaseheads(pushop, bundler):
956 def _pushb2phaseheads(pushop, bundler):
957 """push phase information through a bundle2 - binary part"""
957 """push phase information through a bundle2 - binary part"""
958 pushop.stepsdone.add('phases')
958 pushop.stepsdone.add('phases')
959 if pushop.outdatedphases:
959 if pushop.outdatedphases:
960 updates = [[] for p in phases.allphases]
960 updates = [[] for p in phases.allphases]
961 updates[0].extend(h.node() for h in pushop.outdatedphases)
961 updates[0].extend(h.node() for h in pushop.outdatedphases)
962 phasedata = phases.binaryencode(updates)
962 phasedata = phases.binaryencode(updates)
963 bundler.newpart('phase-heads', data=phasedata)
963 bundler.newpart('phase-heads', data=phasedata)
964
964
965 def _pushb2phasespushkey(pushop, bundler):
965 def _pushb2phasespushkey(pushop, bundler):
966 """push phase information through a bundle2 - pushkey part"""
966 """push phase information through a bundle2 - pushkey part"""
967 pushop.stepsdone.add('phases')
967 pushop.stepsdone.add('phases')
968 part2node = []
968 part2node = []
969
969
970 def handlefailure(pushop, exc):
970 def handlefailure(pushop, exc):
971 targetid = int(exc.partid)
971 targetid = int(exc.partid)
972 for partid, node in part2node:
972 for partid, node in part2node:
973 if partid == targetid:
973 if partid == targetid:
974 raise error.Abort(_('updating %s to public failed') % node)
974 raise error.Abort(_('updating %s to public failed') % node)
975
975
976 enc = pushkey.encode
976 enc = pushkey.encode
977 for newremotehead in pushop.outdatedphases:
977 for newremotehead in pushop.outdatedphases:
978 part = bundler.newpart('pushkey')
978 part = bundler.newpart('pushkey')
979 part.addparam('namespace', enc('phases'))
979 part.addparam('namespace', enc('phases'))
980 part.addparam('key', enc(newremotehead.hex()))
980 part.addparam('key', enc(newremotehead.hex()))
981 part.addparam('old', enc('%d' % phases.draft))
981 part.addparam('old', enc('%d' % phases.draft))
982 part.addparam('new', enc('%d' % phases.public))
982 part.addparam('new', enc('%d' % phases.public))
983 part2node.append((part.id, newremotehead))
983 part2node.append((part.id, newremotehead))
984 pushop.pkfailcb[part.id] = handlefailure
984 pushop.pkfailcb[part.id] = handlefailure
985
985
986 def handlereply(op):
986 def handlereply(op):
987 for partid, node in part2node:
987 for partid, node in part2node:
988 partrep = op.records.getreplies(partid)
988 partrep = op.records.getreplies(partid)
989 results = partrep['pushkey']
989 results = partrep['pushkey']
990 assert len(results) <= 1
990 assert len(results) <= 1
991 msg = None
991 msg = None
992 if not results:
992 if not results:
993 msg = _('server ignored update of %s to public!\n') % node
993 msg = _('server ignored update of %s to public!\n') % node
994 elif not int(results[0]['return']):
994 elif not int(results[0]['return']):
995 msg = _('updating %s to public failed!\n') % node
995 msg = _('updating %s to public failed!\n') % node
996 if msg is not None:
996 if msg is not None:
997 pushop.ui.warn(msg)
997 pushop.ui.warn(msg)
998 return handlereply
998 return handlereply
999
999
1000 @b2partsgenerator('obsmarkers')
1000 @b2partsgenerator('obsmarkers')
1001 def _pushb2obsmarkers(pushop, bundler):
1001 def _pushb2obsmarkers(pushop, bundler):
1002 if 'obsmarkers' in pushop.stepsdone:
1002 if 'obsmarkers' in pushop.stepsdone:
1003 return
1003 return
1004 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
1004 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
1005 if obsolete.commonversion(remoteversions) is None:
1005 if obsolete.commonversion(remoteversions) is None:
1006 return
1006 return
1007 pushop.stepsdone.add('obsmarkers')
1007 pushop.stepsdone.add('obsmarkers')
1008 if pushop.outobsmarkers:
1008 if pushop.outobsmarkers:
1009 markers = sorted(pushop.outobsmarkers)
1009 markers = sorted(pushop.outobsmarkers)
1010 bundle2.buildobsmarkerspart(bundler, markers)
1010 bundle2.buildobsmarkerspart(bundler, markers)
1011
1011
1012 @b2partsgenerator('bookmarks')
1012 @b2partsgenerator('bookmarks')
1013 def _pushb2bookmarks(pushop, bundler):
1013 def _pushb2bookmarks(pushop, bundler):
1014 """handle bookmark push through bundle2"""
1014 """handle bookmark push through bundle2"""
1015 if 'bookmarks' in pushop.stepsdone:
1015 if 'bookmarks' in pushop.stepsdone:
1016 return
1016 return
1017 b2caps = bundle2.bundle2caps(pushop.remote)
1017 b2caps = bundle2.bundle2caps(pushop.remote)
1018
1018
1019 legacy = pushop.repo.ui.configlist('devel', 'legacy.exchange')
1019 legacy = pushop.repo.ui.configlist('devel', 'legacy.exchange')
1020 legacybooks = 'bookmarks' in legacy
1020 legacybooks = 'bookmarks' in legacy
1021
1021
1022 if not legacybooks and 'bookmarks' in b2caps:
1022 if not legacybooks and 'bookmarks' in b2caps:
1023 return _pushb2bookmarkspart(pushop, bundler)
1023 return _pushb2bookmarkspart(pushop, bundler)
1024 elif 'pushkey' in b2caps:
1024 elif 'pushkey' in b2caps:
1025 return _pushb2bookmarkspushkey(pushop, bundler)
1025 return _pushb2bookmarkspushkey(pushop, bundler)
1026
1026
1027 def _bmaction(old, new):
1027 def _bmaction(old, new):
1028 """small utility for bookmark pushing"""
1028 """small utility for bookmark pushing"""
1029 if not old:
1029 if not old:
1030 return 'export'
1030 return 'export'
1031 elif not new:
1031 elif not new:
1032 return 'delete'
1032 return 'delete'
1033 return 'update'
1033 return 'update'
1034
1034
1035 def _pushb2bookmarkspart(pushop, bundler):
1035 def _pushb2bookmarkspart(pushop, bundler):
1036 pushop.stepsdone.add('bookmarks')
1036 pushop.stepsdone.add('bookmarks')
1037 if not pushop.outbookmarks:
1037 if not pushop.outbookmarks:
1038 return
1038 return
1039
1039
1040 allactions = []
1040 allactions = []
1041 data = []
1041 data = []
1042 for book, old, new in pushop.outbookmarks:
1042 for book, old, new in pushop.outbookmarks:
1043 new = bin(new)
1043 new = bin(new)
1044 data.append((book, new))
1044 data.append((book, new))
1045 allactions.append((book, _bmaction(old, new)))
1045 allactions.append((book, _bmaction(old, new)))
1046 checkdata = bookmod.binaryencode(data)
1046 checkdata = bookmod.binaryencode(data)
1047 bundler.newpart('bookmarks', data=checkdata)
1047 bundler.newpart('bookmarks', data=checkdata)
1048
1048
1049 def handlereply(op):
1049 def handlereply(op):
1050 ui = pushop.ui
1050 ui = pushop.ui
1051 # if success
1051 # if success
1052 for book, action in allactions:
1052 for book, action in allactions:
1053 ui.status(bookmsgmap[action][0] % book)
1053 ui.status(bookmsgmap[action][0] % book)
1054
1054
1055 return handlereply
1055 return handlereply
1056
1056
1057 def _pushb2bookmarkspushkey(pushop, bundler):
1057 def _pushb2bookmarkspushkey(pushop, bundler):
1058 pushop.stepsdone.add('bookmarks')
1058 pushop.stepsdone.add('bookmarks')
1059 part2book = []
1059 part2book = []
1060 enc = pushkey.encode
1060 enc = pushkey.encode
1061
1061
1062 def handlefailure(pushop, exc):
1062 def handlefailure(pushop, exc):
1063 targetid = int(exc.partid)
1063 targetid = int(exc.partid)
1064 for partid, book, action in part2book:
1064 for partid, book, action in part2book:
1065 if partid == targetid:
1065 if partid == targetid:
1066 raise error.Abort(bookmsgmap[action][1].rstrip() % book)
1066 raise error.Abort(bookmsgmap[action][1].rstrip() % book)
1067 # we should not be called for part we did not generated
1067 # we should not be called for part we did not generated
1068 assert False
1068 assert False
1069
1069
1070 for book, old, new in pushop.outbookmarks:
1070 for book, old, new in pushop.outbookmarks:
1071 part = bundler.newpart('pushkey')
1071 part = bundler.newpart('pushkey')
1072 part.addparam('namespace', enc('bookmarks'))
1072 part.addparam('namespace', enc('bookmarks'))
1073 part.addparam('key', enc(book))
1073 part.addparam('key', enc(book))
1074 part.addparam('old', enc(old))
1074 part.addparam('old', enc(old))
1075 part.addparam('new', enc(new))
1075 part.addparam('new', enc(new))
1076 action = 'update'
1076 action = 'update'
1077 if not old:
1077 if not old:
1078 action = 'export'
1078 action = 'export'
1079 elif not new:
1079 elif not new:
1080 action = 'delete'
1080 action = 'delete'
1081 part2book.append((part.id, book, action))
1081 part2book.append((part.id, book, action))
1082 pushop.pkfailcb[part.id] = handlefailure
1082 pushop.pkfailcb[part.id] = handlefailure
1083
1083
1084 def handlereply(op):
1084 def handlereply(op):
1085 ui = pushop.ui
1085 ui = pushop.ui
1086 for partid, book, action in part2book:
1086 for partid, book, action in part2book:
1087 partrep = op.records.getreplies(partid)
1087 partrep = op.records.getreplies(partid)
1088 results = partrep['pushkey']
1088 results = partrep['pushkey']
1089 assert len(results) <= 1
1089 assert len(results) <= 1
1090 if not results:
1090 if not results:
1091 pushop.ui.warn(_('server ignored bookmark %s update\n') % book)
1091 pushop.ui.warn(_('server ignored bookmark %s update\n') % book)
1092 else:
1092 else:
1093 ret = int(results[0]['return'])
1093 ret = int(results[0]['return'])
1094 if ret:
1094 if ret:
1095 ui.status(bookmsgmap[action][0] % book)
1095 ui.status(bookmsgmap[action][0] % book)
1096 else:
1096 else:
1097 ui.warn(bookmsgmap[action][1] % book)
1097 ui.warn(bookmsgmap[action][1] % book)
1098 if pushop.bkresult is not None:
1098 if pushop.bkresult is not None:
1099 pushop.bkresult = 1
1099 pushop.bkresult = 1
1100 return handlereply
1100 return handlereply
1101
1101
1102 @b2partsgenerator('pushvars', idx=0)
1102 @b2partsgenerator('pushvars', idx=0)
1103 def _getbundlesendvars(pushop, bundler):
1103 def _getbundlesendvars(pushop, bundler):
1104 '''send shellvars via bundle2'''
1104 '''send shellvars via bundle2'''
1105 pushvars = pushop.pushvars
1105 pushvars = pushop.pushvars
1106 if pushvars:
1106 if pushvars:
1107 shellvars = {}
1107 shellvars = {}
1108 for raw in pushvars:
1108 for raw in pushvars:
1109 if '=' not in raw:
1109 if '=' not in raw:
1110 msg = ("unable to parse variable '%s', should follow "
1110 msg = ("unable to parse variable '%s', should follow "
1111 "'KEY=VALUE' or 'KEY=' format")
1111 "'KEY=VALUE' or 'KEY=' format")
1112 raise error.Abort(msg % raw)
1112 raise error.Abort(msg % raw)
1113 k, v = raw.split('=', 1)
1113 k, v = raw.split('=', 1)
1114 shellvars[k] = v
1114 shellvars[k] = v
1115
1115
1116 part = bundler.newpart('pushvars')
1116 part = bundler.newpart('pushvars')
1117
1117
1118 for key, value in shellvars.iteritems():
1118 for key, value in shellvars.iteritems():
1119 part.addparam(key, value, mandatory=False)
1119 part.addparam(key, value, mandatory=False)
1120
1120
1121 def _pushbundle2(pushop):
1121 def _pushbundle2(pushop):
1122 """push data to the remote using bundle2
1122 """push data to the remote using bundle2
1123
1123
1124 The only currently supported type of data is changegroup but this will
1124 The only currently supported type of data is changegroup but this will
1125 evolve in the future."""
1125 evolve in the future."""
1126 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
1126 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
1127 pushback = (pushop.trmanager
1127 pushback = (pushop.trmanager
1128 and pushop.ui.configbool('experimental', 'bundle2.pushback'))
1128 and pushop.ui.configbool('experimental', 'bundle2.pushback'))
1129
1129
1130 # create reply capability
1130 # create reply capability
1131 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo,
1131 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo,
1132 allowpushback=pushback,
1132 allowpushback=pushback,
1133 role='client'))
1133 role='client'))
1134 bundler.newpart('replycaps', data=capsblob)
1134 bundler.newpart('replycaps', data=capsblob)
1135 replyhandlers = []
1135 replyhandlers = []
1136 for partgenname in b2partsgenorder:
1136 for partgenname in b2partsgenorder:
1137 partgen = b2partsgenmapping[partgenname]
1137 partgen = b2partsgenmapping[partgenname]
1138 ret = partgen(pushop, bundler)
1138 ret = partgen(pushop, bundler)
1139 if callable(ret):
1139 if callable(ret):
1140 replyhandlers.append(ret)
1140 replyhandlers.append(ret)
1141 # do not push if nothing to push
1141 # do not push if nothing to push
1142 if bundler.nbparts <= 1:
1142 if bundler.nbparts <= 1:
1143 return
1143 return
1144 stream = util.chunkbuffer(bundler.getchunks())
1144 stream = util.chunkbuffer(bundler.getchunks())
1145 try:
1145 try:
1146 try:
1146 try:
1147 with pushop.remote.commandexecutor() as e:
1147 with pushop.remote.commandexecutor() as e:
1148 reply = e.callcommand('unbundle', {
1148 reply = e.callcommand('unbundle', {
1149 'bundle': stream,
1149 'bundle': stream,
1150 'heads': ['force'],
1150 'heads': ['force'],
1151 'url': pushop.remote.url(),
1151 'url': pushop.remote.url(),
1152 }).result()
1152 }).result()
1153 except error.BundleValueError as exc:
1153 except error.BundleValueError as exc:
1154 raise error.Abort(_('missing support for %s') % exc)
1154 raise error.Abort(_('missing support for %s') % exc)
1155 try:
1155 try:
1156 trgetter = None
1156 trgetter = None
1157 if pushback:
1157 if pushback:
1158 trgetter = pushop.trmanager.transaction
1158 trgetter = pushop.trmanager.transaction
1159 op = bundle2.processbundle(pushop.repo, reply, trgetter)
1159 op = bundle2.processbundle(pushop.repo, reply, trgetter)
1160 except error.BundleValueError as exc:
1160 except error.BundleValueError as exc:
1161 raise error.Abort(_('missing support for %s') % exc)
1161 raise error.Abort(_('missing support for %s') % exc)
1162 except bundle2.AbortFromPart as exc:
1162 except bundle2.AbortFromPart as exc:
1163 pushop.ui.status(_('remote: %s\n') % exc)
1163 pushop.ui.status(_('remote: %s\n') % exc)
1164 if exc.hint is not None:
1164 if exc.hint is not None:
1165 pushop.ui.status(_('remote: %s\n') % ('(%s)' % exc.hint))
1165 pushop.ui.status(_('remote: %s\n') % ('(%s)' % exc.hint))
1166 raise error.Abort(_('push failed on remote'))
1166 raise error.Abort(_('push failed on remote'))
1167 except error.PushkeyFailed as exc:
1167 except error.PushkeyFailed as exc:
1168 partid = int(exc.partid)
1168 partid = int(exc.partid)
1169 if partid not in pushop.pkfailcb:
1169 if partid not in pushop.pkfailcb:
1170 raise
1170 raise
1171 pushop.pkfailcb[partid](pushop, exc)
1171 pushop.pkfailcb[partid](pushop, exc)
1172 for rephand in replyhandlers:
1172 for rephand in replyhandlers:
1173 rephand(op)
1173 rephand(op)
1174
1174
1175 def _pushchangeset(pushop):
1175 def _pushchangeset(pushop):
1176 """Make the actual push of changeset bundle to remote repo"""
1176 """Make the actual push of changeset bundle to remote repo"""
1177 if 'changesets' in pushop.stepsdone:
1177 if 'changesets' in pushop.stepsdone:
1178 return
1178 return
1179 pushop.stepsdone.add('changesets')
1179 pushop.stepsdone.add('changesets')
1180 if not _pushcheckoutgoing(pushop):
1180 if not _pushcheckoutgoing(pushop):
1181 return
1181 return
1182
1182
1183 # Should have verified this in push().
1183 # Should have verified this in push().
1184 assert pushop.remote.capable('unbundle')
1184 assert pushop.remote.capable('unbundle')
1185
1185
1186 pushop.repo.prepushoutgoinghooks(pushop)
1186 pushop.repo.prepushoutgoinghooks(pushop)
1187 outgoing = pushop.outgoing
1187 outgoing = pushop.outgoing
1188 # TODO: get bundlecaps from remote
1188 # TODO: get bundlecaps from remote
1189 bundlecaps = None
1189 bundlecaps = None
1190 # create a changegroup from local
1190 # create a changegroup from local
1191 if pushop.revs is None and not (outgoing.excluded
1191 if pushop.revs is None and not (outgoing.excluded
1192 or pushop.repo.changelog.filteredrevs):
1192 or pushop.repo.changelog.filteredrevs):
1193 # push everything,
1193 # push everything,
1194 # use the fast path, no race possible on push
1194 # use the fast path, no race possible on push
1195 cg = changegroup.makechangegroup(pushop.repo, outgoing, '01', 'push',
1195 cg = changegroup.makechangegroup(pushop.repo, outgoing, '01', 'push',
1196 fastpath=True, bundlecaps=bundlecaps)
1196 fastpath=True, bundlecaps=bundlecaps)
1197 else:
1197 else:
1198 cg = changegroup.makechangegroup(pushop.repo, outgoing, '01',
1198 cg = changegroup.makechangegroup(pushop.repo, outgoing, '01',
1199 'push', bundlecaps=bundlecaps)
1199 'push', bundlecaps=bundlecaps)
1200
1200
1201 # apply changegroup to remote
1201 # apply changegroup to remote
1202 # local repo finds heads on server, finds out what
1202 # local repo finds heads on server, finds out what
1203 # revs it must push. once revs transferred, if server
1203 # revs it must push. once revs transferred, if server
1204 # finds it has different heads (someone else won
1204 # finds it has different heads (someone else won
1205 # commit/push race), server aborts.
1205 # commit/push race), server aborts.
1206 if pushop.force:
1206 if pushop.force:
1207 remoteheads = ['force']
1207 remoteheads = ['force']
1208 else:
1208 else:
1209 remoteheads = pushop.remoteheads
1209 remoteheads = pushop.remoteheads
1210 # ssh: return remote's addchangegroup()
1210 # ssh: return remote's addchangegroup()
1211 # http: return remote's addchangegroup() or 0 for error
1211 # http: return remote's addchangegroup() or 0 for error
1212 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
1212 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
1213 pushop.repo.url())
1213 pushop.repo.url())
1214
1214
1215 def _pushsyncphase(pushop):
1215 def _pushsyncphase(pushop):
1216 """synchronise phase information locally and remotely"""
1216 """synchronise phase information locally and remotely"""
1217 cheads = pushop.commonheads
1217 cheads = pushop.commonheads
1218 # even when we don't push, exchanging phase data is useful
1218 # even when we don't push, exchanging phase data is useful
1219 remotephases = listkeys(pushop.remote, 'phases')
1219 remotephases = listkeys(pushop.remote, 'phases')
1220 if (pushop.ui.configbool('ui', '_usedassubrepo')
1220 if (pushop.ui.configbool('ui', '_usedassubrepo')
1221 and remotephases # server supports phases
1221 and remotephases # server supports phases
1222 and pushop.cgresult is None # nothing was pushed
1222 and pushop.cgresult is None # nothing was pushed
1223 and remotephases.get('publishing', False)):
1223 and remotephases.get('publishing', False)):
1224 # When:
1224 # When:
1225 # - this is a subrepo push
1225 # - this is a subrepo push
1226 # - and remote support phase
1226 # - and remote support phase
1227 # - and no changeset was pushed
1227 # - and no changeset was pushed
1228 # - and remote is publishing
1228 # - and remote is publishing
1229 # We may be in issue 3871 case!
1229 # We may be in issue 3871 case!
1230 # We drop the possible phase synchronisation done by
1230 # We drop the possible phase synchronisation done by
1231 # courtesy to publish changesets possibly locally draft
1231 # courtesy to publish changesets possibly locally draft
1232 # on the remote.
1232 # on the remote.
1233 remotephases = {'publishing': 'True'}
1233 remotephases = {'publishing': 'True'}
1234 if not remotephases: # old server or public only reply from non-publishing
1234 if not remotephases: # old server or public only reply from non-publishing
1235 _localphasemove(pushop, cheads)
1235 _localphasemove(pushop, cheads)
1236 # don't push any phase data as there is nothing to push
1236 # don't push any phase data as there is nothing to push
1237 else:
1237 else:
1238 ana = phases.analyzeremotephases(pushop.repo, cheads,
1238 ana = phases.analyzeremotephases(pushop.repo, cheads,
1239 remotephases)
1239 remotephases)
1240 pheads, droots = ana
1240 pheads, droots = ana
1241 ### Apply remote phase on local
1241 ### Apply remote phase on local
1242 if remotephases.get('publishing', False):
1242 if remotephases.get('publishing', False):
1243 _localphasemove(pushop, cheads)
1243 _localphasemove(pushop, cheads)
1244 else: # publish = False
1244 else: # publish = False
1245 _localphasemove(pushop, pheads)
1245 _localphasemove(pushop, pheads)
1246 _localphasemove(pushop, cheads, phases.draft)
1246 _localphasemove(pushop, cheads, phases.draft)
1247 ### Apply local phase on remote
1247 ### Apply local phase on remote
1248
1248
1249 if pushop.cgresult:
1249 if pushop.cgresult:
1250 if 'phases' in pushop.stepsdone:
1250 if 'phases' in pushop.stepsdone:
1251 # phases already pushed though bundle2
1251 # phases already pushed though bundle2
1252 return
1252 return
1253 outdated = pushop.outdatedphases
1253 outdated = pushop.outdatedphases
1254 else:
1254 else:
1255 outdated = pushop.fallbackoutdatedphases
1255 outdated = pushop.fallbackoutdatedphases
1256
1256
1257 pushop.stepsdone.add('phases')
1257 pushop.stepsdone.add('phases')
1258
1258
1259 # filter heads already turned public by the push
1259 # filter heads already turned public by the push
1260 outdated = [c for c in outdated if c.node() not in pheads]
1260 outdated = [c for c in outdated if c.node() not in pheads]
1261 # fallback to independent pushkey command
1261 # fallback to independent pushkey command
1262 for newremotehead in outdated:
1262 for newremotehead in outdated:
1263 with pushop.remote.commandexecutor() as e:
1263 with pushop.remote.commandexecutor() as e:
1264 r = e.callcommand('pushkey', {
1264 r = e.callcommand('pushkey', {
1265 'namespace': 'phases',
1265 'namespace': 'phases',
1266 'key': newremotehead.hex(),
1266 'key': newremotehead.hex(),
1267 'old': '%d' % phases.draft,
1267 'old': '%d' % phases.draft,
1268 'new': '%d' % phases.public
1268 'new': '%d' % phases.public
1269 }).result()
1269 }).result()
1270
1270
1271 if not r:
1271 if not r:
1272 pushop.ui.warn(_('updating %s to public failed!\n')
1272 pushop.ui.warn(_('updating %s to public failed!\n')
1273 % newremotehead)
1273 % newremotehead)
1274
1274
1275 def _localphasemove(pushop, nodes, phase=phases.public):
1275 def _localphasemove(pushop, nodes, phase=phases.public):
1276 """move <nodes> to <phase> in the local source repo"""
1276 """move <nodes> to <phase> in the local source repo"""
1277 if pushop.trmanager:
1277 if pushop.trmanager:
1278 phases.advanceboundary(pushop.repo,
1278 phases.advanceboundary(pushop.repo,
1279 pushop.trmanager.transaction(),
1279 pushop.trmanager.transaction(),
1280 phase,
1280 phase,
1281 nodes)
1281 nodes)
1282 else:
1282 else:
1283 # repo is not locked, do not change any phases!
1283 # repo is not locked, do not change any phases!
1284 # Informs the user that phases should have been moved when
1284 # Informs the user that phases should have been moved when
1285 # applicable.
1285 # applicable.
1286 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
1286 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
1287 phasestr = phases.phasenames[phase]
1287 phasestr = phases.phasenames[phase]
1288 if actualmoves:
1288 if actualmoves:
1289 pushop.ui.status(_('cannot lock source repo, skipping '
1289 pushop.ui.status(_('cannot lock source repo, skipping '
1290 'local %s phase update\n') % phasestr)
1290 'local %s phase update\n') % phasestr)
1291
1291
1292 def _pushobsolete(pushop):
1292 def _pushobsolete(pushop):
1293 """utility function to push obsolete markers to a remote"""
1293 """utility function to push obsolete markers to a remote"""
1294 if 'obsmarkers' in pushop.stepsdone:
1294 if 'obsmarkers' in pushop.stepsdone:
1295 return
1295 return
1296 repo = pushop.repo
1296 repo = pushop.repo
1297 remote = pushop.remote
1297 remote = pushop.remote
1298 pushop.stepsdone.add('obsmarkers')
1298 pushop.stepsdone.add('obsmarkers')
1299 if pushop.outobsmarkers:
1299 if pushop.outobsmarkers:
1300 pushop.ui.debug('try to push obsolete markers to remote\n')
1300 pushop.ui.debug('try to push obsolete markers to remote\n')
1301 rslts = []
1301 rslts = []
1302 remotedata = obsolete._pushkeyescape(sorted(pushop.outobsmarkers))
1302 remotedata = obsolete._pushkeyescape(sorted(pushop.outobsmarkers))
1303 for key in sorted(remotedata, reverse=True):
1303 for key in sorted(remotedata, reverse=True):
1304 # reverse sort to ensure we end with dump0
1304 # reverse sort to ensure we end with dump0
1305 data = remotedata[key]
1305 data = remotedata[key]
1306 rslts.append(remote.pushkey('obsolete', key, '', data))
1306 rslts.append(remote.pushkey('obsolete', key, '', data))
1307 if [r for r in rslts if not r]:
1307 if [r for r in rslts if not r]:
1308 msg = _('failed to push some obsolete markers!\n')
1308 msg = _('failed to push some obsolete markers!\n')
1309 repo.ui.warn(msg)
1309 repo.ui.warn(msg)
1310
1310
1311 def _pushbookmark(pushop):
1311 def _pushbookmark(pushop):
1312 """Update bookmark position on remote"""
1312 """Update bookmark position on remote"""
1313 if pushop.cgresult == 0 or 'bookmarks' in pushop.stepsdone:
1313 if pushop.cgresult == 0 or 'bookmarks' in pushop.stepsdone:
1314 return
1314 return
1315 pushop.stepsdone.add('bookmarks')
1315 pushop.stepsdone.add('bookmarks')
1316 ui = pushop.ui
1316 ui = pushop.ui
1317 remote = pushop.remote
1317 remote = pushop.remote
1318
1318
1319 for b, old, new in pushop.outbookmarks:
1319 for b, old, new in pushop.outbookmarks:
1320 action = 'update'
1320 action = 'update'
1321 if not old:
1321 if not old:
1322 action = 'export'
1322 action = 'export'
1323 elif not new:
1323 elif not new:
1324 action = 'delete'
1324 action = 'delete'
1325
1325
1326 with remote.commandexecutor() as e:
1326 with remote.commandexecutor() as e:
1327 r = e.callcommand('pushkey', {
1327 r = e.callcommand('pushkey', {
1328 'namespace': 'bookmarks',
1328 'namespace': 'bookmarks',
1329 'key': b,
1329 'key': b,
1330 'old': old,
1330 'old': old,
1331 'new': new,
1331 'new': new,
1332 }).result()
1332 }).result()
1333
1333
1334 if r:
1334 if r:
1335 ui.status(bookmsgmap[action][0] % b)
1335 ui.status(bookmsgmap[action][0] % b)
1336 else:
1336 else:
1337 ui.warn(bookmsgmap[action][1] % b)
1337 ui.warn(bookmsgmap[action][1] % b)
1338 # discovery can have set the value form invalid entry
1338 # discovery can have set the value form invalid entry
1339 if pushop.bkresult is not None:
1339 if pushop.bkresult is not None:
1340 pushop.bkresult = 1
1340 pushop.bkresult = 1
1341
1341
1342 class pulloperation(object):
1342 class pulloperation(object):
1343 """A object that represent a single pull operation
1343 """A object that represent a single pull operation
1344
1344
1345 It purpose is to carry pull related state and very common operation.
1345 It purpose is to carry pull related state and very common operation.
1346
1346
1347 A new should be created at the beginning of each pull and discarded
1347 A new should be created at the beginning of each pull and discarded
1348 afterward.
1348 afterward.
1349 """
1349 """
1350
1350
1351 def __init__(self, repo, remote, heads=None, force=False, bookmarks=(),
1351 def __init__(self, repo, remote, heads=None, force=False, bookmarks=(),
1352 remotebookmarks=None, streamclonerequested=None,
1352 remotebookmarks=None, streamclonerequested=None,
1353 includepats=None, excludepats=None, depth=None):
1353 includepats=None, excludepats=None, depth=None):
1354 # repo we pull into
1354 # repo we pull into
1355 self.repo = repo
1355 self.repo = repo
1356 # repo we pull from
1356 # repo we pull from
1357 self.remote = remote
1357 self.remote = remote
1358 # revision we try to pull (None is "all")
1358 # revision we try to pull (None is "all")
1359 self.heads = heads
1359 self.heads = heads
1360 # bookmark pulled explicitly
1360 # bookmark pulled explicitly
1361 self.explicitbookmarks = [repo._bookmarks.expandname(bookmark)
1361 self.explicitbookmarks = [repo._bookmarks.expandname(bookmark)
1362 for bookmark in bookmarks]
1362 for bookmark in bookmarks]
1363 # do we force pull?
1363 # do we force pull?
1364 self.force = force
1364 self.force = force
1365 # whether a streaming clone was requested
1365 # whether a streaming clone was requested
1366 self.streamclonerequested = streamclonerequested
1366 self.streamclonerequested = streamclonerequested
1367 # transaction manager
1367 # transaction manager
1368 self.trmanager = None
1368 self.trmanager = None
1369 # set of common changeset between local and remote before pull
1369 # set of common changeset between local and remote before pull
1370 self.common = None
1370 self.common = None
1371 # set of pulled head
1371 # set of pulled head
1372 self.rheads = None
1372 self.rheads = None
1373 # list of missing changeset to fetch remotely
1373 # list of missing changeset to fetch remotely
1374 self.fetch = None
1374 self.fetch = None
1375 # remote bookmarks data
1375 # remote bookmarks data
1376 self.remotebookmarks = remotebookmarks
1376 self.remotebookmarks = remotebookmarks
1377 # result of changegroup pulling (used as return code by pull)
1377 # result of changegroup pulling (used as return code by pull)
1378 self.cgresult = None
1378 self.cgresult = None
1379 # list of step already done
1379 # list of step already done
1380 self.stepsdone = set()
1380 self.stepsdone = set()
1381 # Whether we attempted a clone from pre-generated bundles.
1381 # Whether we attempted a clone from pre-generated bundles.
1382 self.clonebundleattempted = False
1382 self.clonebundleattempted = False
1383 # Set of file patterns to include.
1383 # Set of file patterns to include.
1384 self.includepats = includepats
1384 self.includepats = includepats
1385 # Set of file patterns to exclude.
1385 # Set of file patterns to exclude.
1386 self.excludepats = excludepats
1386 self.excludepats = excludepats
1387 # Number of ancestor changesets to pull from each pulled head.
1387 # Number of ancestor changesets to pull from each pulled head.
1388 self.depth = depth
1388 self.depth = depth
1389
1389
1390 @util.propertycache
1390 @util.propertycache
1391 def pulledsubset(self):
1391 def pulledsubset(self):
1392 """heads of the set of changeset target by the pull"""
1392 """heads of the set of changeset target by the pull"""
1393 # compute target subset
1393 # compute target subset
1394 if self.heads is None:
1394 if self.heads is None:
1395 # We pulled every thing possible
1395 # We pulled every thing possible
1396 # sync on everything common
1396 # sync on everything common
1397 c = set(self.common)
1397 c = set(self.common)
1398 ret = list(self.common)
1398 ret = list(self.common)
1399 for n in self.rheads:
1399 for n in self.rheads:
1400 if n not in c:
1400 if n not in c:
1401 ret.append(n)
1401 ret.append(n)
1402 return ret
1402 return ret
1403 else:
1403 else:
1404 # We pulled a specific subset
1404 # We pulled a specific subset
1405 # sync on this subset
1405 # sync on this subset
1406 return self.heads
1406 return self.heads
1407
1407
1408 @util.propertycache
1408 @util.propertycache
1409 def canusebundle2(self):
1409 def canusebundle2(self):
1410 return not _forcebundle1(self)
1410 return not _forcebundle1(self)
1411
1411
1412 @util.propertycache
1412 @util.propertycache
1413 def remotebundle2caps(self):
1413 def remotebundle2caps(self):
1414 return bundle2.bundle2caps(self.remote)
1414 return bundle2.bundle2caps(self.remote)
1415
1415
1416 def gettransaction(self):
1416 def gettransaction(self):
1417 # deprecated; talk to trmanager directly
1417 # deprecated; talk to trmanager directly
1418 return self.trmanager.transaction()
1418 return self.trmanager.transaction()
1419
1419
1420 class transactionmanager(util.transactional):
1420 class transactionmanager(util.transactional):
1421 """An object to manage the life cycle of a transaction
1421 """An object to manage the life cycle of a transaction
1422
1422
1423 It creates the transaction on demand and calls the appropriate hooks when
1423 It creates the transaction on demand and calls the appropriate hooks when
1424 closing the transaction."""
1424 closing the transaction."""
1425 def __init__(self, repo, source, url):
1425 def __init__(self, repo, source, url):
1426 self.repo = repo
1426 self.repo = repo
1427 self.source = source
1427 self.source = source
1428 self.url = url
1428 self.url = url
1429 self._tr = None
1429 self._tr = None
1430
1430
1431 def transaction(self):
1431 def transaction(self):
1432 """Return an open transaction object, constructing if necessary"""
1432 """Return an open transaction object, constructing if necessary"""
1433 if not self._tr:
1433 if not self._tr:
1434 trname = '%s\n%s' % (self.source, util.hidepassword(self.url))
1434 trname = '%s\n%s' % (self.source, util.hidepassword(self.url))
1435 self._tr = self.repo.transaction(trname)
1435 self._tr = self.repo.transaction(trname)
1436 self._tr.hookargs['source'] = self.source
1436 self._tr.hookargs['source'] = self.source
1437 self._tr.hookargs['url'] = self.url
1437 self._tr.hookargs['url'] = self.url
1438 return self._tr
1438 return self._tr
1439
1439
1440 def close(self):
1440 def close(self):
1441 """close transaction if created"""
1441 """close transaction if created"""
1442 if self._tr is not None:
1442 if self._tr is not None:
1443 self._tr.close()
1443 self._tr.close()
1444
1444
1445 def release(self):
1445 def release(self):
1446 """release transaction if created"""
1446 """release transaction if created"""
1447 if self._tr is not None:
1447 if self._tr is not None:
1448 self._tr.release()
1448 self._tr.release()
1449
1449
1450 def listkeys(remote, namespace):
1450 def listkeys(remote, namespace):
1451 with remote.commandexecutor() as e:
1451 with remote.commandexecutor() as e:
1452 return e.callcommand('listkeys', {'namespace': namespace}).result()
1452 return e.callcommand('listkeys', {'namespace': namespace}).result()
1453
1453
1454 def _fullpullbundle2(repo, pullop):
1454 def _fullpullbundle2(repo, pullop):
1455 # The server may send a partial reply, i.e. when inlining
1455 # The server may send a partial reply, i.e. when inlining
1456 # pre-computed bundles. In that case, update the common
1456 # pre-computed bundles. In that case, update the common
1457 # set based on the results and pull another bundle.
1457 # set based on the results and pull another bundle.
1458 #
1458 #
1459 # There are two indicators that the process is finished:
1459 # There are two indicators that the process is finished:
1460 # - no changeset has been added, or
1460 # - no changeset has been added, or
1461 # - all remote heads are known locally.
1461 # - all remote heads are known locally.
1462 # The head check must use the unfiltered view as obsoletion
1462 # The head check must use the unfiltered view as obsoletion
1463 # markers can hide heads.
1463 # markers can hide heads.
1464 unfi = repo.unfiltered()
1464 unfi = repo.unfiltered()
1465 unficl = unfi.changelog
1465 unficl = unfi.changelog
1466 def headsofdiff(h1, h2):
1466 def headsofdiff(h1, h2):
1467 """Returns heads(h1 % h2)"""
1467 """Returns heads(h1 % h2)"""
1468 res = unfi.set('heads(%ln %% %ln)', h1, h2)
1468 res = unfi.set('heads(%ln %% %ln)', h1, h2)
1469 return set(ctx.node() for ctx in res)
1469 return set(ctx.node() for ctx in res)
1470 def headsofunion(h1, h2):
1470 def headsofunion(h1, h2):
1471 """Returns heads((h1 + h2) - null)"""
1471 """Returns heads((h1 + h2) - null)"""
1472 res = unfi.set('heads((%ln + %ln - null))', h1, h2)
1472 res = unfi.set('heads((%ln + %ln - null))', h1, h2)
1473 return set(ctx.node() for ctx in res)
1473 return set(ctx.node() for ctx in res)
1474 while True:
1474 while True:
1475 old_heads = unficl.heads()
1475 old_heads = unficl.heads()
1476 clstart = len(unficl)
1476 clstart = len(unficl)
1477 _pullbundle2(pullop)
1477 _pullbundle2(pullop)
1478 if repository.NARROW_REQUIREMENT in repo.requirements:
1478 if repository.NARROW_REQUIREMENT in repo.requirements:
1479 # XXX narrow clones filter the heads on the server side during
1479 # XXX narrow clones filter the heads on the server side during
1480 # XXX getbundle and result in partial replies as well.
1480 # XXX getbundle and result in partial replies as well.
1481 # XXX Disable pull bundles in this case as band aid to avoid
1481 # XXX Disable pull bundles in this case as band aid to avoid
1482 # XXX extra round trips.
1482 # XXX extra round trips.
1483 break
1483 break
1484 if clstart == len(unficl):
1484 if clstart == len(unficl):
1485 break
1485 break
1486 if all(unficl.hasnode(n) for n in pullop.rheads):
1486 if all(unficl.hasnode(n) for n in pullop.rheads):
1487 break
1487 break
1488 new_heads = headsofdiff(unficl.heads(), old_heads)
1488 new_heads = headsofdiff(unficl.heads(), old_heads)
1489 pullop.common = headsofunion(new_heads, pullop.common)
1489 pullop.common = headsofunion(new_heads, pullop.common)
1490 pullop.rheads = set(pullop.rheads) - pullop.common
1490 pullop.rheads = set(pullop.rheads) - pullop.common
1491
1491
1492 def pull(repo, remote, heads=None, force=False, bookmarks=(), opargs=None,
1492 def pull(repo, remote, heads=None, force=False, bookmarks=(), opargs=None,
1493 streamclonerequested=None, includepats=None, excludepats=None,
1493 streamclonerequested=None, includepats=None, excludepats=None,
1494 depth=None):
1494 depth=None):
1495 """Fetch repository data from a remote.
1495 """Fetch repository data from a remote.
1496
1496
1497 This is the main function used to retrieve data from a remote repository.
1497 This is the main function used to retrieve data from a remote repository.
1498
1498
1499 ``repo`` is the local repository to clone into.
1499 ``repo`` is the local repository to clone into.
1500 ``remote`` is a peer instance.
1500 ``remote`` is a peer instance.
1501 ``heads`` is an iterable of revisions we want to pull. ``None`` (the
1501 ``heads`` is an iterable of revisions we want to pull. ``None`` (the
1502 default) means to pull everything from the remote.
1502 default) means to pull everything from the remote.
1503 ``bookmarks`` is an iterable of bookmarks requesting to be pulled. By
1503 ``bookmarks`` is an iterable of bookmarks requesting to be pulled. By
1504 default, all remote bookmarks are pulled.
1504 default, all remote bookmarks are pulled.
1505 ``opargs`` are additional keyword arguments to pass to ``pulloperation``
1505 ``opargs`` are additional keyword arguments to pass to ``pulloperation``
1506 initialization.
1506 initialization.
1507 ``streamclonerequested`` is a boolean indicating whether a "streaming
1507 ``streamclonerequested`` is a boolean indicating whether a "streaming
1508 clone" is requested. A "streaming clone" is essentially a raw file copy
1508 clone" is requested. A "streaming clone" is essentially a raw file copy
1509 of revlogs from the server. This only works when the local repository is
1509 of revlogs from the server. This only works when the local repository is
1510 empty. The default value of ``None`` means to respect the server
1510 empty. The default value of ``None`` means to respect the server
1511 configuration for preferring stream clones.
1511 configuration for preferring stream clones.
1512 ``includepats`` and ``excludepats`` define explicit file patterns to
1512 ``includepats`` and ``excludepats`` define explicit file patterns to
1513 include and exclude in storage, respectively. If not defined, narrow
1513 include and exclude in storage, respectively. If not defined, narrow
1514 patterns from the repo instance are used, if available.
1514 patterns from the repo instance are used, if available.
1515 ``depth`` is an integer indicating the DAG depth of history we're
1515 ``depth`` is an integer indicating the DAG depth of history we're
1516 interested in. If defined, for each revision specified in ``heads``, we
1516 interested in. If defined, for each revision specified in ``heads``, we
1517 will fetch up to this many of its ancestors and data associated with them.
1517 will fetch up to this many of its ancestors and data associated with them.
1518
1518
1519 Returns the ``pulloperation`` created for this pull.
1519 Returns the ``pulloperation`` created for this pull.
1520 """
1520 """
1521 if opargs is None:
1521 if opargs is None:
1522 opargs = {}
1522 opargs = {}
1523
1523
1524 # We allow the narrow patterns to be passed in explicitly to provide more
1524 # We allow the narrow patterns to be passed in explicitly to provide more
1525 # flexibility for API consumers.
1525 # flexibility for API consumers.
1526 if includepats or excludepats:
1526 if includepats or excludepats:
1527 includepats = includepats or set()
1527 includepats = includepats or set()
1528 excludepats = excludepats or set()
1528 excludepats = excludepats or set()
1529 else:
1529 else:
1530 includepats, excludepats = repo.narrowpats
1530 includepats, excludepats = repo.narrowpats
1531
1531
1532 narrowspec.validatepatterns(includepats)
1532 narrowspec.validatepatterns(includepats)
1533 narrowspec.validatepatterns(excludepats)
1533 narrowspec.validatepatterns(excludepats)
1534
1534
1535 pullop = pulloperation(repo, remote, heads, force, bookmarks=bookmarks,
1535 pullop = pulloperation(repo, remote, heads, force, bookmarks=bookmarks,
1536 streamclonerequested=streamclonerequested,
1536 streamclonerequested=streamclonerequested,
1537 includepats=includepats, excludepats=excludepats,
1537 includepats=includepats, excludepats=excludepats,
1538 depth=depth,
1538 depth=depth,
1539 **pycompat.strkwargs(opargs))
1539 **pycompat.strkwargs(opargs))
1540
1540
1541 peerlocal = pullop.remote.local()
1541 peerlocal = pullop.remote.local()
1542 if peerlocal:
1542 if peerlocal:
1543 missing = set(peerlocal.requirements) - pullop.repo.supported
1543 missing = set(peerlocal.requirements) - pullop.repo.supported
1544 if missing:
1544 if missing:
1545 msg = _("required features are not"
1545 msg = _("required features are not"
1546 " supported in the destination:"
1546 " supported in the destination:"
1547 " %s") % (', '.join(sorted(missing)))
1547 " %s") % (', '.join(sorted(missing)))
1548 raise error.Abort(msg)
1548 raise error.Abort(msg)
1549
1549
1550 pullop.trmanager = transactionmanager(repo, 'pull', remote.url())
1550 pullop.trmanager = transactionmanager(repo, 'pull', remote.url())
1551 with repo.wlock(), repo.lock(), pullop.trmanager:
1551 with repo.wlock(), repo.lock(), pullop.trmanager:
1552 # Use the modern wire protocol, if available.
1552 # Use the modern wire protocol, if available.
1553 if remote.capable('command-changesetdata'):
1553 if remote.capable('command-changesetdata'):
1554 exchangev2.pull(pullop)
1554 exchangev2.pull(pullop)
1555 else:
1555 else:
1556 # This should ideally be in _pullbundle2(). However, it needs to run
1556 # This should ideally be in _pullbundle2(). However, it needs to run
1557 # before discovery to avoid extra work.
1557 # before discovery to avoid extra work.
1558 _maybeapplyclonebundle(pullop)
1558 _maybeapplyclonebundle(pullop)
1559 streamclone.maybeperformlegacystreamclone(pullop)
1559 streamclone.maybeperformlegacystreamclone(pullop)
1560 _pulldiscovery(pullop)
1560 _pulldiscovery(pullop)
1561 if pullop.canusebundle2:
1561 if pullop.canusebundle2:
1562 _fullpullbundle2(repo, pullop)
1562 _fullpullbundle2(repo, pullop)
1563 _pullchangeset(pullop)
1563 _pullchangeset(pullop)
1564 _pullphase(pullop)
1564 _pullphase(pullop)
1565 _pullbookmarks(pullop)
1565 _pullbookmarks(pullop)
1566 _pullobsolete(pullop)
1566 _pullobsolete(pullop)
1567
1567
1568 # storing remotenames
1568 # storing remotenames
1569 if repo.ui.configbool('experimental', 'remotenames'):
1569 if repo.ui.configbool('experimental', 'remotenames'):
1570 logexchange.pullremotenames(repo, remote)
1570 logexchange.pullremotenames(repo, remote)
1571
1571
1572 return pullop
1572 return pullop
1573
1573
1574 # list of steps to perform discovery before pull
1574 # list of steps to perform discovery before pull
1575 pulldiscoveryorder = []
1575 pulldiscoveryorder = []
1576
1576
1577 # Mapping between step name and function
1577 # Mapping between step name and function
1578 #
1578 #
1579 # This exists to help extensions wrap steps if necessary
1579 # This exists to help extensions wrap steps if necessary
1580 pulldiscoverymapping = {}
1580 pulldiscoverymapping = {}
1581
1581
1582 def pulldiscovery(stepname):
1582 def pulldiscovery(stepname):
1583 """decorator for function performing discovery before pull
1583 """decorator for function performing discovery before pull
1584
1584
1585 The function is added to the step -> function mapping and appended to the
1585 The function is added to the step -> function mapping and appended to the
1586 list of steps. Beware that decorated function will be added in order (this
1586 list of steps. Beware that decorated function will be added in order (this
1587 may matter).
1587 may matter).
1588
1588
1589 You can only use this decorator for a new step, if you want to wrap a step
1589 You can only use this decorator for a new step, if you want to wrap a step
1590 from an extension, change the pulldiscovery dictionary directly."""
1590 from an extension, change the pulldiscovery dictionary directly."""
1591 def dec(func):
1591 def dec(func):
1592 assert stepname not in pulldiscoverymapping
1592 assert stepname not in pulldiscoverymapping
1593 pulldiscoverymapping[stepname] = func
1593 pulldiscoverymapping[stepname] = func
1594 pulldiscoveryorder.append(stepname)
1594 pulldiscoveryorder.append(stepname)
1595 return func
1595 return func
1596 return dec
1596 return dec
1597
1597
1598 def _pulldiscovery(pullop):
1598 def _pulldiscovery(pullop):
1599 """Run all discovery steps"""
1599 """Run all discovery steps"""
1600 for stepname in pulldiscoveryorder:
1600 for stepname in pulldiscoveryorder:
1601 step = pulldiscoverymapping[stepname]
1601 step = pulldiscoverymapping[stepname]
1602 step(pullop)
1602 step(pullop)
1603
1603
1604 @pulldiscovery('b1:bookmarks')
1604 @pulldiscovery('b1:bookmarks')
1605 def _pullbookmarkbundle1(pullop):
1605 def _pullbookmarkbundle1(pullop):
1606 """fetch bookmark data in bundle1 case
1606 """fetch bookmark data in bundle1 case
1607
1607
1608 If not using bundle2, we have to fetch bookmarks before changeset
1608 If not using bundle2, we have to fetch bookmarks before changeset
1609 discovery to reduce the chance and impact of race conditions."""
1609 discovery to reduce the chance and impact of race conditions."""
1610 if pullop.remotebookmarks is not None:
1610 if pullop.remotebookmarks is not None:
1611 return
1611 return
1612 if pullop.canusebundle2 and 'listkeys' in pullop.remotebundle2caps:
1612 if pullop.canusebundle2 and 'listkeys' in pullop.remotebundle2caps:
1613 # all known bundle2 servers now support listkeys, but lets be nice with
1613 # all known bundle2 servers now support listkeys, but lets be nice with
1614 # new implementation.
1614 # new implementation.
1615 return
1615 return
1616 books = listkeys(pullop.remote, 'bookmarks')
1616 books = listkeys(pullop.remote, 'bookmarks')
1617 pullop.remotebookmarks = bookmod.unhexlifybookmarks(books)
1617 pullop.remotebookmarks = bookmod.unhexlifybookmarks(books)
1618
1618
1619
1619
1620 @pulldiscovery('changegroup')
1620 @pulldiscovery('changegroup')
1621 def _pulldiscoverychangegroup(pullop):
1621 def _pulldiscoverychangegroup(pullop):
1622 """discovery phase for the pull
1622 """discovery phase for the pull
1623
1623
1624 Current handle changeset discovery only, will change handle all discovery
1624 Current handle changeset discovery only, will change handle all discovery
1625 at some point."""
1625 at some point."""
1626 tmp = discovery.findcommonincoming(pullop.repo,
1626 tmp = discovery.findcommonincoming(pullop.repo,
1627 pullop.remote,
1627 pullop.remote,
1628 heads=pullop.heads,
1628 heads=pullop.heads,
1629 force=pullop.force)
1629 force=pullop.force)
1630 common, fetch, rheads = tmp
1630 common, fetch, rheads = tmp
1631 nm = pullop.repo.unfiltered().changelog.nodemap
1631 nm = pullop.repo.unfiltered().changelog.nodemap
1632 if fetch and rheads:
1632 if fetch and rheads:
1633 # If a remote heads is filtered locally, put in back in common.
1633 # If a remote heads is filtered locally, put in back in common.
1634 #
1634 #
1635 # This is a hackish solution to catch most of "common but locally
1635 # This is a hackish solution to catch most of "common but locally
1636 # hidden situation". We do not performs discovery on unfiltered
1636 # hidden situation". We do not performs discovery on unfiltered
1637 # repository because it end up doing a pathological amount of round
1637 # repository because it end up doing a pathological amount of round
1638 # trip for w huge amount of changeset we do not care about.
1638 # trip for w huge amount of changeset we do not care about.
1639 #
1639 #
1640 # If a set of such "common but filtered" changeset exist on the server
1640 # If a set of such "common but filtered" changeset exist on the server
1641 # but are not including a remote heads, we'll not be able to detect it,
1641 # but are not including a remote heads, we'll not be able to detect it,
1642 scommon = set(common)
1642 scommon = set(common)
1643 for n in rheads:
1643 for n in rheads:
1644 if n in nm:
1644 if n in nm:
1645 if n not in scommon:
1645 if n not in scommon:
1646 common.append(n)
1646 common.append(n)
1647 if set(rheads).issubset(set(common)):
1647 if set(rheads).issubset(set(common)):
1648 fetch = []
1648 fetch = []
1649 pullop.common = common
1649 pullop.common = common
1650 pullop.fetch = fetch
1650 pullop.fetch = fetch
1651 pullop.rheads = rheads
1651 pullop.rheads = rheads
1652
1652
1653 def _pullbundle2(pullop):
1653 def _pullbundle2(pullop):
1654 """pull data using bundle2
1654 """pull data using bundle2
1655
1655
1656 For now, the only supported data are changegroup."""
1656 For now, the only supported data are changegroup."""
1657 kwargs = {'bundlecaps': caps20to10(pullop.repo, role='client')}
1657 kwargs = {'bundlecaps': caps20to10(pullop.repo, role='client')}
1658
1658
1659 # make ui easier to access
1659 # make ui easier to access
1660 ui = pullop.repo.ui
1660 ui = pullop.repo.ui
1661
1661
1662 # At the moment we don't do stream clones over bundle2. If that is
1662 # At the moment we don't do stream clones over bundle2. If that is
1663 # implemented then here's where the check for that will go.
1663 # implemented then here's where the check for that will go.
1664 streaming = streamclone.canperformstreamclone(pullop, bundle2=True)[0]
1664 streaming = streamclone.canperformstreamclone(pullop, bundle2=True)[0]
1665
1665
1666 # declare pull perimeters
1666 # declare pull perimeters
1667 kwargs['common'] = pullop.common
1667 kwargs['common'] = pullop.common
1668 kwargs['heads'] = pullop.heads or pullop.rheads
1668 kwargs['heads'] = pullop.heads or pullop.rheads
1669
1669
1670 # check server supports narrow and then adding includepats and excludepats
1670 # check server supports narrow and then adding includepats and excludepats
1671 servernarrow = pullop.remote.capable(wireprototypes.NARROWCAP)
1671 servernarrow = pullop.remote.capable(wireprototypes.NARROWCAP)
1672 if servernarrow and pullop.includepats:
1672 if servernarrow and pullop.includepats:
1673 kwargs['includepats'] = pullop.includepats
1673 kwargs['includepats'] = pullop.includepats
1674 if servernarrow and pullop.excludepats:
1674 if servernarrow and pullop.excludepats:
1675 kwargs['excludepats'] = pullop.excludepats
1675 kwargs['excludepats'] = pullop.excludepats
1676
1676
1677 if streaming:
1677 if streaming:
1678 kwargs['cg'] = False
1678 kwargs['cg'] = False
1679 kwargs['stream'] = True
1679 kwargs['stream'] = True
1680 pullop.stepsdone.add('changegroup')
1680 pullop.stepsdone.add('changegroup')
1681 pullop.stepsdone.add('phases')
1681 pullop.stepsdone.add('phases')
1682
1682
1683 else:
1683 else:
1684 # pulling changegroup
1684 # pulling changegroup
1685 pullop.stepsdone.add('changegroup')
1685 pullop.stepsdone.add('changegroup')
1686
1686
1687 kwargs['cg'] = pullop.fetch
1687 kwargs['cg'] = pullop.fetch
1688
1688
1689 legacyphase = 'phases' in ui.configlist('devel', 'legacy.exchange')
1689 legacyphase = 'phases' in ui.configlist('devel', 'legacy.exchange')
1690 hasbinaryphase = 'heads' in pullop.remotebundle2caps.get('phases', ())
1690 hasbinaryphase = 'heads' in pullop.remotebundle2caps.get('phases', ())
1691 if (not legacyphase and hasbinaryphase):
1691 if (not legacyphase and hasbinaryphase):
1692 kwargs['phases'] = True
1692 kwargs['phases'] = True
1693 pullop.stepsdone.add('phases')
1693 pullop.stepsdone.add('phases')
1694
1694
1695 if 'listkeys' in pullop.remotebundle2caps:
1695 if 'listkeys' in pullop.remotebundle2caps:
1696 if 'phases' not in pullop.stepsdone:
1696 if 'phases' not in pullop.stepsdone:
1697 kwargs['listkeys'] = ['phases']
1697 kwargs['listkeys'] = ['phases']
1698
1698
1699 bookmarksrequested = False
1699 bookmarksrequested = False
1700 legacybookmark = 'bookmarks' in ui.configlist('devel', 'legacy.exchange')
1700 legacybookmark = 'bookmarks' in ui.configlist('devel', 'legacy.exchange')
1701 hasbinarybook = 'bookmarks' in pullop.remotebundle2caps
1701 hasbinarybook = 'bookmarks' in pullop.remotebundle2caps
1702
1702
1703 if pullop.remotebookmarks is not None:
1703 if pullop.remotebookmarks is not None:
1704 pullop.stepsdone.add('request-bookmarks')
1704 pullop.stepsdone.add('request-bookmarks')
1705
1705
1706 if ('request-bookmarks' not in pullop.stepsdone
1706 if ('request-bookmarks' not in pullop.stepsdone
1707 and pullop.remotebookmarks is None
1707 and pullop.remotebookmarks is None
1708 and not legacybookmark and hasbinarybook):
1708 and not legacybookmark and hasbinarybook):
1709 kwargs['bookmarks'] = True
1709 kwargs['bookmarks'] = True
1710 bookmarksrequested = True
1710 bookmarksrequested = True
1711
1711
1712 if 'listkeys' in pullop.remotebundle2caps:
1712 if 'listkeys' in pullop.remotebundle2caps:
1713 if 'request-bookmarks' not in pullop.stepsdone:
1713 if 'request-bookmarks' not in pullop.stepsdone:
1714 # make sure to always includes bookmark data when migrating
1714 # make sure to always includes bookmark data when migrating
1715 # `hg incoming --bundle` to using this function.
1715 # `hg incoming --bundle` to using this function.
1716 pullop.stepsdone.add('request-bookmarks')
1716 pullop.stepsdone.add('request-bookmarks')
1717 kwargs.setdefault('listkeys', []).append('bookmarks')
1717 kwargs.setdefault('listkeys', []).append('bookmarks')
1718
1718
1719 # If this is a full pull / clone and the server supports the clone bundles
1719 # If this is a full pull / clone and the server supports the clone bundles
1720 # feature, tell the server whether we attempted a clone bundle. The
1720 # feature, tell the server whether we attempted a clone bundle. The
1721 # presence of this flag indicates the client supports clone bundles. This
1721 # presence of this flag indicates the client supports clone bundles. This
1722 # will enable the server to treat clients that support clone bundles
1722 # will enable the server to treat clients that support clone bundles
1723 # differently from those that don't.
1723 # differently from those that don't.
1724 if (pullop.remote.capable('clonebundles')
1724 if (pullop.remote.capable('clonebundles')
1725 and pullop.heads is None and list(pullop.common) == [nullid]):
1725 and pullop.heads is None and list(pullop.common) == [nullid]):
1726 kwargs['cbattempted'] = pullop.clonebundleattempted
1726 kwargs['cbattempted'] = pullop.clonebundleattempted
1727
1727
1728 if streaming:
1728 if streaming:
1729 pullop.repo.ui.status(_('streaming all changes\n'))
1729 pullop.repo.ui.status(_('streaming all changes\n'))
1730 elif not pullop.fetch:
1730 elif not pullop.fetch:
1731 pullop.repo.ui.status(_("no changes found\n"))
1731 pullop.repo.ui.status(_("no changes found\n"))
1732 pullop.cgresult = 0
1732 pullop.cgresult = 0
1733 else:
1733 else:
1734 if pullop.heads is None and list(pullop.common) == [nullid]:
1734 if pullop.heads is None and list(pullop.common) == [nullid]:
1735 pullop.repo.ui.status(_("requesting all changes\n"))
1735 pullop.repo.ui.status(_("requesting all changes\n"))
1736 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1736 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1737 remoteversions = bundle2.obsmarkersversion(pullop.remotebundle2caps)
1737 remoteversions = bundle2.obsmarkersversion(pullop.remotebundle2caps)
1738 if obsolete.commonversion(remoteversions) is not None:
1738 if obsolete.commonversion(remoteversions) is not None:
1739 kwargs['obsmarkers'] = True
1739 kwargs['obsmarkers'] = True
1740 pullop.stepsdone.add('obsmarkers')
1740 pullop.stepsdone.add('obsmarkers')
1741 _pullbundle2extraprepare(pullop, kwargs)
1741 _pullbundle2extraprepare(pullop, kwargs)
1742
1742
1743 with pullop.remote.commandexecutor() as e:
1743 with pullop.remote.commandexecutor() as e:
1744 args = dict(kwargs)
1744 args = dict(kwargs)
1745 args['source'] = 'pull'
1745 args['source'] = 'pull'
1746 bundle = e.callcommand('getbundle', args).result()
1746 bundle = e.callcommand('getbundle', args).result()
1747
1747
1748 try:
1748 try:
1749 op = bundle2.bundleoperation(pullop.repo, pullop.gettransaction,
1749 op = bundle2.bundleoperation(pullop.repo, pullop.gettransaction,
1750 source='pull')
1750 source='pull')
1751 op.modes['bookmarks'] = 'records'
1751 op.modes['bookmarks'] = 'records'
1752 bundle2.processbundle(pullop.repo, bundle, op=op)
1752 bundle2.processbundle(pullop.repo, bundle, op=op)
1753 except bundle2.AbortFromPart as exc:
1753 except bundle2.AbortFromPart as exc:
1754 pullop.repo.ui.status(_('remote: abort: %s\n') % exc)
1754 pullop.repo.ui.status(_('remote: abort: %s\n') % exc)
1755 raise error.Abort(_('pull failed on remote'), hint=exc.hint)
1755 raise error.Abort(_('pull failed on remote'), hint=exc.hint)
1756 except error.BundleValueError as exc:
1756 except error.BundleValueError as exc:
1757 raise error.Abort(_('missing support for %s') % exc)
1757 raise error.Abort(_('missing support for %s') % exc)
1758
1758
1759 if pullop.fetch:
1759 if pullop.fetch:
1760 pullop.cgresult = bundle2.combinechangegroupresults(op)
1760 pullop.cgresult = bundle2.combinechangegroupresults(op)
1761
1761
1762 # processing phases change
1762 # processing phases change
1763 for namespace, value in op.records['listkeys']:
1763 for namespace, value in op.records['listkeys']:
1764 if namespace == 'phases':
1764 if namespace == 'phases':
1765 _pullapplyphases(pullop, value)
1765 _pullapplyphases(pullop, value)
1766
1766
1767 # processing bookmark update
1767 # processing bookmark update
1768 if bookmarksrequested:
1768 if bookmarksrequested:
1769 books = {}
1769 books = {}
1770 for record in op.records['bookmarks']:
1770 for record in op.records['bookmarks']:
1771 books[record['bookmark']] = record["node"]
1771 books[record['bookmark']] = record["node"]
1772 pullop.remotebookmarks = books
1772 pullop.remotebookmarks = books
1773 else:
1773 else:
1774 for namespace, value in op.records['listkeys']:
1774 for namespace, value in op.records['listkeys']:
1775 if namespace == 'bookmarks':
1775 if namespace == 'bookmarks':
1776 pullop.remotebookmarks = bookmod.unhexlifybookmarks(value)
1776 pullop.remotebookmarks = bookmod.unhexlifybookmarks(value)
1777
1777
1778 # bookmark data were either already there or pulled in the bundle
1778 # bookmark data were either already there or pulled in the bundle
1779 if pullop.remotebookmarks is not None:
1779 if pullop.remotebookmarks is not None:
1780 _pullbookmarks(pullop)
1780 _pullbookmarks(pullop)
1781
1781
1782 def _pullbundle2extraprepare(pullop, kwargs):
1782 def _pullbundle2extraprepare(pullop, kwargs):
1783 """hook function so that extensions can extend the getbundle call"""
1783 """hook function so that extensions can extend the getbundle call"""
1784
1784
1785 def _pullchangeset(pullop):
1785 def _pullchangeset(pullop):
1786 """pull changeset from unbundle into the local repo"""
1786 """pull changeset from unbundle into the local repo"""
1787 # We delay the open of the transaction as late as possible so we
1787 # We delay the open of the transaction as late as possible so we
1788 # don't open transaction for nothing or you break future useful
1788 # don't open transaction for nothing or you break future useful
1789 # rollback call
1789 # rollback call
1790 if 'changegroup' in pullop.stepsdone:
1790 if 'changegroup' in pullop.stepsdone:
1791 return
1791 return
1792 pullop.stepsdone.add('changegroup')
1792 pullop.stepsdone.add('changegroup')
1793 if not pullop.fetch:
1793 if not pullop.fetch:
1794 pullop.repo.ui.status(_("no changes found\n"))
1794 pullop.repo.ui.status(_("no changes found\n"))
1795 pullop.cgresult = 0
1795 pullop.cgresult = 0
1796 return
1796 return
1797 tr = pullop.gettransaction()
1797 tr = pullop.gettransaction()
1798 if pullop.heads is None and list(pullop.common) == [nullid]:
1798 if pullop.heads is None and list(pullop.common) == [nullid]:
1799 pullop.repo.ui.status(_("requesting all changes\n"))
1799 pullop.repo.ui.status(_("requesting all changes\n"))
1800 elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
1800 elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
1801 # issue1320, avoid a race if remote changed after discovery
1801 # issue1320, avoid a race if remote changed after discovery
1802 pullop.heads = pullop.rheads
1802 pullop.heads = pullop.rheads
1803
1803
1804 if pullop.remote.capable('getbundle'):
1804 if pullop.remote.capable('getbundle'):
1805 # TODO: get bundlecaps from remote
1805 # TODO: get bundlecaps from remote
1806 cg = pullop.remote.getbundle('pull', common=pullop.common,
1806 cg = pullop.remote.getbundle('pull', common=pullop.common,
1807 heads=pullop.heads or pullop.rheads)
1807 heads=pullop.heads or pullop.rheads)
1808 elif pullop.heads is None:
1808 elif pullop.heads is None:
1809 with pullop.remote.commandexecutor() as e:
1809 with pullop.remote.commandexecutor() as e:
1810 cg = e.callcommand('changegroup', {
1810 cg = e.callcommand('changegroup', {
1811 'nodes': pullop.fetch,
1811 'nodes': pullop.fetch,
1812 'source': 'pull',
1812 'source': 'pull',
1813 }).result()
1813 }).result()
1814
1814
1815 elif not pullop.remote.capable('changegroupsubset'):
1815 elif not pullop.remote.capable('changegroupsubset'):
1816 raise error.Abort(_("partial pull cannot be done because "
1816 raise error.Abort(_("partial pull cannot be done because "
1817 "other repository doesn't support "
1817 "other repository doesn't support "
1818 "changegroupsubset."))
1818 "changegroupsubset."))
1819 else:
1819 else:
1820 with pullop.remote.commandexecutor() as e:
1820 with pullop.remote.commandexecutor() as e:
1821 cg = e.callcommand('changegroupsubset', {
1821 cg = e.callcommand('changegroupsubset', {
1822 'bases': pullop.fetch,
1822 'bases': pullop.fetch,
1823 'heads': pullop.heads,
1823 'heads': pullop.heads,
1824 'source': 'pull',
1824 'source': 'pull',
1825 }).result()
1825 }).result()
1826
1826
1827 bundleop = bundle2.applybundle(pullop.repo, cg, tr, 'pull',
1827 bundleop = bundle2.applybundle(pullop.repo, cg, tr, 'pull',
1828 pullop.remote.url())
1828 pullop.remote.url())
1829 pullop.cgresult = bundle2.combinechangegroupresults(bundleop)
1829 pullop.cgresult = bundle2.combinechangegroupresults(bundleop)
1830
1830
1831 def _pullphase(pullop):
1831 def _pullphase(pullop):
1832 # Get remote phases data from remote
1832 # Get remote phases data from remote
1833 if 'phases' in pullop.stepsdone:
1833 if 'phases' in pullop.stepsdone:
1834 return
1834 return
1835 remotephases = listkeys(pullop.remote, 'phases')
1835 remotephases = listkeys(pullop.remote, 'phases')
1836 _pullapplyphases(pullop, remotephases)
1836 _pullapplyphases(pullop, remotephases)
1837
1837
1838 def _pullapplyphases(pullop, remotephases):
1838 def _pullapplyphases(pullop, remotephases):
1839 """apply phase movement from observed remote state"""
1839 """apply phase movement from observed remote state"""
1840 if 'phases' in pullop.stepsdone:
1840 if 'phases' in pullop.stepsdone:
1841 return
1841 return
1842 pullop.stepsdone.add('phases')
1842 pullop.stepsdone.add('phases')
1843 publishing = bool(remotephases.get('publishing', False))
1843 publishing = bool(remotephases.get('publishing', False))
1844 if remotephases and not publishing:
1844 if remotephases and not publishing:
1845 # remote is new and non-publishing
1845 # remote is new and non-publishing
1846 pheads, _dr = phases.analyzeremotephases(pullop.repo,
1846 pheads, _dr = phases.analyzeremotephases(pullop.repo,
1847 pullop.pulledsubset,
1847 pullop.pulledsubset,
1848 remotephases)
1848 remotephases)
1849 dheads = pullop.pulledsubset
1849 dheads = pullop.pulledsubset
1850 else:
1850 else:
1851 # Remote is old or publishing all common changesets
1851 # Remote is old or publishing all common changesets
1852 # should be seen as public
1852 # should be seen as public
1853 pheads = pullop.pulledsubset
1853 pheads = pullop.pulledsubset
1854 dheads = []
1854 dheads = []
1855 unfi = pullop.repo.unfiltered()
1855 unfi = pullop.repo.unfiltered()
1856 phase = unfi._phasecache.phase
1856 phase = unfi._phasecache.phase
1857 rev = unfi.changelog.nodemap.get
1857 rev = unfi.changelog.nodemap.get
1858 public = phases.public
1858 public = phases.public
1859 draft = phases.draft
1859 draft = phases.draft
1860
1860
1861 # exclude changesets already public locally and update the others
1861 # exclude changesets already public locally and update the others
1862 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
1862 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
1863 if pheads:
1863 if pheads:
1864 tr = pullop.gettransaction()
1864 tr = pullop.gettransaction()
1865 phases.advanceboundary(pullop.repo, tr, public, pheads)
1865 phases.advanceboundary(pullop.repo, tr, public, pheads)
1866
1866
1867 # exclude changesets already draft locally and update the others
1867 # exclude changesets already draft locally and update the others
1868 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
1868 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
1869 if dheads:
1869 if dheads:
1870 tr = pullop.gettransaction()
1870 tr = pullop.gettransaction()
1871 phases.advanceboundary(pullop.repo, tr, draft, dheads)
1871 phases.advanceboundary(pullop.repo, tr, draft, dheads)
1872
1872
1873 def _pullbookmarks(pullop):
1873 def _pullbookmarks(pullop):
1874 """process the remote bookmark information to update the local one"""
1874 """process the remote bookmark information to update the local one"""
1875 if 'bookmarks' in pullop.stepsdone:
1875 if 'bookmarks' in pullop.stepsdone:
1876 return
1876 return
1877 pullop.stepsdone.add('bookmarks')
1877 pullop.stepsdone.add('bookmarks')
1878 repo = pullop.repo
1878 repo = pullop.repo
1879 remotebookmarks = pullop.remotebookmarks
1879 remotebookmarks = pullop.remotebookmarks
1880 bookmod.updatefromremote(repo.ui, repo, remotebookmarks,
1880 bookmod.updatefromremote(repo.ui, repo, remotebookmarks,
1881 pullop.remote.url(),
1881 pullop.remote.url(),
1882 pullop.gettransaction,
1882 pullop.gettransaction,
1883 explicit=pullop.explicitbookmarks)
1883 explicit=pullop.explicitbookmarks)
1884
1884
1885 def _pullobsolete(pullop):
1885 def _pullobsolete(pullop):
1886 """utility function to pull obsolete markers from a remote
1886 """utility function to pull obsolete markers from a remote
1887
1887
1888 The `gettransaction` is function that return the pull transaction, creating
1888 The `gettransaction` is function that return the pull transaction, creating
1889 one if necessary. We return the transaction to inform the calling code that
1889 one if necessary. We return the transaction to inform the calling code that
1890 a new transaction have been created (when applicable).
1890 a new transaction have been created (when applicable).
1891
1891
1892 Exists mostly to allow overriding for experimentation purpose"""
1892 Exists mostly to allow overriding for experimentation purpose"""
1893 if 'obsmarkers' in pullop.stepsdone:
1893 if 'obsmarkers' in pullop.stepsdone:
1894 return
1894 return
1895 pullop.stepsdone.add('obsmarkers')
1895 pullop.stepsdone.add('obsmarkers')
1896 tr = None
1896 tr = None
1897 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1897 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1898 pullop.repo.ui.debug('fetching remote obsolete markers\n')
1898 pullop.repo.ui.debug('fetching remote obsolete markers\n')
1899 remoteobs = listkeys(pullop.remote, 'obsolete')
1899 remoteobs = listkeys(pullop.remote, 'obsolete')
1900 if 'dump0' in remoteobs:
1900 if 'dump0' in remoteobs:
1901 tr = pullop.gettransaction()
1901 tr = pullop.gettransaction()
1902 markers = []
1902 markers = []
1903 for key in sorted(remoteobs, reverse=True):
1903 for key in sorted(remoteobs, reverse=True):
1904 if key.startswith('dump'):
1904 if key.startswith('dump'):
1905 data = util.b85decode(remoteobs[key])
1905 data = util.b85decode(remoteobs[key])
1906 version, newmarks = obsolete._readmarkers(data)
1906 version, newmarks = obsolete._readmarkers(data)
1907 markers += newmarks
1907 markers += newmarks
1908 if markers:
1908 if markers:
1909 pullop.repo.obsstore.add(tr, markers)
1909 pullop.repo.obsstore.add(tr, markers)
1910 pullop.repo.invalidatevolatilesets()
1910 pullop.repo.invalidatevolatilesets()
1911 return tr
1911 return tr
1912
1912
1913 def applynarrowacl(repo, kwargs):
1913 def applynarrowacl(repo, kwargs):
1914 """Apply narrow fetch access control.
1914 """Apply narrow fetch access control.
1915
1915
1916 This massages the named arguments for getbundle wire protocol commands
1916 This massages the named arguments for getbundle wire protocol commands
1917 so requested data is filtered through access control rules.
1917 so requested data is filtered through access control rules.
1918 """
1918 """
1919 ui = repo.ui
1919 ui = repo.ui
1920 # TODO this assumes existence of HTTP and is a layering violation.
1920 # TODO this assumes existence of HTTP and is a layering violation.
1921 username = ui.shortuser(ui.environ.get('REMOTE_USER') or ui.username())
1921 username = ui.shortuser(ui.environ.get('REMOTE_USER') or ui.username())
1922 user_includes = ui.configlist(
1922 user_includes = ui.configlist(
1923 _NARROWACL_SECTION, username + '.includes',
1923 _NARROWACL_SECTION, username + '.includes',
1924 ui.configlist(_NARROWACL_SECTION, 'default.includes'))
1924 ui.configlist(_NARROWACL_SECTION, 'default.includes'))
1925 user_excludes = ui.configlist(
1925 user_excludes = ui.configlist(
1926 _NARROWACL_SECTION, username + '.excludes',
1926 _NARROWACL_SECTION, username + '.excludes',
1927 ui.configlist(_NARROWACL_SECTION, 'default.excludes'))
1927 ui.configlist(_NARROWACL_SECTION, 'default.excludes'))
1928 if not user_includes:
1928 if not user_includes:
1929 raise error.Abort(_("{} configuration for user {} is empty")
1929 raise error.Abort(_("{} configuration for user {} is empty")
1930 .format(_NARROWACL_SECTION, username))
1930 .format(_NARROWACL_SECTION, username))
1931
1931
1932 user_includes = [
1932 user_includes = [
1933 'path:.' if p == '*' else 'path:' + p for p in user_includes]
1933 'path:.' if p == '*' else 'path:' + p for p in user_includes]
1934 user_excludes = [
1934 user_excludes = [
1935 'path:.' if p == '*' else 'path:' + p for p in user_excludes]
1935 'path:.' if p == '*' else 'path:' + p for p in user_excludes]
1936
1936
1937 req_includes = set(kwargs.get(r'includepats', []))
1937 req_includes = set(kwargs.get(r'includepats', []))
1938 req_excludes = set(kwargs.get(r'excludepats', []))
1938 req_excludes = set(kwargs.get(r'excludepats', []))
1939
1939
1940 req_includes, req_excludes, invalid_includes = narrowspec.restrictpatterns(
1940 req_includes, req_excludes, invalid_includes = narrowspec.restrictpatterns(
1941 req_includes, req_excludes, user_includes, user_excludes)
1941 req_includes, req_excludes, user_includes, user_excludes)
1942
1942
1943 if invalid_includes:
1943 if invalid_includes:
1944 raise error.Abort(
1944 raise error.Abort(
1945 _("The following includes are not accessible for {}: {}")
1945 _("The following includes are not accessible for {}: {}")
1946 .format(username, invalid_includes))
1946 .format(username, invalid_includes))
1947
1947
1948 new_args = {}
1948 new_args = {}
1949 new_args.update(kwargs)
1949 new_args.update(kwargs)
1950 new_args[r'narrow'] = True
1950 new_args[r'narrow'] = True
1951 new_args[r'narrow_acl'] = True
1951 new_args[r'narrow_acl'] = True
1952 new_args[r'includepats'] = req_includes
1952 new_args[r'includepats'] = req_includes
1953 if req_excludes:
1953 if req_excludes:
1954 new_args[r'excludepats'] = req_excludes
1954 new_args[r'excludepats'] = req_excludes
1955
1955
1956 return new_args
1956 return new_args
1957
1957
1958 def _computeellipsis(repo, common, heads, known, match, depth=None):
1958 def _computeellipsis(repo, common, heads, known, match, depth=None):
1959 """Compute the shape of a narrowed DAG.
1959 """Compute the shape of a narrowed DAG.
1960
1960
1961 Args:
1961 Args:
1962 repo: The repository we're transferring.
1962 repo: The repository we're transferring.
1963 common: The roots of the DAG range we're transferring.
1963 common: The roots of the DAG range we're transferring.
1964 May be just [nullid], which means all ancestors of heads.
1964 May be just [nullid], which means all ancestors of heads.
1965 heads: The heads of the DAG range we're transferring.
1965 heads: The heads of the DAG range we're transferring.
1966 match: The narrowmatcher that allows us to identify relevant changes.
1966 match: The narrowmatcher that allows us to identify relevant changes.
1967 depth: If not None, only consider nodes to be full nodes if they are at
1967 depth: If not None, only consider nodes to be full nodes if they are at
1968 most depth changesets away from one of heads.
1968 most depth changesets away from one of heads.
1969
1969
1970 Returns:
1970 Returns:
1971 A tuple of (visitnodes, relevant_nodes, ellipsisroots) where:
1971 A tuple of (visitnodes, relevant_nodes, ellipsisroots) where:
1972
1972
1973 visitnodes: The list of nodes (either full or ellipsis) which
1973 visitnodes: The list of nodes (either full or ellipsis) which
1974 need to be sent to the client.
1974 need to be sent to the client.
1975 relevant_nodes: The set of changelog nodes which change a file inside
1975 relevant_nodes: The set of changelog nodes which change a file inside
1976 the narrowspec. The client needs these as non-ellipsis nodes.
1976 the narrowspec. The client needs these as non-ellipsis nodes.
1977 ellipsisroots: A dict of {rev: parents} that is used in
1977 ellipsisroots: A dict of {rev: parents} that is used in
1978 narrowchangegroup to produce ellipsis nodes with the
1978 narrowchangegroup to produce ellipsis nodes with the
1979 correct parents.
1979 correct parents.
1980 """
1980 """
1981 cl = repo.changelog
1981 cl = repo.changelog
1982 mfl = repo.manifestlog
1982 mfl = repo.manifestlog
1983
1983
1984 clrev = cl.rev
1984 clrev = cl.rev
1985
1985
1986 commonrevs = {clrev(n) for n in common} | {nullrev}
1986 commonrevs = {clrev(n) for n in common} | {nullrev}
1987 headsrevs = {clrev(n) for n in heads}
1987 headsrevs = {clrev(n) for n in heads}
1988
1988
1989 if depth:
1989 if depth:
1990 revdepth = {h: 0 for h in headsrevs}
1990 revdepth = {h: 0 for h in headsrevs}
1991
1991
1992 ellipsisheads = collections.defaultdict(set)
1992 ellipsisheads = collections.defaultdict(set)
1993 ellipsisroots = collections.defaultdict(set)
1993 ellipsisroots = collections.defaultdict(set)
1994
1994
1995 def addroot(head, curchange):
1995 def addroot(head, curchange):
1996 """Add a root to an ellipsis head, splitting heads with 3 roots."""
1996 """Add a root to an ellipsis head, splitting heads with 3 roots."""
1997 ellipsisroots[head].add(curchange)
1997 ellipsisroots[head].add(curchange)
1998 # Recursively split ellipsis heads with 3 roots by finding the
1998 # Recursively split ellipsis heads with 3 roots by finding the
1999 # roots' youngest common descendant which is an elided merge commit.
1999 # roots' youngest common descendant which is an elided merge commit.
2000 # That descendant takes 2 of the 3 roots as its own, and becomes a
2000 # That descendant takes 2 of the 3 roots as its own, and becomes a
2001 # root of the head.
2001 # root of the head.
2002 while len(ellipsisroots[head]) > 2:
2002 while len(ellipsisroots[head]) > 2:
2003 child, roots = splithead(head)
2003 child, roots = splithead(head)
2004 splitroots(head, child, roots)
2004 splitroots(head, child, roots)
2005 head = child # Recurse in case we just added a 3rd root
2005 head = child # Recurse in case we just added a 3rd root
2006
2006
2007 def splitroots(head, child, roots):
2007 def splitroots(head, child, roots):
2008 ellipsisroots[head].difference_update(roots)
2008 ellipsisroots[head].difference_update(roots)
2009 ellipsisroots[head].add(child)
2009 ellipsisroots[head].add(child)
2010 ellipsisroots[child].update(roots)
2010 ellipsisroots[child].update(roots)
2011 ellipsisroots[child].discard(child)
2011 ellipsisroots[child].discard(child)
2012
2012
2013 def splithead(head):
2013 def splithead(head):
2014 r1, r2, r3 = sorted(ellipsisroots[head])
2014 r1, r2, r3 = sorted(ellipsisroots[head])
2015 for nr1, nr2 in ((r2, r3), (r1, r3), (r1, r2)):
2015 for nr1, nr2 in ((r2, r3), (r1, r3), (r1, r2)):
2016 mid = repo.revs('sort(merge() & %d::%d & %d::%d, -rev)',
2016 mid = repo.revs('sort(merge() & %d::%d & %d::%d, -rev)',
2017 nr1, head, nr2, head)
2017 nr1, head, nr2, head)
2018 for j in mid:
2018 for j in mid:
2019 if j == nr2:
2019 if j == nr2:
2020 return nr2, (nr1, nr2)
2020 return nr2, (nr1, nr2)
2021 if j not in ellipsisroots or len(ellipsisroots[j]) < 2:
2021 if j not in ellipsisroots or len(ellipsisroots[j]) < 2:
2022 return j, (nr1, nr2)
2022 return j, (nr1, nr2)
2023 raise error.Abort(_('Failed to split up ellipsis node! head: %d, '
2023 raise error.Abort(_('Failed to split up ellipsis node! head: %d, '
2024 'roots: %d %d %d') % (head, r1, r2, r3))
2024 'roots: %d %d %d') % (head, r1, r2, r3))
2025
2025
2026 missing = list(cl.findmissingrevs(common=commonrevs, heads=headsrevs))
2026 missing = list(cl.findmissingrevs(common=commonrevs, heads=headsrevs))
2027 visit = reversed(missing)
2027 visit = reversed(missing)
2028 relevant_nodes = set()
2028 relevant_nodes = set()
2029 visitnodes = [cl.node(m) for m in missing]
2029 visitnodes = [cl.node(m) for m in missing]
2030 required = set(headsrevs) | known
2030 required = set(headsrevs) | known
2031 for rev in visit:
2031 for rev in visit:
2032 clrev = cl.changelogrevision(rev)
2032 clrev = cl.changelogrevision(rev)
2033 ps = [prev for prev in cl.parentrevs(rev) if prev != nullrev]
2033 ps = [prev for prev in cl.parentrevs(rev) if prev != nullrev]
2034 if depth is not None:
2034 if depth is not None:
2035 curdepth = revdepth[rev]
2035 curdepth = revdepth[rev]
2036 for p in ps:
2036 for p in ps:
2037 revdepth[p] = min(curdepth + 1, revdepth.get(p, depth + 1))
2037 revdepth[p] = min(curdepth + 1, revdepth.get(p, depth + 1))
2038 needed = False
2038 needed = False
2039 shallow_enough = depth is None or revdepth[rev] <= depth
2039 shallow_enough = depth is None or revdepth[rev] <= depth
2040 if shallow_enough:
2040 if shallow_enough:
2041 curmf = mfl[clrev.manifest].read()
2041 curmf = mfl[clrev.manifest].read()
2042 if ps:
2042 if ps:
2043 # We choose to not trust the changed files list in
2043 # We choose to not trust the changed files list in
2044 # changesets because it's not always correct. TODO: could
2044 # changesets because it's not always correct. TODO: could
2045 # we trust it for the non-merge case?
2045 # we trust it for the non-merge case?
2046 p1mf = mfl[cl.changelogrevision(ps[0]).manifest].read()
2046 p1mf = mfl[cl.changelogrevision(ps[0]).manifest].read()
2047 needed = bool(curmf.diff(p1mf, match))
2047 needed = bool(curmf.diff(p1mf, match))
2048 if not needed and len(ps) > 1:
2048 if not needed and len(ps) > 1:
2049 # For merge changes, the list of changed files is not
2049 # For merge changes, the list of changed files is not
2050 # helpful, since we need to emit the merge if a file
2050 # helpful, since we need to emit the merge if a file
2051 # in the narrow spec has changed on either side of the
2051 # in the narrow spec has changed on either side of the
2052 # merge. As a result, we do a manifest diff to check.
2052 # merge. As a result, we do a manifest diff to check.
2053 p2mf = mfl[cl.changelogrevision(ps[1]).manifest].read()
2053 p2mf = mfl[cl.changelogrevision(ps[1]).manifest].read()
2054 needed = bool(curmf.diff(p2mf, match))
2054 needed = bool(curmf.diff(p2mf, match))
2055 else:
2055 else:
2056 # For a root node, we need to include the node if any
2056 # For a root node, we need to include the node if any
2057 # files in the node match the narrowspec.
2057 # files in the node match the narrowspec.
2058 needed = any(curmf.walk(match))
2058 needed = any(curmf.walk(match))
2059
2059
2060 if needed:
2060 if needed:
2061 for head in ellipsisheads[rev]:
2061 for head in ellipsisheads[rev]:
2062 addroot(head, rev)
2062 addroot(head, rev)
2063 for p in ps:
2063 for p in ps:
2064 required.add(p)
2064 required.add(p)
2065 relevant_nodes.add(cl.node(rev))
2065 relevant_nodes.add(cl.node(rev))
2066 else:
2066 else:
2067 if not ps:
2067 if not ps:
2068 ps = [nullrev]
2068 ps = [nullrev]
2069 if rev in required:
2069 if rev in required:
2070 for head in ellipsisheads[rev]:
2070 for head in ellipsisheads[rev]:
2071 addroot(head, rev)
2071 addroot(head, rev)
2072 for p in ps:
2072 for p in ps:
2073 ellipsisheads[p].add(rev)
2073 ellipsisheads[p].add(rev)
2074 else:
2074 else:
2075 for p in ps:
2075 for p in ps:
2076 ellipsisheads[p] |= ellipsisheads[rev]
2076 ellipsisheads[p] |= ellipsisheads[rev]
2077
2077
2078 # add common changesets as roots of their reachable ellipsis heads
2078 # add common changesets as roots of their reachable ellipsis heads
2079 for c in commonrevs:
2079 for c in commonrevs:
2080 for head in ellipsisheads[c]:
2080 for head in ellipsisheads[c]:
2081 addroot(head, c)
2081 addroot(head, c)
2082 return visitnodes, relevant_nodes, ellipsisroots
2082 return visitnodes, relevant_nodes, ellipsisroots
2083
2083
2084 def caps20to10(repo, role):
2084 def caps20to10(repo, role):
2085 """return a set with appropriate options to use bundle20 during getbundle"""
2085 """return a set with appropriate options to use bundle20 during getbundle"""
2086 caps = {'HG20'}
2086 caps = {'HG20'}
2087 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo, role=role))
2087 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo, role=role))
2088 caps.add('bundle2=' + urlreq.quote(capsblob))
2088 caps.add('bundle2=' + urlreq.quote(capsblob))
2089 return caps
2089 return caps
2090
2090
2091 # List of names of steps to perform for a bundle2 for getbundle, order matters.
2091 # List of names of steps to perform for a bundle2 for getbundle, order matters.
2092 getbundle2partsorder = []
2092 getbundle2partsorder = []
2093
2093
2094 # Mapping between step name and function
2094 # Mapping between step name and function
2095 #
2095 #
2096 # This exists to help extensions wrap steps if necessary
2096 # This exists to help extensions wrap steps if necessary
2097 getbundle2partsmapping = {}
2097 getbundle2partsmapping = {}
2098
2098
2099 def getbundle2partsgenerator(stepname, idx=None):
2099 def getbundle2partsgenerator(stepname, idx=None):
2100 """decorator for function generating bundle2 part for getbundle
2100 """decorator for function generating bundle2 part for getbundle
2101
2101
2102 The function is added to the step -> function mapping and appended to the
2102 The function is added to the step -> function mapping and appended to the
2103 list of steps. Beware that decorated functions will be added in order
2103 list of steps. Beware that decorated functions will be added in order
2104 (this may matter).
2104 (this may matter).
2105
2105
2106 You can only use this decorator for new steps, if you want to wrap a step
2106 You can only use this decorator for new steps, if you want to wrap a step
2107 from an extension, attack the getbundle2partsmapping dictionary directly."""
2107 from an extension, attack the getbundle2partsmapping dictionary directly."""
2108 def dec(func):
2108 def dec(func):
2109 assert stepname not in getbundle2partsmapping
2109 assert stepname not in getbundle2partsmapping
2110 getbundle2partsmapping[stepname] = func
2110 getbundle2partsmapping[stepname] = func
2111 if idx is None:
2111 if idx is None:
2112 getbundle2partsorder.append(stepname)
2112 getbundle2partsorder.append(stepname)
2113 else:
2113 else:
2114 getbundle2partsorder.insert(idx, stepname)
2114 getbundle2partsorder.insert(idx, stepname)
2115 return func
2115 return func
2116 return dec
2116 return dec
2117
2117
2118 def bundle2requested(bundlecaps):
2118 def bundle2requested(bundlecaps):
2119 if bundlecaps is not None:
2119 if bundlecaps is not None:
2120 return any(cap.startswith('HG2') for cap in bundlecaps)
2120 return any(cap.startswith('HG2') for cap in bundlecaps)
2121 return False
2121 return False
2122
2122
2123 def getbundlechunks(repo, source, heads=None, common=None, bundlecaps=None,
2123 def getbundlechunks(repo, source, heads=None, common=None, bundlecaps=None,
2124 **kwargs):
2124 **kwargs):
2125 """Return chunks constituting a bundle's raw data.
2125 """Return chunks constituting a bundle's raw data.
2126
2126
2127 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
2127 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
2128 passed.
2128 passed.
2129
2129
2130 Returns a 2-tuple of a dict with metadata about the generated bundle
2130 Returns a 2-tuple of a dict with metadata about the generated bundle
2131 and an iterator over raw chunks (of varying sizes).
2131 and an iterator over raw chunks (of varying sizes).
2132 """
2132 """
2133 kwargs = pycompat.byteskwargs(kwargs)
2133 kwargs = pycompat.byteskwargs(kwargs)
2134 info = {}
2134 info = {}
2135 usebundle2 = bundle2requested(bundlecaps)
2135 usebundle2 = bundle2requested(bundlecaps)
2136 # bundle10 case
2136 # bundle10 case
2137 if not usebundle2:
2137 if not usebundle2:
2138 if bundlecaps and not kwargs.get('cg', True):
2138 if bundlecaps and not kwargs.get('cg', True):
2139 raise ValueError(_('request for bundle10 must include changegroup'))
2139 raise ValueError(_('request for bundle10 must include changegroup'))
2140
2140
2141 if kwargs:
2141 if kwargs:
2142 raise ValueError(_('unsupported getbundle arguments: %s')
2142 raise ValueError(_('unsupported getbundle arguments: %s')
2143 % ', '.join(sorted(kwargs.keys())))
2143 % ', '.join(sorted(kwargs.keys())))
2144 outgoing = _computeoutgoing(repo, heads, common)
2144 outgoing = _computeoutgoing(repo, heads, common)
2145 info['bundleversion'] = 1
2145 info['bundleversion'] = 1
2146 return info, changegroup.makestream(repo, outgoing, '01', source,
2146 return info, changegroup.makestream(repo, outgoing, '01', source,
2147 bundlecaps=bundlecaps)
2147 bundlecaps=bundlecaps)
2148
2148
2149 # bundle20 case
2149 # bundle20 case
2150 info['bundleversion'] = 2
2150 info['bundleversion'] = 2
2151 b2caps = {}
2151 b2caps = {}
2152 for bcaps in bundlecaps:
2152 for bcaps in bundlecaps:
2153 if bcaps.startswith('bundle2='):
2153 if bcaps.startswith('bundle2='):
2154 blob = urlreq.unquote(bcaps[len('bundle2='):])
2154 blob = urlreq.unquote(bcaps[len('bundle2='):])
2155 b2caps.update(bundle2.decodecaps(blob))
2155 b2caps.update(bundle2.decodecaps(blob))
2156 bundler = bundle2.bundle20(repo.ui, b2caps)
2156 bundler = bundle2.bundle20(repo.ui, b2caps)
2157
2157
2158 kwargs['heads'] = heads
2158 kwargs['heads'] = heads
2159 kwargs['common'] = common
2159 kwargs['common'] = common
2160
2160
2161 for name in getbundle2partsorder:
2161 for name in getbundle2partsorder:
2162 func = getbundle2partsmapping[name]
2162 func = getbundle2partsmapping[name]
2163 func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
2163 func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
2164 **pycompat.strkwargs(kwargs))
2164 **pycompat.strkwargs(kwargs))
2165
2165
2166 info['prefercompressed'] = bundler.prefercompressed
2166 info['prefercompressed'] = bundler.prefercompressed
2167
2167
2168 return info, bundler.getchunks()
2168 return info, bundler.getchunks()
2169
2169
2170 @getbundle2partsgenerator('stream2')
2170 @getbundle2partsgenerator('stream2')
2171 def _getbundlestream2(bundler, repo, *args, **kwargs):
2171 def _getbundlestream2(bundler, repo, *args, **kwargs):
2172 return bundle2.addpartbundlestream2(bundler, repo, **kwargs)
2172 return bundle2.addpartbundlestream2(bundler, repo, **kwargs)
2173
2173
2174 @getbundle2partsgenerator('changegroup')
2174 @getbundle2partsgenerator('changegroup')
2175 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
2175 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
2176 b2caps=None, heads=None, common=None, **kwargs):
2176 b2caps=None, heads=None, common=None, **kwargs):
2177 """add a changegroup part to the requested bundle"""
2177 """add a changegroup part to the requested bundle"""
2178 if not kwargs.get(r'cg', True):
2178 if not kwargs.get(r'cg', True):
2179 return
2179 return
2180
2180
2181 version = '01'
2181 version = '01'
2182 cgversions = b2caps.get('changegroup')
2182 cgversions = b2caps.get('changegroup')
2183 if cgversions: # 3.1 and 3.2 ship with an empty value
2183 if cgversions: # 3.1 and 3.2 ship with an empty value
2184 cgversions = [v for v in cgversions
2184 cgversions = [v for v in cgversions
2185 if v in changegroup.supportedoutgoingversions(repo)]
2185 if v in changegroup.supportedoutgoingversions(repo)]
2186 if not cgversions:
2186 if not cgversions:
2187 raise error.Abort(_('no common changegroup version'))
2187 raise error.Abort(_('no common changegroup version'))
2188 version = max(cgversions)
2188 version = max(cgversions)
2189
2189
2190 outgoing = _computeoutgoing(repo, heads, common)
2190 outgoing = _computeoutgoing(repo, heads, common)
2191 if not outgoing.missing:
2191 if not outgoing.missing:
2192 return
2192 return
2193
2193
2194 if kwargs.get(r'narrow', False):
2194 if kwargs.get(r'narrow', False):
2195 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
2195 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
2196 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
2196 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
2197 matcher = narrowspec.match(repo.root, include=include, exclude=exclude)
2197 matcher = narrowspec.match(repo.root, include=include, exclude=exclude)
2198 else:
2198 else:
2199 matcher = None
2199 matcher = None
2200
2200
2201 cgstream = changegroup.makestream(repo, outgoing, version, source,
2201 cgstream = changegroup.makestream(repo, outgoing, version, source,
2202 bundlecaps=bundlecaps, matcher=matcher)
2202 bundlecaps=bundlecaps, matcher=matcher)
2203
2203
2204 part = bundler.newpart('changegroup', data=cgstream)
2204 part = bundler.newpart('changegroup', data=cgstream)
2205 if cgversions:
2205 if cgversions:
2206 part.addparam('version', version)
2206 part.addparam('version', version)
2207
2207
2208 part.addparam('nbchanges', '%d' % len(outgoing.missing),
2208 part.addparam('nbchanges', '%d' % len(outgoing.missing),
2209 mandatory=False)
2209 mandatory=False)
2210
2210
2211 if 'treemanifest' in repo.requirements:
2211 if 'treemanifest' in repo.requirements:
2212 part.addparam('treemanifest', '1')
2212 part.addparam('treemanifest', '1')
2213
2213
2214 if (kwargs.get(r'narrow', False) and kwargs.get(r'narrow_acl', False)
2214 if (kwargs.get(r'narrow', False) and kwargs.get(r'narrow_acl', False)
2215 and (include or exclude)):
2215 and (include or exclude)):
2216 narrowspecpart = bundler.newpart('narrow:spec')
2216 # this is mandatory because otherwise ACL clients won't work
2217 if include:
2217 narrowspecpart = bundler.newpart('Narrow:responsespec')
2218 narrowspecpart.addparam(
2218 narrowspecpart.data = '%s\0%s' % ('\n'.join(include),
2219 'include', '\n'.join(include), mandatory=True)
2219 '\n'.join(exclude))
2220 if exclude:
2221 narrowspecpart.addparam(
2222 'exclude', '\n'.join(exclude), mandatory=True)
2223
2220
2224 @getbundle2partsgenerator('bookmarks')
2221 @getbundle2partsgenerator('bookmarks')
2225 def _getbundlebookmarkpart(bundler, repo, source, bundlecaps=None,
2222 def _getbundlebookmarkpart(bundler, repo, source, bundlecaps=None,
2226 b2caps=None, **kwargs):
2223 b2caps=None, **kwargs):
2227 """add a bookmark part to the requested bundle"""
2224 """add a bookmark part to the requested bundle"""
2228 if not kwargs.get(r'bookmarks', False):
2225 if not kwargs.get(r'bookmarks', False):
2229 return
2226 return
2230 if 'bookmarks' not in b2caps:
2227 if 'bookmarks' not in b2caps:
2231 raise error.Abort(_('no common bookmarks exchange method'))
2228 raise error.Abort(_('no common bookmarks exchange method'))
2232 books = bookmod.listbinbookmarks(repo)
2229 books = bookmod.listbinbookmarks(repo)
2233 data = bookmod.binaryencode(books)
2230 data = bookmod.binaryencode(books)
2234 if data:
2231 if data:
2235 bundler.newpart('bookmarks', data=data)
2232 bundler.newpart('bookmarks', data=data)
2236
2233
2237 @getbundle2partsgenerator('listkeys')
2234 @getbundle2partsgenerator('listkeys')
2238 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
2235 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
2239 b2caps=None, **kwargs):
2236 b2caps=None, **kwargs):
2240 """add parts containing listkeys namespaces to the requested bundle"""
2237 """add parts containing listkeys namespaces to the requested bundle"""
2241 listkeys = kwargs.get(r'listkeys', ())
2238 listkeys = kwargs.get(r'listkeys', ())
2242 for namespace in listkeys:
2239 for namespace in listkeys:
2243 part = bundler.newpart('listkeys')
2240 part = bundler.newpart('listkeys')
2244 part.addparam('namespace', namespace)
2241 part.addparam('namespace', namespace)
2245 keys = repo.listkeys(namespace).items()
2242 keys = repo.listkeys(namespace).items()
2246 part.data = pushkey.encodekeys(keys)
2243 part.data = pushkey.encodekeys(keys)
2247
2244
2248 @getbundle2partsgenerator('obsmarkers')
2245 @getbundle2partsgenerator('obsmarkers')
2249 def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None,
2246 def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None,
2250 b2caps=None, heads=None, **kwargs):
2247 b2caps=None, heads=None, **kwargs):
2251 """add an obsolescence markers part to the requested bundle"""
2248 """add an obsolescence markers part to the requested bundle"""
2252 if kwargs.get(r'obsmarkers', False):
2249 if kwargs.get(r'obsmarkers', False):
2253 if heads is None:
2250 if heads is None:
2254 heads = repo.heads()
2251 heads = repo.heads()
2255 subset = [c.node() for c in repo.set('::%ln', heads)]
2252 subset = [c.node() for c in repo.set('::%ln', heads)]
2256 markers = repo.obsstore.relevantmarkers(subset)
2253 markers = repo.obsstore.relevantmarkers(subset)
2257 markers = sorted(markers)
2254 markers = sorted(markers)
2258 bundle2.buildobsmarkerspart(bundler, markers)
2255 bundle2.buildobsmarkerspart(bundler, markers)
2259
2256
2260 @getbundle2partsgenerator('phases')
2257 @getbundle2partsgenerator('phases')
2261 def _getbundlephasespart(bundler, repo, source, bundlecaps=None,
2258 def _getbundlephasespart(bundler, repo, source, bundlecaps=None,
2262 b2caps=None, heads=None, **kwargs):
2259 b2caps=None, heads=None, **kwargs):
2263 """add phase heads part to the requested bundle"""
2260 """add phase heads part to the requested bundle"""
2264 if kwargs.get(r'phases', False):
2261 if kwargs.get(r'phases', False):
2265 if not 'heads' in b2caps.get('phases'):
2262 if not 'heads' in b2caps.get('phases'):
2266 raise error.Abort(_('no common phases exchange method'))
2263 raise error.Abort(_('no common phases exchange method'))
2267 if heads is None:
2264 if heads is None:
2268 heads = repo.heads()
2265 heads = repo.heads()
2269
2266
2270 headsbyphase = collections.defaultdict(set)
2267 headsbyphase = collections.defaultdict(set)
2271 if repo.publishing():
2268 if repo.publishing():
2272 headsbyphase[phases.public] = heads
2269 headsbyphase[phases.public] = heads
2273 else:
2270 else:
2274 # find the appropriate heads to move
2271 # find the appropriate heads to move
2275
2272
2276 phase = repo._phasecache.phase
2273 phase = repo._phasecache.phase
2277 node = repo.changelog.node
2274 node = repo.changelog.node
2278 rev = repo.changelog.rev
2275 rev = repo.changelog.rev
2279 for h in heads:
2276 for h in heads:
2280 headsbyphase[phase(repo, rev(h))].add(h)
2277 headsbyphase[phase(repo, rev(h))].add(h)
2281 seenphases = list(headsbyphase.keys())
2278 seenphases = list(headsbyphase.keys())
2282
2279
2283 # We do not handle anything but public and draft phase for now)
2280 # We do not handle anything but public and draft phase for now)
2284 if seenphases:
2281 if seenphases:
2285 assert max(seenphases) <= phases.draft
2282 assert max(seenphases) <= phases.draft
2286
2283
2287 # if client is pulling non-public changesets, we need to find
2284 # if client is pulling non-public changesets, we need to find
2288 # intermediate public heads.
2285 # intermediate public heads.
2289 draftheads = headsbyphase.get(phases.draft, set())
2286 draftheads = headsbyphase.get(phases.draft, set())
2290 if draftheads:
2287 if draftheads:
2291 publicheads = headsbyphase.get(phases.public, set())
2288 publicheads = headsbyphase.get(phases.public, set())
2292
2289
2293 revset = 'heads(only(%ln, %ln) and public())'
2290 revset = 'heads(only(%ln, %ln) and public())'
2294 extraheads = repo.revs(revset, draftheads, publicheads)
2291 extraheads = repo.revs(revset, draftheads, publicheads)
2295 for r in extraheads:
2292 for r in extraheads:
2296 headsbyphase[phases.public].add(node(r))
2293 headsbyphase[phases.public].add(node(r))
2297
2294
2298 # transform data in a format used by the encoding function
2295 # transform data in a format used by the encoding function
2299 phasemapping = []
2296 phasemapping = []
2300 for phase in phases.allphases:
2297 for phase in phases.allphases:
2301 phasemapping.append(sorted(headsbyphase[phase]))
2298 phasemapping.append(sorted(headsbyphase[phase]))
2302
2299
2303 # generate the actual part
2300 # generate the actual part
2304 phasedata = phases.binaryencode(phasemapping)
2301 phasedata = phases.binaryencode(phasemapping)
2305 bundler.newpart('phase-heads', data=phasedata)
2302 bundler.newpart('phase-heads', data=phasedata)
2306
2303
2307 @getbundle2partsgenerator('hgtagsfnodes')
2304 @getbundle2partsgenerator('hgtagsfnodes')
2308 def _getbundletagsfnodes(bundler, repo, source, bundlecaps=None,
2305 def _getbundletagsfnodes(bundler, repo, source, bundlecaps=None,
2309 b2caps=None, heads=None, common=None,
2306 b2caps=None, heads=None, common=None,
2310 **kwargs):
2307 **kwargs):
2311 """Transfer the .hgtags filenodes mapping.
2308 """Transfer the .hgtags filenodes mapping.
2312
2309
2313 Only values for heads in this bundle will be transferred.
2310 Only values for heads in this bundle will be transferred.
2314
2311
2315 The part data consists of pairs of 20 byte changeset node and .hgtags
2312 The part data consists of pairs of 20 byte changeset node and .hgtags
2316 filenodes raw values.
2313 filenodes raw values.
2317 """
2314 """
2318 # Don't send unless:
2315 # Don't send unless:
2319 # - changeset are being exchanged,
2316 # - changeset are being exchanged,
2320 # - the client supports it.
2317 # - the client supports it.
2321 if not (kwargs.get(r'cg', True) and 'hgtagsfnodes' in b2caps):
2318 if not (kwargs.get(r'cg', True) and 'hgtagsfnodes' in b2caps):
2322 return
2319 return
2323
2320
2324 outgoing = _computeoutgoing(repo, heads, common)
2321 outgoing = _computeoutgoing(repo, heads, common)
2325 bundle2.addparttagsfnodescache(repo, bundler, outgoing)
2322 bundle2.addparttagsfnodescache(repo, bundler, outgoing)
2326
2323
2327 @getbundle2partsgenerator('cache:rev-branch-cache')
2324 @getbundle2partsgenerator('cache:rev-branch-cache')
2328 def _getbundlerevbranchcache(bundler, repo, source, bundlecaps=None,
2325 def _getbundlerevbranchcache(bundler, repo, source, bundlecaps=None,
2329 b2caps=None, heads=None, common=None,
2326 b2caps=None, heads=None, common=None,
2330 **kwargs):
2327 **kwargs):
2331 """Transfer the rev-branch-cache mapping
2328 """Transfer the rev-branch-cache mapping
2332
2329
2333 The payload is a series of data related to each branch
2330 The payload is a series of data related to each branch
2334
2331
2335 1) branch name length
2332 1) branch name length
2336 2) number of open heads
2333 2) number of open heads
2337 3) number of closed heads
2334 3) number of closed heads
2338 4) open heads nodes
2335 4) open heads nodes
2339 5) closed heads nodes
2336 5) closed heads nodes
2340 """
2337 """
2341 # Don't send unless:
2338 # Don't send unless:
2342 # - changeset are being exchanged,
2339 # - changeset are being exchanged,
2343 # - the client supports it.
2340 # - the client supports it.
2344 # - narrow bundle isn't in play (not currently compatible).
2341 # - narrow bundle isn't in play (not currently compatible).
2345 if (not kwargs.get(r'cg', True)
2342 if (not kwargs.get(r'cg', True)
2346 or 'rev-branch-cache' not in b2caps
2343 or 'rev-branch-cache' not in b2caps
2347 or kwargs.get(r'narrow', False)
2344 or kwargs.get(r'narrow', False)
2348 or repo.ui.has_section(_NARROWACL_SECTION)):
2345 or repo.ui.has_section(_NARROWACL_SECTION)):
2349 return
2346 return
2350
2347
2351 outgoing = _computeoutgoing(repo, heads, common)
2348 outgoing = _computeoutgoing(repo, heads, common)
2352 bundle2.addpartrevbranchcache(repo, bundler, outgoing)
2349 bundle2.addpartrevbranchcache(repo, bundler, outgoing)
2353
2350
2354 def check_heads(repo, their_heads, context):
2351 def check_heads(repo, their_heads, context):
2355 """check if the heads of a repo have been modified
2352 """check if the heads of a repo have been modified
2356
2353
2357 Used by peer for unbundling.
2354 Used by peer for unbundling.
2358 """
2355 """
2359 heads = repo.heads()
2356 heads = repo.heads()
2360 heads_hash = hashlib.sha1(''.join(sorted(heads))).digest()
2357 heads_hash = hashlib.sha1(''.join(sorted(heads))).digest()
2361 if not (their_heads == ['force'] or their_heads == heads or
2358 if not (their_heads == ['force'] or their_heads == heads or
2362 their_heads == ['hashed', heads_hash]):
2359 their_heads == ['hashed', heads_hash]):
2363 # someone else committed/pushed/unbundled while we
2360 # someone else committed/pushed/unbundled while we
2364 # were transferring data
2361 # were transferring data
2365 raise error.PushRaced('repository changed while %s - '
2362 raise error.PushRaced('repository changed while %s - '
2366 'please try again' % context)
2363 'please try again' % context)
2367
2364
2368 def unbundle(repo, cg, heads, source, url):
2365 def unbundle(repo, cg, heads, source, url):
2369 """Apply a bundle to a repo.
2366 """Apply a bundle to a repo.
2370
2367
2371 this function makes sure the repo is locked during the application and have
2368 this function makes sure the repo is locked during the application and have
2372 mechanism to check that no push race occurred between the creation of the
2369 mechanism to check that no push race occurred between the creation of the
2373 bundle and its application.
2370 bundle and its application.
2374
2371
2375 If the push was raced as PushRaced exception is raised."""
2372 If the push was raced as PushRaced exception is raised."""
2376 r = 0
2373 r = 0
2377 # need a transaction when processing a bundle2 stream
2374 # need a transaction when processing a bundle2 stream
2378 # [wlock, lock, tr] - needs to be an array so nested functions can modify it
2375 # [wlock, lock, tr] - needs to be an array so nested functions can modify it
2379 lockandtr = [None, None, None]
2376 lockandtr = [None, None, None]
2380 recordout = None
2377 recordout = None
2381 # quick fix for output mismatch with bundle2 in 3.4
2378 # quick fix for output mismatch with bundle2 in 3.4
2382 captureoutput = repo.ui.configbool('experimental', 'bundle2-output-capture')
2379 captureoutput = repo.ui.configbool('experimental', 'bundle2-output-capture')
2383 if url.startswith('remote:http:') or url.startswith('remote:https:'):
2380 if url.startswith('remote:http:') or url.startswith('remote:https:'):
2384 captureoutput = True
2381 captureoutput = True
2385 try:
2382 try:
2386 # note: outside bundle1, 'heads' is expected to be empty and this
2383 # note: outside bundle1, 'heads' is expected to be empty and this
2387 # 'check_heads' call wil be a no-op
2384 # 'check_heads' call wil be a no-op
2388 check_heads(repo, heads, 'uploading changes')
2385 check_heads(repo, heads, 'uploading changes')
2389 # push can proceed
2386 # push can proceed
2390 if not isinstance(cg, bundle2.unbundle20):
2387 if not isinstance(cg, bundle2.unbundle20):
2391 # legacy case: bundle1 (changegroup 01)
2388 # legacy case: bundle1 (changegroup 01)
2392 txnname = "\n".join([source, util.hidepassword(url)])
2389 txnname = "\n".join([source, util.hidepassword(url)])
2393 with repo.lock(), repo.transaction(txnname) as tr:
2390 with repo.lock(), repo.transaction(txnname) as tr:
2394 op = bundle2.applybundle(repo, cg, tr, source, url)
2391 op = bundle2.applybundle(repo, cg, tr, source, url)
2395 r = bundle2.combinechangegroupresults(op)
2392 r = bundle2.combinechangegroupresults(op)
2396 else:
2393 else:
2397 r = None
2394 r = None
2398 try:
2395 try:
2399 def gettransaction():
2396 def gettransaction():
2400 if not lockandtr[2]:
2397 if not lockandtr[2]:
2401 lockandtr[0] = repo.wlock()
2398 lockandtr[0] = repo.wlock()
2402 lockandtr[1] = repo.lock()
2399 lockandtr[1] = repo.lock()
2403 lockandtr[2] = repo.transaction(source)
2400 lockandtr[2] = repo.transaction(source)
2404 lockandtr[2].hookargs['source'] = source
2401 lockandtr[2].hookargs['source'] = source
2405 lockandtr[2].hookargs['url'] = url
2402 lockandtr[2].hookargs['url'] = url
2406 lockandtr[2].hookargs['bundle2'] = '1'
2403 lockandtr[2].hookargs['bundle2'] = '1'
2407 return lockandtr[2]
2404 return lockandtr[2]
2408
2405
2409 # Do greedy locking by default until we're satisfied with lazy
2406 # Do greedy locking by default until we're satisfied with lazy
2410 # locking.
2407 # locking.
2411 if not repo.ui.configbool('experimental', 'bundle2lazylocking'):
2408 if not repo.ui.configbool('experimental', 'bundle2lazylocking'):
2412 gettransaction()
2409 gettransaction()
2413
2410
2414 op = bundle2.bundleoperation(repo, gettransaction,
2411 op = bundle2.bundleoperation(repo, gettransaction,
2415 captureoutput=captureoutput,
2412 captureoutput=captureoutput,
2416 source='push')
2413 source='push')
2417 try:
2414 try:
2418 op = bundle2.processbundle(repo, cg, op=op)
2415 op = bundle2.processbundle(repo, cg, op=op)
2419 finally:
2416 finally:
2420 r = op.reply
2417 r = op.reply
2421 if captureoutput and r is not None:
2418 if captureoutput and r is not None:
2422 repo.ui.pushbuffer(error=True, subproc=True)
2419 repo.ui.pushbuffer(error=True, subproc=True)
2423 def recordout(output):
2420 def recordout(output):
2424 r.newpart('output', data=output, mandatory=False)
2421 r.newpart('output', data=output, mandatory=False)
2425 if lockandtr[2] is not None:
2422 if lockandtr[2] is not None:
2426 lockandtr[2].close()
2423 lockandtr[2].close()
2427 except BaseException as exc:
2424 except BaseException as exc:
2428 exc.duringunbundle2 = True
2425 exc.duringunbundle2 = True
2429 if captureoutput and r is not None:
2426 if captureoutput and r is not None:
2430 parts = exc._bundle2salvagedoutput = r.salvageoutput()
2427 parts = exc._bundle2salvagedoutput = r.salvageoutput()
2431 def recordout(output):
2428 def recordout(output):
2432 part = bundle2.bundlepart('output', data=output,
2429 part = bundle2.bundlepart('output', data=output,
2433 mandatory=False)
2430 mandatory=False)
2434 parts.append(part)
2431 parts.append(part)
2435 raise
2432 raise
2436 finally:
2433 finally:
2437 lockmod.release(lockandtr[2], lockandtr[1], lockandtr[0])
2434 lockmod.release(lockandtr[2], lockandtr[1], lockandtr[0])
2438 if recordout is not None:
2435 if recordout is not None:
2439 recordout(repo.ui.popbuffer())
2436 recordout(repo.ui.popbuffer())
2440 return r
2437 return r
2441
2438
2442 def _maybeapplyclonebundle(pullop):
2439 def _maybeapplyclonebundle(pullop):
2443 """Apply a clone bundle from a remote, if possible."""
2440 """Apply a clone bundle from a remote, if possible."""
2444
2441
2445 repo = pullop.repo
2442 repo = pullop.repo
2446 remote = pullop.remote
2443 remote = pullop.remote
2447
2444
2448 if not repo.ui.configbool('ui', 'clonebundles'):
2445 if not repo.ui.configbool('ui', 'clonebundles'):
2449 return
2446 return
2450
2447
2451 # Only run if local repo is empty.
2448 # Only run if local repo is empty.
2452 if len(repo):
2449 if len(repo):
2453 return
2450 return
2454
2451
2455 if pullop.heads:
2452 if pullop.heads:
2456 return
2453 return
2457
2454
2458 if not remote.capable('clonebundles'):
2455 if not remote.capable('clonebundles'):
2459 return
2456 return
2460
2457
2461 with remote.commandexecutor() as e:
2458 with remote.commandexecutor() as e:
2462 res = e.callcommand('clonebundles', {}).result()
2459 res = e.callcommand('clonebundles', {}).result()
2463
2460
2464 # If we call the wire protocol command, that's good enough to record the
2461 # If we call the wire protocol command, that's good enough to record the
2465 # attempt.
2462 # attempt.
2466 pullop.clonebundleattempted = True
2463 pullop.clonebundleattempted = True
2467
2464
2468 entries = parseclonebundlesmanifest(repo, res)
2465 entries = parseclonebundlesmanifest(repo, res)
2469 if not entries:
2466 if not entries:
2470 repo.ui.note(_('no clone bundles available on remote; '
2467 repo.ui.note(_('no clone bundles available on remote; '
2471 'falling back to regular clone\n'))
2468 'falling back to regular clone\n'))
2472 return
2469 return
2473
2470
2474 entries = filterclonebundleentries(
2471 entries = filterclonebundleentries(
2475 repo, entries, streamclonerequested=pullop.streamclonerequested)
2472 repo, entries, streamclonerequested=pullop.streamclonerequested)
2476
2473
2477 if not entries:
2474 if not entries:
2478 # There is a thundering herd concern here. However, if a server
2475 # There is a thundering herd concern here. However, if a server
2479 # operator doesn't advertise bundles appropriate for its clients,
2476 # operator doesn't advertise bundles appropriate for its clients,
2480 # they deserve what's coming. Furthermore, from a client's
2477 # they deserve what's coming. Furthermore, from a client's
2481 # perspective, no automatic fallback would mean not being able to
2478 # perspective, no automatic fallback would mean not being able to
2482 # clone!
2479 # clone!
2483 repo.ui.warn(_('no compatible clone bundles available on server; '
2480 repo.ui.warn(_('no compatible clone bundles available on server; '
2484 'falling back to regular clone\n'))
2481 'falling back to regular clone\n'))
2485 repo.ui.warn(_('(you may want to report this to the server '
2482 repo.ui.warn(_('(you may want to report this to the server '
2486 'operator)\n'))
2483 'operator)\n'))
2487 return
2484 return
2488
2485
2489 entries = sortclonebundleentries(repo.ui, entries)
2486 entries = sortclonebundleentries(repo.ui, entries)
2490
2487
2491 url = entries[0]['URL']
2488 url = entries[0]['URL']
2492 repo.ui.status(_('applying clone bundle from %s\n') % url)
2489 repo.ui.status(_('applying clone bundle from %s\n') % url)
2493 if trypullbundlefromurl(repo.ui, repo, url):
2490 if trypullbundlefromurl(repo.ui, repo, url):
2494 repo.ui.status(_('finished applying clone bundle\n'))
2491 repo.ui.status(_('finished applying clone bundle\n'))
2495 # Bundle failed.
2492 # Bundle failed.
2496 #
2493 #
2497 # We abort by default to avoid the thundering herd of
2494 # We abort by default to avoid the thundering herd of
2498 # clients flooding a server that was expecting expensive
2495 # clients flooding a server that was expecting expensive
2499 # clone load to be offloaded.
2496 # clone load to be offloaded.
2500 elif repo.ui.configbool('ui', 'clonebundlefallback'):
2497 elif repo.ui.configbool('ui', 'clonebundlefallback'):
2501 repo.ui.warn(_('falling back to normal clone\n'))
2498 repo.ui.warn(_('falling back to normal clone\n'))
2502 else:
2499 else:
2503 raise error.Abort(_('error applying bundle'),
2500 raise error.Abort(_('error applying bundle'),
2504 hint=_('if this error persists, consider contacting '
2501 hint=_('if this error persists, consider contacting '
2505 'the server operator or disable clone '
2502 'the server operator or disable clone '
2506 'bundles via '
2503 'bundles via '
2507 '"--config ui.clonebundles=false"'))
2504 '"--config ui.clonebundles=false"'))
2508
2505
2509 def parseclonebundlesmanifest(repo, s):
2506 def parseclonebundlesmanifest(repo, s):
2510 """Parses the raw text of a clone bundles manifest.
2507 """Parses the raw text of a clone bundles manifest.
2511
2508
2512 Returns a list of dicts. The dicts have a ``URL`` key corresponding
2509 Returns a list of dicts. The dicts have a ``URL`` key corresponding
2513 to the URL and other keys are the attributes for the entry.
2510 to the URL and other keys are the attributes for the entry.
2514 """
2511 """
2515 m = []
2512 m = []
2516 for line in s.splitlines():
2513 for line in s.splitlines():
2517 fields = line.split()
2514 fields = line.split()
2518 if not fields:
2515 if not fields:
2519 continue
2516 continue
2520 attrs = {'URL': fields[0]}
2517 attrs = {'URL': fields[0]}
2521 for rawattr in fields[1:]:
2518 for rawattr in fields[1:]:
2522 key, value = rawattr.split('=', 1)
2519 key, value = rawattr.split('=', 1)
2523 key = urlreq.unquote(key)
2520 key = urlreq.unquote(key)
2524 value = urlreq.unquote(value)
2521 value = urlreq.unquote(value)
2525 attrs[key] = value
2522 attrs[key] = value
2526
2523
2527 # Parse BUNDLESPEC into components. This makes client-side
2524 # Parse BUNDLESPEC into components. This makes client-side
2528 # preferences easier to specify since you can prefer a single
2525 # preferences easier to specify since you can prefer a single
2529 # component of the BUNDLESPEC.
2526 # component of the BUNDLESPEC.
2530 if key == 'BUNDLESPEC':
2527 if key == 'BUNDLESPEC':
2531 try:
2528 try:
2532 bundlespec = parsebundlespec(repo, value)
2529 bundlespec = parsebundlespec(repo, value)
2533 attrs['COMPRESSION'] = bundlespec.compression
2530 attrs['COMPRESSION'] = bundlespec.compression
2534 attrs['VERSION'] = bundlespec.version
2531 attrs['VERSION'] = bundlespec.version
2535 except error.InvalidBundleSpecification:
2532 except error.InvalidBundleSpecification:
2536 pass
2533 pass
2537 except error.UnsupportedBundleSpecification:
2534 except error.UnsupportedBundleSpecification:
2538 pass
2535 pass
2539
2536
2540 m.append(attrs)
2537 m.append(attrs)
2541
2538
2542 return m
2539 return m
2543
2540
2544 def isstreamclonespec(bundlespec):
2541 def isstreamclonespec(bundlespec):
2545 # Stream clone v1
2542 # Stream clone v1
2546 if (bundlespec.wirecompression == 'UN' and bundlespec.wireversion == 's1'):
2543 if (bundlespec.wirecompression == 'UN' and bundlespec.wireversion == 's1'):
2547 return True
2544 return True
2548
2545
2549 # Stream clone v2
2546 # Stream clone v2
2550 if (bundlespec.wirecompression == 'UN' and
2547 if (bundlespec.wirecompression == 'UN' and
2551 bundlespec.wireversion == '02' and
2548 bundlespec.wireversion == '02' and
2552 bundlespec.contentopts.get('streamv2')):
2549 bundlespec.contentopts.get('streamv2')):
2553 return True
2550 return True
2554
2551
2555 return False
2552 return False
2556
2553
2557 def filterclonebundleentries(repo, entries, streamclonerequested=False):
2554 def filterclonebundleentries(repo, entries, streamclonerequested=False):
2558 """Remove incompatible clone bundle manifest entries.
2555 """Remove incompatible clone bundle manifest entries.
2559
2556
2560 Accepts a list of entries parsed with ``parseclonebundlesmanifest``
2557 Accepts a list of entries parsed with ``parseclonebundlesmanifest``
2561 and returns a new list consisting of only the entries that this client
2558 and returns a new list consisting of only the entries that this client
2562 should be able to apply.
2559 should be able to apply.
2563
2560
2564 There is no guarantee we'll be able to apply all returned entries because
2561 There is no guarantee we'll be able to apply all returned entries because
2565 the metadata we use to filter on may be missing or wrong.
2562 the metadata we use to filter on may be missing or wrong.
2566 """
2563 """
2567 newentries = []
2564 newentries = []
2568 for entry in entries:
2565 for entry in entries:
2569 spec = entry.get('BUNDLESPEC')
2566 spec = entry.get('BUNDLESPEC')
2570 if spec:
2567 if spec:
2571 try:
2568 try:
2572 bundlespec = parsebundlespec(repo, spec, strict=True)
2569 bundlespec = parsebundlespec(repo, spec, strict=True)
2573
2570
2574 # If a stream clone was requested, filter out non-streamclone
2571 # If a stream clone was requested, filter out non-streamclone
2575 # entries.
2572 # entries.
2576 if streamclonerequested and not isstreamclonespec(bundlespec):
2573 if streamclonerequested and not isstreamclonespec(bundlespec):
2577 repo.ui.debug('filtering %s because not a stream clone\n' %
2574 repo.ui.debug('filtering %s because not a stream clone\n' %
2578 entry['URL'])
2575 entry['URL'])
2579 continue
2576 continue
2580
2577
2581 except error.InvalidBundleSpecification as e:
2578 except error.InvalidBundleSpecification as e:
2582 repo.ui.debug(stringutil.forcebytestr(e) + '\n')
2579 repo.ui.debug(stringutil.forcebytestr(e) + '\n')
2583 continue
2580 continue
2584 except error.UnsupportedBundleSpecification as e:
2581 except error.UnsupportedBundleSpecification as e:
2585 repo.ui.debug('filtering %s because unsupported bundle '
2582 repo.ui.debug('filtering %s because unsupported bundle '
2586 'spec: %s\n' % (
2583 'spec: %s\n' % (
2587 entry['URL'], stringutil.forcebytestr(e)))
2584 entry['URL'], stringutil.forcebytestr(e)))
2588 continue
2585 continue
2589 # If we don't have a spec and requested a stream clone, we don't know
2586 # If we don't have a spec and requested a stream clone, we don't know
2590 # what the entry is so don't attempt to apply it.
2587 # what the entry is so don't attempt to apply it.
2591 elif streamclonerequested:
2588 elif streamclonerequested:
2592 repo.ui.debug('filtering %s because cannot determine if a stream '
2589 repo.ui.debug('filtering %s because cannot determine if a stream '
2593 'clone bundle\n' % entry['URL'])
2590 'clone bundle\n' % entry['URL'])
2594 continue
2591 continue
2595
2592
2596 if 'REQUIRESNI' in entry and not sslutil.hassni:
2593 if 'REQUIRESNI' in entry and not sslutil.hassni:
2597 repo.ui.debug('filtering %s because SNI not supported\n' %
2594 repo.ui.debug('filtering %s because SNI not supported\n' %
2598 entry['URL'])
2595 entry['URL'])
2599 continue
2596 continue
2600
2597
2601 newentries.append(entry)
2598 newentries.append(entry)
2602
2599
2603 return newentries
2600 return newentries
2604
2601
2605 class clonebundleentry(object):
2602 class clonebundleentry(object):
2606 """Represents an item in a clone bundles manifest.
2603 """Represents an item in a clone bundles manifest.
2607
2604
2608 This rich class is needed to support sorting since sorted() in Python 3
2605 This rich class is needed to support sorting since sorted() in Python 3
2609 doesn't support ``cmp`` and our comparison is complex enough that ``key=``
2606 doesn't support ``cmp`` and our comparison is complex enough that ``key=``
2610 won't work.
2607 won't work.
2611 """
2608 """
2612
2609
2613 def __init__(self, value, prefers):
2610 def __init__(self, value, prefers):
2614 self.value = value
2611 self.value = value
2615 self.prefers = prefers
2612 self.prefers = prefers
2616
2613
2617 def _cmp(self, other):
2614 def _cmp(self, other):
2618 for prefkey, prefvalue in self.prefers:
2615 for prefkey, prefvalue in self.prefers:
2619 avalue = self.value.get(prefkey)
2616 avalue = self.value.get(prefkey)
2620 bvalue = other.value.get(prefkey)
2617 bvalue = other.value.get(prefkey)
2621
2618
2622 # Special case for b missing attribute and a matches exactly.
2619 # Special case for b missing attribute and a matches exactly.
2623 if avalue is not None and bvalue is None and avalue == prefvalue:
2620 if avalue is not None and bvalue is None and avalue == prefvalue:
2624 return -1
2621 return -1
2625
2622
2626 # Special case for a missing attribute and b matches exactly.
2623 # Special case for a missing attribute and b matches exactly.
2627 if bvalue is not None and avalue is None and bvalue == prefvalue:
2624 if bvalue is not None and avalue is None and bvalue == prefvalue:
2628 return 1
2625 return 1
2629
2626
2630 # We can't compare unless attribute present on both.
2627 # We can't compare unless attribute present on both.
2631 if avalue is None or bvalue is None:
2628 if avalue is None or bvalue is None:
2632 continue
2629 continue
2633
2630
2634 # Same values should fall back to next attribute.
2631 # Same values should fall back to next attribute.
2635 if avalue == bvalue:
2632 if avalue == bvalue:
2636 continue
2633 continue
2637
2634
2638 # Exact matches come first.
2635 # Exact matches come first.
2639 if avalue == prefvalue:
2636 if avalue == prefvalue:
2640 return -1
2637 return -1
2641 if bvalue == prefvalue:
2638 if bvalue == prefvalue:
2642 return 1
2639 return 1
2643
2640
2644 # Fall back to next attribute.
2641 # Fall back to next attribute.
2645 continue
2642 continue
2646
2643
2647 # If we got here we couldn't sort by attributes and prefers. Fall
2644 # If we got here we couldn't sort by attributes and prefers. Fall
2648 # back to index order.
2645 # back to index order.
2649 return 0
2646 return 0
2650
2647
2651 def __lt__(self, other):
2648 def __lt__(self, other):
2652 return self._cmp(other) < 0
2649 return self._cmp(other) < 0
2653
2650
2654 def __gt__(self, other):
2651 def __gt__(self, other):
2655 return self._cmp(other) > 0
2652 return self._cmp(other) > 0
2656
2653
2657 def __eq__(self, other):
2654 def __eq__(self, other):
2658 return self._cmp(other) == 0
2655 return self._cmp(other) == 0
2659
2656
2660 def __le__(self, other):
2657 def __le__(self, other):
2661 return self._cmp(other) <= 0
2658 return self._cmp(other) <= 0
2662
2659
2663 def __ge__(self, other):
2660 def __ge__(self, other):
2664 return self._cmp(other) >= 0
2661 return self._cmp(other) >= 0
2665
2662
2666 def __ne__(self, other):
2663 def __ne__(self, other):
2667 return self._cmp(other) != 0
2664 return self._cmp(other) != 0
2668
2665
2669 def sortclonebundleentries(ui, entries):
2666 def sortclonebundleentries(ui, entries):
2670 prefers = ui.configlist('ui', 'clonebundleprefers')
2667 prefers = ui.configlist('ui', 'clonebundleprefers')
2671 if not prefers:
2668 if not prefers:
2672 return list(entries)
2669 return list(entries)
2673
2670
2674 prefers = [p.split('=', 1) for p in prefers]
2671 prefers = [p.split('=', 1) for p in prefers]
2675
2672
2676 items = sorted(clonebundleentry(v, prefers) for v in entries)
2673 items = sorted(clonebundleentry(v, prefers) for v in entries)
2677 return [i.value for i in items]
2674 return [i.value for i in items]
2678
2675
2679 def trypullbundlefromurl(ui, repo, url):
2676 def trypullbundlefromurl(ui, repo, url):
2680 """Attempt to apply a bundle from a URL."""
2677 """Attempt to apply a bundle from a URL."""
2681 with repo.lock(), repo.transaction('bundleurl') as tr:
2678 with repo.lock(), repo.transaction('bundleurl') as tr:
2682 try:
2679 try:
2683 fh = urlmod.open(ui, url)
2680 fh = urlmod.open(ui, url)
2684 cg = readbundle(ui, fh, 'stream')
2681 cg = readbundle(ui, fh, 'stream')
2685
2682
2686 if isinstance(cg, streamclone.streamcloneapplier):
2683 if isinstance(cg, streamclone.streamcloneapplier):
2687 cg.apply(repo)
2684 cg.apply(repo)
2688 else:
2685 else:
2689 bundle2.applybundle(repo, cg, tr, 'clonebundles', url)
2686 bundle2.applybundle(repo, cg, tr, 'clonebundles', url)
2690 return True
2687 return True
2691 except urlerr.httperror as e:
2688 except urlerr.httperror as e:
2692 ui.warn(_('HTTP error fetching bundle: %s\n') %
2689 ui.warn(_('HTTP error fetching bundle: %s\n') %
2693 stringutil.forcebytestr(e))
2690 stringutil.forcebytestr(e))
2694 except urlerr.urlerror as e:
2691 except urlerr.urlerror as e:
2695 ui.warn(_('error fetching bundle: %s\n') %
2692 ui.warn(_('error fetching bundle: %s\n') %
2696 stringutil.forcebytestr(e.reason))
2693 stringutil.forcebytestr(e.reason))
2697
2694
2698 return False
2695 return False
@@ -1,831 +1,831 b''
1 from __future__ import absolute_import
1 from __future__ import absolute_import
2
2
3 import os
3 import os
4 import re
4 import re
5 import socket
5 import socket
6 import stat
6 import stat
7 import subprocess
7 import subprocess
8 import sys
8 import sys
9 import tempfile
9 import tempfile
10
10
11 tempprefix = 'hg-hghave-'
11 tempprefix = 'hg-hghave-'
12
12
13 checks = {
13 checks = {
14 "true": (lambda: True, "yak shaving"),
14 "true": (lambda: True, "yak shaving"),
15 "false": (lambda: False, "nail clipper"),
15 "false": (lambda: False, "nail clipper"),
16 }
16 }
17
17
18 try:
18 try:
19 import msvcrt
19 import msvcrt
20 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
20 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
21 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
21 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
22 except ImportError:
22 except ImportError:
23 pass
23 pass
24
24
25 stdout = getattr(sys.stdout, 'buffer', sys.stdout)
25 stdout = getattr(sys.stdout, 'buffer', sys.stdout)
26 stderr = getattr(sys.stderr, 'buffer', sys.stderr)
26 stderr = getattr(sys.stderr, 'buffer', sys.stderr)
27
27
28 if sys.version_info[0] >= 3:
28 if sys.version_info[0] >= 3:
29 def _bytespath(p):
29 def _bytespath(p):
30 if p is None:
30 if p is None:
31 return p
31 return p
32 return p.encode('utf-8')
32 return p.encode('utf-8')
33
33
34 def _strpath(p):
34 def _strpath(p):
35 if p is None:
35 if p is None:
36 return p
36 return p
37 return p.decode('utf-8')
37 return p.decode('utf-8')
38 else:
38 else:
39 def _bytespath(p):
39 def _bytespath(p):
40 return p
40 return p
41
41
42 _strpath = _bytespath
42 _strpath = _bytespath
43
43
44 def check(name, desc):
44 def check(name, desc):
45 """Registers a check function for a feature."""
45 """Registers a check function for a feature."""
46 def decorator(func):
46 def decorator(func):
47 checks[name] = (func, desc)
47 checks[name] = (func, desc)
48 return func
48 return func
49 return decorator
49 return decorator
50
50
51 def checkvers(name, desc, vers):
51 def checkvers(name, desc, vers):
52 """Registers a check function for each of a series of versions.
52 """Registers a check function for each of a series of versions.
53
53
54 vers can be a list or an iterator"""
54 vers can be a list or an iterator"""
55 def decorator(func):
55 def decorator(func):
56 def funcv(v):
56 def funcv(v):
57 def f():
57 def f():
58 return func(v)
58 return func(v)
59 return f
59 return f
60 for v in vers:
60 for v in vers:
61 v = str(v)
61 v = str(v)
62 f = funcv(v)
62 f = funcv(v)
63 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v)
63 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v)
64 return func
64 return func
65 return decorator
65 return decorator
66
66
67 def checkfeatures(features):
67 def checkfeatures(features):
68 result = {
68 result = {
69 'error': [],
69 'error': [],
70 'missing': [],
70 'missing': [],
71 'skipped': [],
71 'skipped': [],
72 }
72 }
73
73
74 for feature in features:
74 for feature in features:
75 negate = feature.startswith('no-')
75 negate = feature.startswith('no-')
76 if negate:
76 if negate:
77 feature = feature[3:]
77 feature = feature[3:]
78
78
79 if feature not in checks:
79 if feature not in checks:
80 result['missing'].append(feature)
80 result['missing'].append(feature)
81 continue
81 continue
82
82
83 check, desc = checks[feature]
83 check, desc = checks[feature]
84 try:
84 try:
85 available = check()
85 available = check()
86 except Exception:
86 except Exception:
87 result['error'].append('hghave check failed: %s' % feature)
87 result['error'].append('hghave check failed: %s' % feature)
88 continue
88 continue
89
89
90 if not negate and not available:
90 if not negate and not available:
91 result['skipped'].append('missing feature: %s' % desc)
91 result['skipped'].append('missing feature: %s' % desc)
92 elif negate and available:
92 elif negate and available:
93 result['skipped'].append('system supports %s' % desc)
93 result['skipped'].append('system supports %s' % desc)
94
94
95 return result
95 return result
96
96
97 def require(features):
97 def require(features):
98 """Require that features are available, exiting if not."""
98 """Require that features are available, exiting if not."""
99 result = checkfeatures(features)
99 result = checkfeatures(features)
100
100
101 for missing in result['missing']:
101 for missing in result['missing']:
102 stderr.write(('skipped: unknown feature: %s\n'
102 stderr.write(('skipped: unknown feature: %s\n'
103 % missing).encode('utf-8'))
103 % missing).encode('utf-8'))
104 for msg in result['skipped']:
104 for msg in result['skipped']:
105 stderr.write(('skipped: %s\n' % msg).encode('utf-8'))
105 stderr.write(('skipped: %s\n' % msg).encode('utf-8'))
106 for msg in result['error']:
106 for msg in result['error']:
107 stderr.write(('%s\n' % msg).encode('utf-8'))
107 stderr.write(('%s\n' % msg).encode('utf-8'))
108
108
109 if result['missing']:
109 if result['missing']:
110 sys.exit(2)
110 sys.exit(2)
111
111
112 if result['skipped'] or result['error']:
112 if result['skipped'] or result['error']:
113 sys.exit(1)
113 sys.exit(1)
114
114
115 def matchoutput(cmd, regexp, ignorestatus=False):
115 def matchoutput(cmd, regexp, ignorestatus=False):
116 """Return the match object if cmd executes successfully and its output
116 """Return the match object if cmd executes successfully and its output
117 is matched by the supplied regular expression.
117 is matched by the supplied regular expression.
118 """
118 """
119 r = re.compile(regexp)
119 r = re.compile(regexp)
120 p = subprocess.Popen(
120 p = subprocess.Popen(
121 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
121 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
122 s = p.communicate()[0]
122 s = p.communicate()[0]
123 ret = p.returncode
123 ret = p.returncode
124 return (ignorestatus or not ret) and r.search(s)
124 return (ignorestatus or not ret) and r.search(s)
125
125
126 @check("baz", "GNU Arch baz client")
126 @check("baz", "GNU Arch baz client")
127 def has_baz():
127 def has_baz():
128 return matchoutput('baz --version 2>&1', br'baz Bazaar version')
128 return matchoutput('baz --version 2>&1', br'baz Bazaar version')
129
129
130 @check("bzr", "Canonical's Bazaar client")
130 @check("bzr", "Canonical's Bazaar client")
131 def has_bzr():
131 def has_bzr():
132 try:
132 try:
133 import bzrlib
133 import bzrlib
134 import bzrlib.bzrdir
134 import bzrlib.bzrdir
135 import bzrlib.errors
135 import bzrlib.errors
136 import bzrlib.revision
136 import bzrlib.revision
137 import bzrlib.revisionspec
137 import bzrlib.revisionspec
138 bzrlib.revisionspec.RevisionSpec
138 bzrlib.revisionspec.RevisionSpec
139 return bzrlib.__doc__ is not None
139 return bzrlib.__doc__ is not None
140 except (AttributeError, ImportError):
140 except (AttributeError, ImportError):
141 return False
141 return False
142
142
143 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,))
143 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,))
144 def has_bzr_range(v):
144 def has_bzr_range(v):
145 major, minor = v.split('.')[0:2]
145 major, minor = v.split('rc')[0].split('.')[0:2]
146 try:
146 try:
147 import bzrlib
147 import bzrlib
148 return (bzrlib.__doc__ is not None
148 return (bzrlib.__doc__ is not None
149 and bzrlib.version_info[:2] >= (int(major), int(minor)))
149 and bzrlib.version_info[:2] >= (int(major), int(minor)))
150 except ImportError:
150 except ImportError:
151 return False
151 return False
152
152
153 @check("chg", "running with chg")
153 @check("chg", "running with chg")
154 def has_chg():
154 def has_chg():
155 return 'CHGHG' in os.environ
155 return 'CHGHG' in os.environ
156
156
157 @check("cvs", "cvs client/server")
157 @check("cvs", "cvs client/server")
158 def has_cvs():
158 def has_cvs():
159 re = br'Concurrent Versions System.*?server'
159 re = br'Concurrent Versions System.*?server'
160 return matchoutput('cvs --version 2>&1', re) and not has_msys()
160 return matchoutput('cvs --version 2>&1', re) and not has_msys()
161
161
162 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
162 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
163 def has_cvs112():
163 def has_cvs112():
164 re = br'Concurrent Versions System \(CVS\) 1.12.*?server'
164 re = br'Concurrent Versions System \(CVS\) 1.12.*?server'
165 return matchoutput('cvs --version 2>&1', re) and not has_msys()
165 return matchoutput('cvs --version 2>&1', re) and not has_msys()
166
166
167 @check("cvsnt", "cvsnt client/server")
167 @check("cvsnt", "cvsnt client/server")
168 def has_cvsnt():
168 def has_cvsnt():
169 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)'
169 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)'
170 return matchoutput('cvsnt --version 2>&1', re)
170 return matchoutput('cvsnt --version 2>&1', re)
171
171
172 @check("darcs", "darcs client")
172 @check("darcs", "darcs client")
173 def has_darcs():
173 def has_darcs():
174 return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True)
174 return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True)
175
175
176 @check("mtn", "monotone client (>= 1.0)")
176 @check("mtn", "monotone client (>= 1.0)")
177 def has_mtn():
177 def has_mtn():
178 return matchoutput('mtn --version', br'monotone', True) and not matchoutput(
178 return matchoutput('mtn --version', br'monotone', True) and not matchoutput(
179 'mtn --version', br'monotone 0\.', True)
179 'mtn --version', br'monotone 0\.', True)
180
180
181 @check("eol-in-paths", "end-of-lines in paths")
181 @check("eol-in-paths", "end-of-lines in paths")
182 def has_eol_in_paths():
182 def has_eol_in_paths():
183 try:
183 try:
184 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
184 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
185 os.close(fd)
185 os.close(fd)
186 os.remove(path)
186 os.remove(path)
187 return True
187 return True
188 except (IOError, OSError):
188 except (IOError, OSError):
189 return False
189 return False
190
190
191 @check("execbit", "executable bit")
191 @check("execbit", "executable bit")
192 def has_executablebit():
192 def has_executablebit():
193 try:
193 try:
194 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
194 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
195 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
195 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
196 try:
196 try:
197 os.close(fh)
197 os.close(fh)
198 m = os.stat(fn).st_mode & 0o777
198 m = os.stat(fn).st_mode & 0o777
199 new_file_has_exec = m & EXECFLAGS
199 new_file_has_exec = m & EXECFLAGS
200 os.chmod(fn, m ^ EXECFLAGS)
200 os.chmod(fn, m ^ EXECFLAGS)
201 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m)
201 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m)
202 finally:
202 finally:
203 os.unlink(fn)
203 os.unlink(fn)
204 except (IOError, OSError):
204 except (IOError, OSError):
205 # we don't care, the user probably won't be able to commit anyway
205 # we don't care, the user probably won't be able to commit anyway
206 return False
206 return False
207 return not (new_file_has_exec or exec_flags_cannot_flip)
207 return not (new_file_has_exec or exec_flags_cannot_flip)
208
208
209 @check("icasefs", "case insensitive file system")
209 @check("icasefs", "case insensitive file system")
210 def has_icasefs():
210 def has_icasefs():
211 # Stolen from mercurial.util
211 # Stolen from mercurial.util
212 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
212 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
213 os.close(fd)
213 os.close(fd)
214 try:
214 try:
215 s1 = os.stat(path)
215 s1 = os.stat(path)
216 d, b = os.path.split(path)
216 d, b = os.path.split(path)
217 p2 = os.path.join(d, b.upper())
217 p2 = os.path.join(d, b.upper())
218 if path == p2:
218 if path == p2:
219 p2 = os.path.join(d, b.lower())
219 p2 = os.path.join(d, b.lower())
220 try:
220 try:
221 s2 = os.stat(p2)
221 s2 = os.stat(p2)
222 return s2 == s1
222 return s2 == s1
223 except OSError:
223 except OSError:
224 return False
224 return False
225 finally:
225 finally:
226 os.remove(path)
226 os.remove(path)
227
227
228 @check("fifo", "named pipes")
228 @check("fifo", "named pipes")
229 def has_fifo():
229 def has_fifo():
230 if getattr(os, "mkfifo", None) is None:
230 if getattr(os, "mkfifo", None) is None:
231 return False
231 return False
232 name = tempfile.mktemp(dir='.', prefix=tempprefix)
232 name = tempfile.mktemp(dir='.', prefix=tempprefix)
233 try:
233 try:
234 os.mkfifo(name)
234 os.mkfifo(name)
235 os.unlink(name)
235 os.unlink(name)
236 return True
236 return True
237 except OSError:
237 except OSError:
238 return False
238 return False
239
239
240 @check("killdaemons", 'killdaemons.py support')
240 @check("killdaemons", 'killdaemons.py support')
241 def has_killdaemons():
241 def has_killdaemons():
242 return True
242 return True
243
243
244 @check("cacheable", "cacheable filesystem")
244 @check("cacheable", "cacheable filesystem")
245 def has_cacheable_fs():
245 def has_cacheable_fs():
246 from mercurial import util
246 from mercurial import util
247
247
248 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
248 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
249 os.close(fd)
249 os.close(fd)
250 try:
250 try:
251 return util.cachestat(path).cacheable()
251 return util.cachestat(path).cacheable()
252 finally:
252 finally:
253 os.remove(path)
253 os.remove(path)
254
254
255 @check("lsprof", "python lsprof module")
255 @check("lsprof", "python lsprof module")
256 def has_lsprof():
256 def has_lsprof():
257 try:
257 try:
258 import _lsprof
258 import _lsprof
259 _lsprof.Profiler # silence unused import warning
259 _lsprof.Profiler # silence unused import warning
260 return True
260 return True
261 except ImportError:
261 except ImportError:
262 return False
262 return False
263
263
264 def gethgversion():
264 def gethgversion():
265 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)')
265 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)')
266 if not m:
266 if not m:
267 return (0, 0)
267 return (0, 0)
268 return (int(m.group(1)), int(m.group(2)))
268 return (int(m.group(1)), int(m.group(2)))
269
269
270 @checkvers("hg", "Mercurial >= %s",
270 @checkvers("hg", "Mercurial >= %s",
271 list([(1.0 * x) / 10 for x in range(9, 99)]))
271 list([(1.0 * x) / 10 for x in range(9, 99)]))
272 def has_hg_range(v):
272 def has_hg_range(v):
273 major, minor = v.split('.')[0:2]
273 major, minor = v.split('.')[0:2]
274 return gethgversion() >= (int(major), int(minor))
274 return gethgversion() >= (int(major), int(minor))
275
275
276 @check("hg08", "Mercurial >= 0.8")
276 @check("hg08", "Mercurial >= 0.8")
277 def has_hg08():
277 def has_hg08():
278 if checks["hg09"][0]():
278 if checks["hg09"][0]():
279 return True
279 return True
280 return matchoutput('hg help annotate 2>&1', '--date')
280 return matchoutput('hg help annotate 2>&1', '--date')
281
281
282 @check("hg07", "Mercurial >= 0.7")
282 @check("hg07", "Mercurial >= 0.7")
283 def has_hg07():
283 def has_hg07():
284 if checks["hg08"][0]():
284 if checks["hg08"][0]():
285 return True
285 return True
286 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM')
286 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM')
287
287
288 @check("hg06", "Mercurial >= 0.6")
288 @check("hg06", "Mercurial >= 0.6")
289 def has_hg06():
289 def has_hg06():
290 if checks["hg07"][0]():
290 if checks["hg07"][0]():
291 return True
291 return True
292 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version')
292 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version')
293
293
294 @check("gettext", "GNU Gettext (msgfmt)")
294 @check("gettext", "GNU Gettext (msgfmt)")
295 def has_gettext():
295 def has_gettext():
296 return matchoutput('msgfmt --version', br'GNU gettext-tools')
296 return matchoutput('msgfmt --version', br'GNU gettext-tools')
297
297
298 @check("git", "git command line client")
298 @check("git", "git command line client")
299 def has_git():
299 def has_git():
300 return matchoutput('git --version 2>&1', br'^git version')
300 return matchoutput('git --version 2>&1', br'^git version')
301
301
302 def getgitversion():
302 def getgitversion():
303 m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)')
303 m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)')
304 if not m:
304 if not m:
305 return (0, 0)
305 return (0, 0)
306 return (int(m.group(1)), int(m.group(2)))
306 return (int(m.group(1)), int(m.group(2)))
307
307
308 # https://github.com/git-lfs/lfs-test-server
308 # https://github.com/git-lfs/lfs-test-server
309 @check("lfs-test-server", "git-lfs test server")
309 @check("lfs-test-server", "git-lfs test server")
310 def has_lfsserver():
310 def has_lfsserver():
311 exe = 'lfs-test-server'
311 exe = 'lfs-test-server'
312 if has_windows():
312 if has_windows():
313 exe = 'lfs-test-server.exe'
313 exe = 'lfs-test-server.exe'
314 return any(
314 return any(
315 os.access(os.path.join(path, exe), os.X_OK)
315 os.access(os.path.join(path, exe), os.X_OK)
316 for path in os.environ["PATH"].split(os.pathsep)
316 for path in os.environ["PATH"].split(os.pathsep)
317 )
317 )
318
318
319 @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,))
319 @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,))
320 def has_git_range(v):
320 def has_git_range(v):
321 major, minor = v.split('.')[0:2]
321 major, minor = v.split('.')[0:2]
322 return getgitversion() >= (int(major), int(minor))
322 return getgitversion() >= (int(major), int(minor))
323
323
324 @check("docutils", "Docutils text processing library")
324 @check("docutils", "Docutils text processing library")
325 def has_docutils():
325 def has_docutils():
326 try:
326 try:
327 import docutils.core
327 import docutils.core
328 docutils.core.publish_cmdline # silence unused import
328 docutils.core.publish_cmdline # silence unused import
329 return True
329 return True
330 except ImportError:
330 except ImportError:
331 return False
331 return False
332
332
333 def getsvnversion():
333 def getsvnversion():
334 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)')
334 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)')
335 if not m:
335 if not m:
336 return (0, 0)
336 return (0, 0)
337 return (int(m.group(1)), int(m.group(2)))
337 return (int(m.group(1)), int(m.group(2)))
338
338
339 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5))
339 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5))
340 def has_svn_range(v):
340 def has_svn_range(v):
341 major, minor = v.split('.')[0:2]
341 major, minor = v.split('.')[0:2]
342 return getsvnversion() >= (int(major), int(minor))
342 return getsvnversion() >= (int(major), int(minor))
343
343
344 @check("svn", "subversion client and admin tools")
344 @check("svn", "subversion client and admin tools")
345 def has_svn():
345 def has_svn():
346 return (matchoutput('svn --version 2>&1', br'^svn, version') and
346 return (matchoutput('svn --version 2>&1', br'^svn, version') and
347 matchoutput('svnadmin --version 2>&1', br'^svnadmin, version'))
347 matchoutput('svnadmin --version 2>&1', br'^svnadmin, version'))
348
348
349 @check("svn-bindings", "subversion python bindings")
349 @check("svn-bindings", "subversion python bindings")
350 def has_svn_bindings():
350 def has_svn_bindings():
351 try:
351 try:
352 import svn.core
352 import svn.core
353 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
353 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
354 if version < (1, 4):
354 if version < (1, 4):
355 return False
355 return False
356 return True
356 return True
357 except ImportError:
357 except ImportError:
358 return False
358 return False
359
359
360 @check("p4", "Perforce server and client")
360 @check("p4", "Perforce server and client")
361 def has_p4():
361 def has_p4():
362 return (matchoutput('p4 -V', br'Rev\. P4/') and
362 return (matchoutput('p4 -V', br'Rev\. P4/') and
363 matchoutput('p4d -V', br'Rev\. P4D/'))
363 matchoutput('p4d -V', br'Rev\. P4D/'))
364
364
365 @check("symlink", "symbolic links")
365 @check("symlink", "symbolic links")
366 def has_symlink():
366 def has_symlink():
367 if getattr(os, "symlink", None) is None:
367 if getattr(os, "symlink", None) is None:
368 return False
368 return False
369 name = tempfile.mktemp(dir='.', prefix=tempprefix)
369 name = tempfile.mktemp(dir='.', prefix=tempprefix)
370 try:
370 try:
371 os.symlink(".", name)
371 os.symlink(".", name)
372 os.unlink(name)
372 os.unlink(name)
373 return True
373 return True
374 except (OSError, AttributeError):
374 except (OSError, AttributeError):
375 return False
375 return False
376
376
377 @check("hardlink", "hardlinks")
377 @check("hardlink", "hardlinks")
378 def has_hardlink():
378 def has_hardlink():
379 from mercurial import util
379 from mercurial import util
380 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
380 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
381 os.close(fh)
381 os.close(fh)
382 name = tempfile.mktemp(dir='.', prefix=tempprefix)
382 name = tempfile.mktemp(dir='.', prefix=tempprefix)
383 try:
383 try:
384 util.oslink(_bytespath(fn), _bytespath(name))
384 util.oslink(_bytespath(fn), _bytespath(name))
385 os.unlink(name)
385 os.unlink(name)
386 return True
386 return True
387 except OSError:
387 except OSError:
388 return False
388 return False
389 finally:
389 finally:
390 os.unlink(fn)
390 os.unlink(fn)
391
391
392 @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems")
392 @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems")
393 def has_hardlink_whitelisted():
393 def has_hardlink_whitelisted():
394 from mercurial import util
394 from mercurial import util
395 try:
395 try:
396 fstype = util.getfstype(b'.')
396 fstype = util.getfstype(b'.')
397 except OSError:
397 except OSError:
398 return False
398 return False
399 return fstype in util._hardlinkfswhitelist
399 return fstype in util._hardlinkfswhitelist
400
400
401 @check("rmcwd", "can remove current working directory")
401 @check("rmcwd", "can remove current working directory")
402 def has_rmcwd():
402 def has_rmcwd():
403 ocwd = os.getcwd()
403 ocwd = os.getcwd()
404 temp = tempfile.mkdtemp(dir='.', prefix=tempprefix)
404 temp = tempfile.mkdtemp(dir='.', prefix=tempprefix)
405 try:
405 try:
406 os.chdir(temp)
406 os.chdir(temp)
407 # On Linux, 'rmdir .' isn't allowed, but the other names are okay.
407 # On Linux, 'rmdir .' isn't allowed, but the other names are okay.
408 # On Solaris and Windows, the cwd can't be removed by any names.
408 # On Solaris and Windows, the cwd can't be removed by any names.
409 os.rmdir(os.getcwd())
409 os.rmdir(os.getcwd())
410 return True
410 return True
411 except OSError:
411 except OSError:
412 return False
412 return False
413 finally:
413 finally:
414 os.chdir(ocwd)
414 os.chdir(ocwd)
415 # clean up temp dir on platforms where cwd can't be removed
415 # clean up temp dir on platforms where cwd can't be removed
416 try:
416 try:
417 os.rmdir(temp)
417 os.rmdir(temp)
418 except OSError:
418 except OSError:
419 pass
419 pass
420
420
421 @check("tla", "GNU Arch tla client")
421 @check("tla", "GNU Arch tla client")
422 def has_tla():
422 def has_tla():
423 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision')
423 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision')
424
424
425 @check("gpg", "gpg client")
425 @check("gpg", "gpg client")
426 def has_gpg():
426 def has_gpg():
427 return matchoutput('gpg --version 2>&1', br'GnuPG')
427 return matchoutput('gpg --version 2>&1', br'GnuPG')
428
428
429 @check("gpg2", "gpg client v2")
429 @check("gpg2", "gpg client v2")
430 def has_gpg2():
430 def has_gpg2():
431 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.')
431 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.')
432
432
433 @check("gpg21", "gpg client v2.1+")
433 @check("gpg21", "gpg client v2.1+")
434 def has_gpg21():
434 def has_gpg21():
435 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)')
435 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)')
436
436
437 @check("unix-permissions", "unix-style permissions")
437 @check("unix-permissions", "unix-style permissions")
438 def has_unix_permissions():
438 def has_unix_permissions():
439 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
439 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
440 try:
440 try:
441 fname = os.path.join(d, 'foo')
441 fname = os.path.join(d, 'foo')
442 for umask in (0o77, 0o07, 0o22):
442 for umask in (0o77, 0o07, 0o22):
443 os.umask(umask)
443 os.umask(umask)
444 f = open(fname, 'w')
444 f = open(fname, 'w')
445 f.close()
445 f.close()
446 mode = os.stat(fname).st_mode
446 mode = os.stat(fname).st_mode
447 os.unlink(fname)
447 os.unlink(fname)
448 if mode & 0o777 != ~umask & 0o666:
448 if mode & 0o777 != ~umask & 0o666:
449 return False
449 return False
450 return True
450 return True
451 finally:
451 finally:
452 os.rmdir(d)
452 os.rmdir(d)
453
453
454 @check("unix-socket", "AF_UNIX socket family")
454 @check("unix-socket", "AF_UNIX socket family")
455 def has_unix_socket():
455 def has_unix_socket():
456 return getattr(socket, 'AF_UNIX', None) is not None
456 return getattr(socket, 'AF_UNIX', None) is not None
457
457
458 @check("root", "root permissions")
458 @check("root", "root permissions")
459 def has_root():
459 def has_root():
460 return getattr(os, 'geteuid', None) and os.geteuid() == 0
460 return getattr(os, 'geteuid', None) and os.geteuid() == 0
461
461
462 @check("pyflakes", "Pyflakes python linter")
462 @check("pyflakes", "Pyflakes python linter")
463 def has_pyflakes():
463 def has_pyflakes():
464 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
464 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
465 br"<stdin>:1: 're' imported but unused",
465 br"<stdin>:1: 're' imported but unused",
466 True)
466 True)
467
467
468 @check("pylint", "Pylint python linter")
468 @check("pylint", "Pylint python linter")
469 def has_pylint():
469 def has_pylint():
470 return matchoutput("pylint --help",
470 return matchoutput("pylint --help",
471 br"Usage: pylint",
471 br"Usage: pylint",
472 True)
472 True)
473
473
474 @check("clang-format", "clang-format C code formatter")
474 @check("clang-format", "clang-format C code formatter")
475 def has_clang_format():
475 def has_clang_format():
476 m = matchoutput('clang-format --version', br'clang-format version (\d)')
476 m = matchoutput('clang-format --version', br'clang-format version (\d)')
477 # style changed somewhere between 4.x and 6.x
477 # style changed somewhere between 4.x and 6.x
478 return m and int(m.group(1)) >= 6
478 return m and int(m.group(1)) >= 6
479
479
480 @check("jshint", "JSHint static code analysis tool")
480 @check("jshint", "JSHint static code analysis tool")
481 def has_jshint():
481 def has_jshint():
482 return matchoutput("jshint --version 2>&1", br"jshint v")
482 return matchoutput("jshint --version 2>&1", br"jshint v")
483
483
484 @check("pygments", "Pygments source highlighting library")
484 @check("pygments", "Pygments source highlighting library")
485 def has_pygments():
485 def has_pygments():
486 try:
486 try:
487 import pygments
487 import pygments
488 pygments.highlight # silence unused import warning
488 pygments.highlight # silence unused import warning
489 return True
489 return True
490 except ImportError:
490 except ImportError:
491 return False
491 return False
492
492
493 @check("outer-repo", "outer repo")
493 @check("outer-repo", "outer repo")
494 def has_outer_repo():
494 def has_outer_repo():
495 # failing for other reasons than 'no repo' imply that there is a repo
495 # failing for other reasons than 'no repo' imply that there is a repo
496 return not matchoutput('hg root 2>&1',
496 return not matchoutput('hg root 2>&1',
497 br'abort: no repository found', True)
497 br'abort: no repository found', True)
498
498
499 @check("ssl", "ssl module available")
499 @check("ssl", "ssl module available")
500 def has_ssl():
500 def has_ssl():
501 try:
501 try:
502 import ssl
502 import ssl
503 ssl.CERT_NONE
503 ssl.CERT_NONE
504 return True
504 return True
505 except ImportError:
505 except ImportError:
506 return False
506 return False
507
507
508 @check("sslcontext", "python >= 2.7.9 ssl")
508 @check("sslcontext", "python >= 2.7.9 ssl")
509 def has_sslcontext():
509 def has_sslcontext():
510 try:
510 try:
511 import ssl
511 import ssl
512 ssl.SSLContext
512 ssl.SSLContext
513 return True
513 return True
514 except (ImportError, AttributeError):
514 except (ImportError, AttributeError):
515 return False
515 return False
516
516
517 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
517 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
518 def has_defaultcacerts():
518 def has_defaultcacerts():
519 from mercurial import sslutil, ui as uimod
519 from mercurial import sslutil, ui as uimod
520 ui = uimod.ui.load()
520 ui = uimod.ui.load()
521 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts
521 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts
522
522
523 @check("defaultcacertsloaded", "detected presence of loaded system CA certs")
523 @check("defaultcacertsloaded", "detected presence of loaded system CA certs")
524 def has_defaultcacertsloaded():
524 def has_defaultcacertsloaded():
525 import ssl
525 import ssl
526 from mercurial import sslutil, ui as uimod
526 from mercurial import sslutil, ui as uimod
527
527
528 if not has_defaultcacerts():
528 if not has_defaultcacerts():
529 return False
529 return False
530 if not has_sslcontext():
530 if not has_sslcontext():
531 return False
531 return False
532
532
533 ui = uimod.ui.load()
533 ui = uimod.ui.load()
534 cafile = sslutil._defaultcacerts(ui)
534 cafile = sslutil._defaultcacerts(ui)
535 ctx = ssl.create_default_context()
535 ctx = ssl.create_default_context()
536 if cafile:
536 if cafile:
537 ctx.load_verify_locations(cafile=cafile)
537 ctx.load_verify_locations(cafile=cafile)
538 else:
538 else:
539 ctx.load_default_certs()
539 ctx.load_default_certs()
540
540
541 return len(ctx.get_ca_certs()) > 0
541 return len(ctx.get_ca_certs()) > 0
542
542
543 @check("tls1.2", "TLS 1.2 protocol support")
543 @check("tls1.2", "TLS 1.2 protocol support")
544 def has_tls1_2():
544 def has_tls1_2():
545 from mercurial import sslutil
545 from mercurial import sslutil
546 return b'tls1.2' in sslutil.supportedprotocols
546 return b'tls1.2' in sslutil.supportedprotocols
547
547
548 @check("windows", "Windows")
548 @check("windows", "Windows")
549 def has_windows():
549 def has_windows():
550 return os.name == 'nt'
550 return os.name == 'nt'
551
551
552 @check("system-sh", "system() uses sh")
552 @check("system-sh", "system() uses sh")
553 def has_system_sh():
553 def has_system_sh():
554 return os.name != 'nt'
554 return os.name != 'nt'
555
555
556 @check("serve", "platform and python can manage 'hg serve -d'")
556 @check("serve", "platform and python can manage 'hg serve -d'")
557 def has_serve():
557 def has_serve():
558 return True
558 return True
559
559
560 @check("test-repo", "running tests from repository")
560 @check("test-repo", "running tests from repository")
561 def has_test_repo():
561 def has_test_repo():
562 t = os.environ["TESTDIR"]
562 t = os.environ["TESTDIR"]
563 return os.path.isdir(os.path.join(t, "..", ".hg"))
563 return os.path.isdir(os.path.join(t, "..", ".hg"))
564
564
565 @check("tic", "terminfo compiler and curses module")
565 @check("tic", "terminfo compiler and curses module")
566 def has_tic():
566 def has_tic():
567 try:
567 try:
568 import curses
568 import curses
569 curses.COLOR_BLUE
569 curses.COLOR_BLUE
570 return matchoutput('test -x "`which tic`"', br'')
570 return matchoutput('test -x "`which tic`"', br'')
571 except ImportError:
571 except ImportError:
572 return False
572 return False
573
573
574 @check("msys", "Windows with MSYS")
574 @check("msys", "Windows with MSYS")
575 def has_msys():
575 def has_msys():
576 return os.getenv('MSYSTEM')
576 return os.getenv('MSYSTEM')
577
577
578 @check("aix", "AIX")
578 @check("aix", "AIX")
579 def has_aix():
579 def has_aix():
580 return sys.platform.startswith("aix")
580 return sys.platform.startswith("aix")
581
581
582 @check("osx", "OS X")
582 @check("osx", "OS X")
583 def has_osx():
583 def has_osx():
584 return sys.platform == 'darwin'
584 return sys.platform == 'darwin'
585
585
586 @check("osxpackaging", "OS X packaging tools")
586 @check("osxpackaging", "OS X packaging tools")
587 def has_osxpackaging():
587 def has_osxpackaging():
588 try:
588 try:
589 return (matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1)
589 return (matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1)
590 and matchoutput(
590 and matchoutput(
591 'productbuild', br'Usage: productbuild ',
591 'productbuild', br'Usage: productbuild ',
592 ignorestatus=1)
592 ignorestatus=1)
593 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1)
593 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1)
594 and matchoutput(
594 and matchoutput(
595 'xar --help', br'Usage: xar', ignorestatus=1))
595 'xar --help', br'Usage: xar', ignorestatus=1))
596 except ImportError:
596 except ImportError:
597 return False
597 return False
598
598
599 @check('linuxormacos', 'Linux or MacOS')
599 @check('linuxormacos', 'Linux or MacOS')
600 def has_linuxormacos():
600 def has_linuxormacos():
601 # This isn't a perfect test for MacOS. But it is sufficient for our needs.
601 # This isn't a perfect test for MacOS. But it is sufficient for our needs.
602 return sys.platform.startswith(('linux', 'darwin'))
602 return sys.platform.startswith(('linux', 'darwin'))
603
603
604 @check("docker", "docker support")
604 @check("docker", "docker support")
605 def has_docker():
605 def has_docker():
606 pat = br'A self-sufficient runtime for'
606 pat = br'A self-sufficient runtime for'
607 if matchoutput('docker --help', pat):
607 if matchoutput('docker --help', pat):
608 if 'linux' not in sys.platform:
608 if 'linux' not in sys.platform:
609 # TODO: in theory we should be able to test docker-based
609 # TODO: in theory we should be able to test docker-based
610 # package creation on non-linux using boot2docker, but in
610 # package creation on non-linux using boot2docker, but in
611 # practice that requires extra coordination to make sure
611 # practice that requires extra coordination to make sure
612 # $TESTTEMP is going to be visible at the same path to the
612 # $TESTTEMP is going to be visible at the same path to the
613 # boot2docker VM. If we figure out how to verify that, we
613 # boot2docker VM. If we figure out how to verify that, we
614 # can use the following instead of just saying False:
614 # can use the following instead of just saying False:
615 # return 'DOCKER_HOST' in os.environ
615 # return 'DOCKER_HOST' in os.environ
616 return False
616 return False
617
617
618 return True
618 return True
619 return False
619 return False
620
620
621 @check("debhelper", "debian packaging tools")
621 @check("debhelper", "debian packaging tools")
622 def has_debhelper():
622 def has_debhelper():
623 # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first
623 # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first
624 # quote), so just accept anything in that spot.
624 # quote), so just accept anything in that spot.
625 dpkg = matchoutput('dpkg --version',
625 dpkg = matchoutput('dpkg --version',
626 br"Debian .dpkg' package management program")
626 br"Debian .dpkg' package management program")
627 dh = matchoutput('dh --help',
627 dh = matchoutput('dh --help',
628 br'dh is a part of debhelper.', ignorestatus=True)
628 br'dh is a part of debhelper.', ignorestatus=True)
629 dh_py2 = matchoutput('dh_python2 --help',
629 dh_py2 = matchoutput('dh_python2 --help',
630 br'other supported Python versions')
630 br'other supported Python versions')
631 # debuild comes from the 'devscripts' package, though you might want
631 # debuild comes from the 'devscripts' package, though you might want
632 # the 'build-debs' package instead, which has a dependency on devscripts.
632 # the 'build-debs' package instead, which has a dependency on devscripts.
633 debuild = matchoutput('debuild --help',
633 debuild = matchoutput('debuild --help',
634 br'to run debian/rules with given parameter')
634 br'to run debian/rules with given parameter')
635 return dpkg and dh and dh_py2 and debuild
635 return dpkg and dh and dh_py2 and debuild
636
636
637 @check("debdeps",
637 @check("debdeps",
638 "debian build dependencies (run dpkg-checkbuilddeps in contrib/)")
638 "debian build dependencies (run dpkg-checkbuilddeps in contrib/)")
639 def has_debdeps():
639 def has_debdeps():
640 # just check exit status (ignoring output)
640 # just check exit status (ignoring output)
641 path = '%s/../contrib/packaging/debian/control' % os.environ['TESTDIR']
641 path = '%s/../contrib/packaging/debian/control' % os.environ['TESTDIR']
642 return matchoutput('dpkg-checkbuilddeps %s' % path, br'')
642 return matchoutput('dpkg-checkbuilddeps %s' % path, br'')
643
643
644 @check("demandimport", "demandimport enabled")
644 @check("demandimport", "demandimport enabled")
645 def has_demandimport():
645 def has_demandimport():
646 # chg disables demandimport intentionally for performance wins.
646 # chg disables demandimport intentionally for performance wins.
647 return ((not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable')
647 return ((not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable')
648
648
649 @checkvers("py", "Python >= %s", (2.7, 3.5, 3.6, 3.7, 3.8, 3.9))
649 @checkvers("py", "Python >= %s", (2.7, 3.5, 3.6, 3.7, 3.8, 3.9))
650 def has_python_range(v):
650 def has_python_range(v):
651 major, minor = v.split('.')[0:2]
651 major, minor = v.split('.')[0:2]
652 py_major, py_minor = sys.version_info.major, sys.version_info.minor
652 py_major, py_minor = sys.version_info.major, sys.version_info.minor
653
653
654 return (py_major, py_minor) >= (int(major), int(minor))
654 return (py_major, py_minor) >= (int(major), int(minor))
655
655
656 @check("py3", "running with Python 3.x")
656 @check("py3", "running with Python 3.x")
657 def has_py3():
657 def has_py3():
658 return 3 == sys.version_info[0]
658 return 3 == sys.version_info[0]
659
659
660 @check("py3exe", "a Python 3.x interpreter is available")
660 @check("py3exe", "a Python 3.x interpreter is available")
661 def has_python3exe():
661 def has_python3exe():
662 return matchoutput('python3 -V', br'^Python 3.(5|6|7|8|9)')
662 return matchoutput('python3 -V', br'^Python 3.(5|6|7|8|9)')
663
663
664 @check("pure", "running with pure Python code")
664 @check("pure", "running with pure Python code")
665 def has_pure():
665 def has_pure():
666 return any([
666 return any([
667 os.environ.get("HGMODULEPOLICY") == "py",
667 os.environ.get("HGMODULEPOLICY") == "py",
668 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
668 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
669 ])
669 ])
670
670
671 @check("slow", "allow slow tests (use --allow-slow-tests)")
671 @check("slow", "allow slow tests (use --allow-slow-tests)")
672 def has_slow():
672 def has_slow():
673 return os.environ.get('HGTEST_SLOW') == 'slow'
673 return os.environ.get('HGTEST_SLOW') == 'slow'
674
674
675 @check("hypothesis", "Hypothesis automated test generation")
675 @check("hypothesis", "Hypothesis automated test generation")
676 def has_hypothesis():
676 def has_hypothesis():
677 try:
677 try:
678 import hypothesis
678 import hypothesis
679 hypothesis.given
679 hypothesis.given
680 return True
680 return True
681 except ImportError:
681 except ImportError:
682 return False
682 return False
683
683
684 @check("unziplinks", "unzip(1) understands and extracts symlinks")
684 @check("unziplinks", "unzip(1) understands and extracts symlinks")
685 def unzip_understands_symlinks():
685 def unzip_understands_symlinks():
686 return matchoutput('unzip --help', br'Info-ZIP')
686 return matchoutput('unzip --help', br'Info-ZIP')
687
687
688 @check("zstd", "zstd Python module available")
688 @check("zstd", "zstd Python module available")
689 def has_zstd():
689 def has_zstd():
690 try:
690 try:
691 import mercurial.zstd
691 import mercurial.zstd
692 mercurial.zstd.__version__
692 mercurial.zstd.__version__
693 return True
693 return True
694 except ImportError:
694 except ImportError:
695 return False
695 return False
696
696
697 @check("devfull", "/dev/full special file")
697 @check("devfull", "/dev/full special file")
698 def has_dev_full():
698 def has_dev_full():
699 return os.path.exists('/dev/full')
699 return os.path.exists('/dev/full')
700
700
701 @check("virtualenv", "Python virtualenv support")
701 @check("virtualenv", "Python virtualenv support")
702 def has_virtualenv():
702 def has_virtualenv():
703 try:
703 try:
704 import virtualenv
704 import virtualenv
705 virtualenv.ACTIVATE_SH
705 virtualenv.ACTIVATE_SH
706 return True
706 return True
707 except ImportError:
707 except ImportError:
708 return False
708 return False
709
709
710 @check("fsmonitor", "running tests with fsmonitor")
710 @check("fsmonitor", "running tests with fsmonitor")
711 def has_fsmonitor():
711 def has_fsmonitor():
712 return 'HGFSMONITOR_TESTS' in os.environ
712 return 'HGFSMONITOR_TESTS' in os.environ
713
713
714 @check("fuzzywuzzy", "Fuzzy string matching library")
714 @check("fuzzywuzzy", "Fuzzy string matching library")
715 def has_fuzzywuzzy():
715 def has_fuzzywuzzy():
716 try:
716 try:
717 import fuzzywuzzy
717 import fuzzywuzzy
718 fuzzywuzzy.__version__
718 fuzzywuzzy.__version__
719 return True
719 return True
720 except ImportError:
720 except ImportError:
721 return False
721 return False
722
722
723 @check("clang-libfuzzer", "clang new enough to include libfuzzer")
723 @check("clang-libfuzzer", "clang new enough to include libfuzzer")
724 def has_clang_libfuzzer():
724 def has_clang_libfuzzer():
725 mat = matchoutput('clang --version', br'clang version (\d)')
725 mat = matchoutput('clang --version', br'clang version (\d)')
726 if mat:
726 if mat:
727 # libfuzzer is new in clang 6
727 # libfuzzer is new in clang 6
728 return int(mat.group(1)) > 5
728 return int(mat.group(1)) > 5
729 return False
729 return False
730
730
731 @check("clang-6.0", "clang 6.0 with version suffix (libfuzzer included)")
731 @check("clang-6.0", "clang 6.0 with version suffix (libfuzzer included)")
732 def has_clang60():
732 def has_clang60():
733 return matchoutput('clang-6.0 --version', br'clang version 6\.')
733 return matchoutput('clang-6.0 --version', br'clang version 6\.')
734
734
735 @check("xdiff", "xdiff algorithm")
735 @check("xdiff", "xdiff algorithm")
736 def has_xdiff():
736 def has_xdiff():
737 try:
737 try:
738 from mercurial import policy
738 from mercurial import policy
739 bdiff = policy.importmod('bdiff')
739 bdiff = policy.importmod('bdiff')
740 return bdiff.xdiffblocks(b'', b'') == [(0, 0, 0, 0)]
740 return bdiff.xdiffblocks(b'', b'') == [(0, 0, 0, 0)]
741 except (ImportError, AttributeError):
741 except (ImportError, AttributeError):
742 return False
742 return False
743
743
744 @check('extraextensions', 'whether tests are running with extra extensions')
744 @check('extraextensions', 'whether tests are running with extra extensions')
745 def has_extraextensions():
745 def has_extraextensions():
746 return 'HGTESTEXTRAEXTENSIONS' in os.environ
746 return 'HGTESTEXTRAEXTENSIONS' in os.environ
747
747
748 def getrepofeatures():
748 def getrepofeatures():
749 """Obtain set of repository features in use.
749 """Obtain set of repository features in use.
750
750
751 HGREPOFEATURES can be used to define or remove features. It contains
751 HGREPOFEATURES can be used to define or remove features. It contains
752 a space-delimited list of feature strings. Strings beginning with ``-``
752 a space-delimited list of feature strings. Strings beginning with ``-``
753 mean to remove.
753 mean to remove.
754 """
754 """
755 # Default list provided by core.
755 # Default list provided by core.
756 features = {
756 features = {
757 'bundlerepo',
757 'bundlerepo',
758 'revlogstore',
758 'revlogstore',
759 'fncache',
759 'fncache',
760 }
760 }
761
761
762 # Features that imply other features.
762 # Features that imply other features.
763 implies = {
763 implies = {
764 'simplestore': ['-revlogstore', '-bundlerepo', '-fncache'],
764 'simplestore': ['-revlogstore', '-bundlerepo', '-fncache'],
765 }
765 }
766
766
767 for override in os.environ.get('HGREPOFEATURES', '').split(' '):
767 for override in os.environ.get('HGREPOFEATURES', '').split(' '):
768 if not override:
768 if not override:
769 continue
769 continue
770
770
771 if override.startswith('-'):
771 if override.startswith('-'):
772 if override[1:] in features:
772 if override[1:] in features:
773 features.remove(override[1:])
773 features.remove(override[1:])
774 else:
774 else:
775 features.add(override)
775 features.add(override)
776
776
777 for imply in implies.get(override, []):
777 for imply in implies.get(override, []):
778 if imply.startswith('-'):
778 if imply.startswith('-'):
779 if imply[1:] in features:
779 if imply[1:] in features:
780 features.remove(imply[1:])
780 features.remove(imply[1:])
781 else:
781 else:
782 features.add(imply)
782 features.add(imply)
783
783
784 return features
784 return features
785
785
786 @check('reporevlogstore', 'repository using the default revlog store')
786 @check('reporevlogstore', 'repository using the default revlog store')
787 def has_reporevlogstore():
787 def has_reporevlogstore():
788 return 'revlogstore' in getrepofeatures()
788 return 'revlogstore' in getrepofeatures()
789
789
790 @check('reposimplestore', 'repository using simple storage extension')
790 @check('reposimplestore', 'repository using simple storage extension')
791 def has_reposimplestore():
791 def has_reposimplestore():
792 return 'simplestore' in getrepofeatures()
792 return 'simplestore' in getrepofeatures()
793
793
794 @check('repobundlerepo', 'whether we can open bundle files as repos')
794 @check('repobundlerepo', 'whether we can open bundle files as repos')
795 def has_repobundlerepo():
795 def has_repobundlerepo():
796 return 'bundlerepo' in getrepofeatures()
796 return 'bundlerepo' in getrepofeatures()
797
797
798 @check('repofncache', 'repository has an fncache')
798 @check('repofncache', 'repository has an fncache')
799 def has_repofncache():
799 def has_repofncache():
800 return 'fncache' in getrepofeatures()
800 return 'fncache' in getrepofeatures()
801
801
802 @check('sqlite', 'sqlite3 module is available')
802 @check('sqlite', 'sqlite3 module is available')
803 def has_sqlite():
803 def has_sqlite():
804 try:
804 try:
805 import sqlite3
805 import sqlite3
806 version = sqlite3.sqlite_version_info
806 version = sqlite3.sqlite_version_info
807 except ImportError:
807 except ImportError:
808 return False
808 return False
809
809
810 if version < (3, 8, 3):
810 if version < (3, 8, 3):
811 # WITH clause not supported
811 # WITH clause not supported
812 return False
812 return False
813
813
814 return matchoutput('sqlite3 -version', br'^3\.\d+')
814 return matchoutput('sqlite3 -version', br'^3\.\d+')
815
815
816 @check('vcr', 'vcr http mocking library')
816 @check('vcr', 'vcr http mocking library')
817 def has_vcr():
817 def has_vcr():
818 try:
818 try:
819 import vcr
819 import vcr
820 vcr.VCR
820 vcr.VCR
821 return True
821 return True
822 except (ImportError, AttributeError):
822 except (ImportError, AttributeError):
823 pass
823 pass
824 return False
824 return False
825
825
826 @check('emacs', 'GNU Emacs')
826 @check('emacs', 'GNU Emacs')
827 def has_emacs():
827 def has_emacs():
828 # Our emacs lisp uses `with-eval-after-load` which is new in emacs
828 # Our emacs lisp uses `with-eval-after-load` which is new in emacs
829 # 24.4, so we allow emacs 24.4, 24.5, and 25+ (24.5 was the last
829 # 24.4, so we allow emacs 24.4, 24.5, and 25+ (24.5 was the last
830 # 24 release)
830 # 24 release)
831 return matchoutput('emacs --version', b'GNU Emacs 2(4.4|4.5|5|6|7|8|9)')
831 return matchoutput('emacs --version', b'GNU Emacs 2(4.4|4.5|5|6|7|8|9)')
@@ -1,42 +1,42 b''
1 Make a narrow clone then archive it
1 Make a narrow clone then archive it
2 $ . "$TESTDIR/narrow-library.sh"
2 $ . "$TESTDIR/narrow-library.sh"
3
3
4 $ hg init master
4 $ hg init master
5 $ cd master
5 $ cd master
6
6
7 $ for x in `$TESTDIR/seq.py 3`; do
7 $ for x in `$TESTDIR/seq.py 3`; do
8 > echo $x > "f$x"
8 > echo $x > "f$x"
9 > hg add "f$x"
9 > hg add "f$x"
10 > hg commit -m "Add $x"
10 > hg commit -m "Add $x"
11 > done
11 > done
12 $ cat >> .hg/hgrc << EOF
12 $ cat >> .hg/hgrc << EOF
13 > [narrowhgacl]
13 > [narrowacl]
14 > default.includes=f1 f2
14 > default.includes=f1 f2
15 > EOF
15 > EOF
16 $ hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid
16 $ hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid
17 $ cat hg.pid >> "$DAEMON_PIDS"
17 $ cat hg.pid >> "$DAEMON_PIDS"
18
18
19 $ cd ..
19 $ cd ..
20 $ hg clone http://localhost:$HGPORT1 narrowclone1
20 $ hg clone http://localhost:$HGPORT1 narrowclone1
21 requesting all changes
21 requesting all changes
22 adding changesets
22 adding changesets
23 adding manifests
23 adding manifests
24 adding file changes
24 adding file changes
25 added 3 changesets with 2 changes to 2 files
25 added 3 changesets with 2 changes to 2 files
26 new changesets * (glob)
26 new changesets * (glob)
27 updating to branch default
27 updating to branch default
28 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
29
29
30 The clone directory should only contain f1 and f2
30 The clone directory should only contain f1 and f2
31 $ ls -1 narrowclone1 | sort
31 $ ls -1 narrowclone1 | sort
32 f1
32 f1
33 f2
33 f2
34
34
35 Requirements should contain narrowhg
35 Requirements should contain narrowhg
36 $ cat narrowclone1/.hg/requires | grep narrowhg
36 $ cat narrowclone1/.hg/requires | grep narrowhg
37 narrowhg-experimental
37 narrowhg-experimental
38
38
39 NarrowHG should track f1 and f2
39 NarrowHG should track f1 and f2
40 $ hg -R narrowclone1 tracked
40 $ hg -R narrowclone1 tracked
41 I path:f1
41 I path:f1
42 I path:f2
42 I path:f2
@@ -1,762 +1,805 b''
1 #require symlink execbit
1 #require symlink execbit
2 $ cat << EOF >> $HGRCPATH
2 $ cat << EOF >> $HGRCPATH
3 > [phases]
3 > [phases]
4 > publish=False
4 > publish=False
5 > [extensions]
5 > [extensions]
6 > amend=
6 > amend=
7 > rebase=
7 > rebase=
8 > debugdrawdag=$TESTDIR/drawdag.py
8 > debugdrawdag=$TESTDIR/drawdag.py
9 > strip=
9 > strip=
10 > [rebase]
10 > [rebase]
11 > experimental.inmemory=1
11 > experimental.inmemory=1
12 > [diff]
12 > [diff]
13 > git=1
13 > git=1
14 > [alias]
14 > [alias]
15 > tglog = log -G --template "{rev}: {node|short} '{desc}'\n"
15 > tglog = log -G --template "{rev}: {node|short} '{desc}'\n"
16 > EOF
16 > EOF
17
17
18 Rebase a simple DAG:
18 Rebase a simple DAG:
19 $ hg init repo1
19 $ hg init repo1
20 $ cd repo1
20 $ cd repo1
21 $ hg debugdrawdag <<'EOS'
21 $ hg debugdrawdag <<'EOS'
22 > c b
22 > c b
23 > |/
23 > |/
24 > d
24 > d
25 > |
25 > |
26 > a
26 > a
27 > EOS
27 > EOS
28 $ hg up -C a
28 $ hg up -C a
29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 $ hg tglog
30 $ hg tglog
31 o 3: 814f6bd05178 'c'
31 o 3: 814f6bd05178 'c'
32 |
32 |
33 | o 2: db0e82a16a62 'b'
33 | o 2: db0e82a16a62 'b'
34 |/
34 |/
35 o 1: 02952614a83d 'd'
35 o 1: 02952614a83d 'd'
36 |
36 |
37 @ 0: b173517d0057 'a'
37 @ 0: b173517d0057 'a'
38
38
39 $ hg cat -r 3 c
39 $ hg cat -r 3 c
40 c (no-eol)
40 c (no-eol)
41 $ hg cat -r 2 b
41 $ hg cat -r 2 b
42 b (no-eol)
42 b (no-eol)
43 $ hg rebase --debug -r b -d c | grep rebasing
43 $ hg rebase --debug -r b -d c | grep rebasing
44 rebasing in-memory
44 rebasing in-memory
45 rebasing 2:db0e82a16a62 "b" (b)
45 rebasing 2:db0e82a16a62 "b" (b)
46 $ hg tglog
46 $ hg tglog
47 o 3: ca58782ad1e4 'b'
47 o 3: ca58782ad1e4 'b'
48 |
48 |
49 o 2: 814f6bd05178 'c'
49 o 2: 814f6bd05178 'c'
50 |
50 |
51 o 1: 02952614a83d 'd'
51 o 1: 02952614a83d 'd'
52 |
52 |
53 @ 0: b173517d0057 'a'
53 @ 0: b173517d0057 'a'
54
54
55 $ hg cat -r 3 b
55 $ hg cat -r 3 b
56 b (no-eol)
56 b (no-eol)
57 $ hg cat -r 2 c
57 $ hg cat -r 2 c
58 c (no-eol)
58 c (no-eol)
59 $ cd ..
59 $ cd ..
60
60
61 Case 2:
61 Case 2:
62 $ hg init repo2
62 $ hg init repo2
63 $ cd repo2
63 $ cd repo2
64 $ hg debugdrawdag <<'EOS'
64 $ hg debugdrawdag <<'EOS'
65 > c b
65 > c b
66 > |/
66 > |/
67 > d
67 > d
68 > |
68 > |
69 > a
69 > a
70 > EOS
70 > EOS
71
71
72 Add a symlink and executable file:
72 Add a symlink and executable file:
73 $ hg up -C c
73 $ hg up -C c
74 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
74 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
75 $ ln -s somefile e
75 $ ln -s somefile e
76 $ echo f > f
76 $ echo f > f
77 $ chmod +x f
77 $ chmod +x f
78 $ hg add e f
78 $ hg add e f
79 $ hg amend -q
79 $ hg amend -q
80 $ hg up -Cq a
80 $ hg up -Cq a
81
81
82 Write files to the working copy, and ensure they're still there after the rebase
82 Write files to the working copy, and ensure they're still there after the rebase
83 $ echo "abc" > a
83 $ echo "abc" > a
84 $ ln -s def b
84 $ ln -s def b
85 $ echo "ghi" > c
85 $ echo "ghi" > c
86 $ echo "jkl" > d
86 $ echo "jkl" > d
87 $ echo "mno" > e
87 $ echo "mno" > e
88 $ hg tglog
88 $ hg tglog
89 o 3: f56b71190a8f 'c'
89 o 3: f56b71190a8f 'c'
90 |
90 |
91 | o 2: db0e82a16a62 'b'
91 | o 2: db0e82a16a62 'b'
92 |/
92 |/
93 o 1: 02952614a83d 'd'
93 o 1: 02952614a83d 'd'
94 |
94 |
95 @ 0: b173517d0057 'a'
95 @ 0: b173517d0057 'a'
96
96
97 $ hg cat -r 3 c
97 $ hg cat -r 3 c
98 c (no-eol)
98 c (no-eol)
99 $ hg cat -r 2 b
99 $ hg cat -r 2 b
100 b (no-eol)
100 b (no-eol)
101 $ hg cat -r 3 e
101 $ hg cat -r 3 e
102 somefile (no-eol)
102 somefile (no-eol)
103 $ hg rebase --debug -s b -d a | grep rebasing
103 $ hg rebase --debug -s b -d a | grep rebasing
104 rebasing in-memory
104 rebasing in-memory
105 rebasing 2:db0e82a16a62 "b" (b)
105 rebasing 2:db0e82a16a62 "b" (b)
106 $ hg tglog
106 $ hg tglog
107 o 3: fc055c3b4d33 'b'
107 o 3: fc055c3b4d33 'b'
108 |
108 |
109 | o 2: f56b71190a8f 'c'
109 | o 2: f56b71190a8f 'c'
110 | |
110 | |
111 | o 1: 02952614a83d 'd'
111 | o 1: 02952614a83d 'd'
112 |/
112 |/
113 @ 0: b173517d0057 'a'
113 @ 0: b173517d0057 'a'
114
114
115 $ hg cat -r 2 c
115 $ hg cat -r 2 c
116 c (no-eol)
116 c (no-eol)
117 $ hg cat -r 3 b
117 $ hg cat -r 3 b
118 b (no-eol)
118 b (no-eol)
119 $ hg rebase --debug -s 1 -d 3 | grep rebasing
119 $ hg rebase --debug -s 1 -d 3 | grep rebasing
120 rebasing in-memory
120 rebasing in-memory
121 rebasing 1:02952614a83d "d" (d)
121 rebasing 1:02952614a83d "d" (d)
122 rebasing 2:f56b71190a8f "c"
122 rebasing 2:f56b71190a8f "c"
123 $ hg tglog
123 $ hg tglog
124 o 3: 753feb6fd12a 'c'
124 o 3: 753feb6fd12a 'c'
125 |
125 |
126 o 2: 09c044d2cb43 'd'
126 o 2: 09c044d2cb43 'd'
127 |
127 |
128 o 1: fc055c3b4d33 'b'
128 o 1: fc055c3b4d33 'b'
129 |
129 |
130 @ 0: b173517d0057 'a'
130 @ 0: b173517d0057 'a'
131
131
132 Ensure working copy files are still there:
132 Ensure working copy files are still there:
133 $ cat a
133 $ cat a
134 abc
134 abc
135 $ readlink.py b
135 $ readlink.py b
136 b -> def
136 b -> def
137 $ cat e
137 $ cat e
138 mno
138 mno
139
139
140 Ensure symlink and executable files were rebased properly:
140 Ensure symlink and executable files were rebased properly:
141 $ hg up -Cq 3
141 $ hg up -Cq 3
142 $ readlink.py e
142 $ readlink.py e
143 e -> somefile
143 e -> somefile
144 $ ls -l f | cut -c -10
144 $ ls -l f | cut -c -10
145 -rwxr-xr-x
145 -rwxr-xr-x
146
146
147 Rebase the working copy parent
147 Rebase the working copy parent
148 $ hg up -C 3
148 $ hg up -C 3
149 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 $ hg rebase -r 3 -d 0 --debug | grep rebasing
150 $ hg rebase -r 3 -d 0 --debug | grep rebasing
151 rebasing in-memory
151 rebasing in-memory
152 rebasing 3:753feb6fd12a "c" (tip)
152 rebasing 3:753feb6fd12a "c" (tip)
153 $ hg tglog
153 $ hg tglog
154 @ 3: 844a7de3e617 'c'
154 @ 3: 844a7de3e617 'c'
155 |
155 |
156 | o 2: 09c044d2cb43 'd'
156 | o 2: 09c044d2cb43 'd'
157 | |
157 | |
158 | o 1: fc055c3b4d33 'b'
158 | o 1: fc055c3b4d33 'b'
159 |/
159 |/
160 o 0: b173517d0057 'a'
160 o 0: b173517d0057 'a'
161
161
162
162
163 Test reporting of path conflicts
163 Test reporting of path conflicts
164
164
165 $ hg rm a
165 $ hg rm a
166 $ mkdir a
166 $ mkdir a
167 $ touch a/a
167 $ touch a/a
168 $ hg ci -Am "a/a"
168 $ hg ci -Am "a/a"
169 adding a/a
169 adding a/a
170 $ hg tglog
170 $ hg tglog
171 @ 4: daf7dfc139cb 'a/a'
171 @ 4: daf7dfc139cb 'a/a'
172 |
172 |
173 o 3: 844a7de3e617 'c'
173 o 3: 844a7de3e617 'c'
174 |
174 |
175 | o 2: 09c044d2cb43 'd'
175 | o 2: 09c044d2cb43 'd'
176 | |
176 | |
177 | o 1: fc055c3b4d33 'b'
177 | o 1: fc055c3b4d33 'b'
178 |/
178 |/
179 o 0: b173517d0057 'a'
179 o 0: b173517d0057 'a'
180
180
181 $ hg rebase -r . -d 2
181 $ hg rebase -r . -d 2
182 rebasing 4:daf7dfc139cb "a/a" (tip)
182 rebasing 4:daf7dfc139cb "a/a" (tip)
183 saved backup bundle to $TESTTMP/repo2/.hg/strip-backup/daf7dfc139cb-fdbfcf4f-rebase.hg
183 saved backup bundle to $TESTTMP/repo2/.hg/strip-backup/daf7dfc139cb-fdbfcf4f-rebase.hg
184
184
185 $ hg tglog
185 $ hg tglog
186 @ 4: c6ad37a4f250 'a/a'
186 @ 4: c6ad37a4f250 'a/a'
187 |
187 |
188 | o 3: 844a7de3e617 'c'
188 | o 3: 844a7de3e617 'c'
189 | |
189 | |
190 o | 2: 09c044d2cb43 'd'
190 o | 2: 09c044d2cb43 'd'
191 | |
191 | |
192 o | 1: fc055c3b4d33 'b'
192 o | 1: fc055c3b4d33 'b'
193 |/
193 |/
194 o 0: b173517d0057 'a'
194 o 0: b173517d0057 'a'
195
195
196 $ echo foo > foo
196 $ echo foo > foo
197 $ hg ci -Aqm "added foo"
197 $ hg ci -Aqm "added foo"
198 $ hg up '.^'
198 $ hg up '.^'
199 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
199 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
200 $ echo bar > bar
200 $ echo bar > bar
201 $ hg ci -Aqm "added bar"
201 $ hg ci -Aqm "added bar"
202 $ hg rm a/a
202 $ hg rm a/a
203 $ echo a > a
203 $ echo a > a
204 $ hg ci -Aqm "added a back!"
204 $ hg ci -Aqm "added a back!"
205 $ hg tglog
205 $ hg tglog
206 @ 7: 855e9797387e 'added a back!'
206 @ 7: 855e9797387e 'added a back!'
207 |
207 |
208 o 6: d14530e5e3e6 'added bar'
208 o 6: d14530e5e3e6 'added bar'
209 |
209 |
210 | o 5: 9b94b9373deb 'added foo'
210 | o 5: 9b94b9373deb 'added foo'
211 |/
211 |/
212 o 4: c6ad37a4f250 'a/a'
212 o 4: c6ad37a4f250 'a/a'
213 |
213 |
214 | o 3: 844a7de3e617 'c'
214 | o 3: 844a7de3e617 'c'
215 | |
215 | |
216 o | 2: 09c044d2cb43 'd'
216 o | 2: 09c044d2cb43 'd'
217 | |
217 | |
218 o | 1: fc055c3b4d33 'b'
218 o | 1: fc055c3b4d33 'b'
219 |/
219 |/
220 o 0: b173517d0057 'a'
220 o 0: b173517d0057 'a'
221
221
222 $ hg rebase -r . -d 5
222 $ hg rebase -r . -d 5
223 rebasing 7:855e9797387e "added a back!" (tip)
223 rebasing 7:855e9797387e "added a back!" (tip)
224 saved backup bundle to $TESTTMP/repo2/.hg/strip-backup/855e9797387e-81ee4c5d-rebase.hg
224 saved backup bundle to $TESTTMP/repo2/.hg/strip-backup/855e9797387e-81ee4c5d-rebase.hg
225
225
226 $ hg tglog
226 $ hg tglog
227 @ 7: bb3f02be2688 'added a back!'
227 @ 7: bb3f02be2688 'added a back!'
228 |
228 |
229 | o 6: d14530e5e3e6 'added bar'
229 | o 6: d14530e5e3e6 'added bar'
230 | |
230 | |
231 o | 5: 9b94b9373deb 'added foo'
231 o | 5: 9b94b9373deb 'added foo'
232 |/
232 |/
233 o 4: c6ad37a4f250 'a/a'
233 o 4: c6ad37a4f250 'a/a'
234 |
234 |
235 | o 3: 844a7de3e617 'c'
235 | o 3: 844a7de3e617 'c'
236 | |
236 | |
237 o | 2: 09c044d2cb43 'd'
237 o | 2: 09c044d2cb43 'd'
238 | |
238 | |
239 o | 1: fc055c3b4d33 'b'
239 o | 1: fc055c3b4d33 'b'
240 |/
240 |/
241 o 0: b173517d0057 'a'
241 o 0: b173517d0057 'a'
242
242
243 $ mkdir -p c/subdir
243 $ mkdir -p c/subdir
244 $ echo c > c/subdir/file.txt
244 $ echo c > c/subdir/file.txt
245 $ hg add c/subdir/file.txt
245 $ hg add c/subdir/file.txt
246 $ hg ci -m 'c/subdir/file.txt'
246 $ hg ci -m 'c/subdir/file.txt'
247 $ hg rebase -r . -d 3 -n
247 $ hg rebase -r . -d 3 -n
248 starting dry-run rebase; repository will not be changed
248 starting dry-run rebase; repository will not be changed
249 rebasing 8:e147e6e3c490 "c/subdir/file.txt" (tip)
249 rebasing 8:e147e6e3c490 "c/subdir/file.txt" (tip)
250 abort: error: 'c/subdir/file.txt' conflicts with file 'c' in 3.
250 abort: error: 'c/subdir/file.txt' conflicts with file 'c' in 3.
251 [255]
251 [255]
252 $ hg rebase -r 3 -d . -n
252 $ hg rebase -r 3 -d . -n
253 starting dry-run rebase; repository will not be changed
253 starting dry-run rebase; repository will not be changed
254 rebasing 3:844a7de3e617 "c"
254 rebasing 3:844a7de3e617 "c"
255 abort: error: file 'c' cannot be written because 'c/' is a directory in e147e6e3c490 (containing 1 entries: c/subdir/file.txt)
255 abort: error: file 'c' cannot be written because 'c/' is a directory in e147e6e3c490 (containing 1 entries: c/subdir/file.txt)
256 [255]
256 [255]
257
257
258 $ cd ..
258 $ cd ..
259
259
260 Test path auditing (issue5818)
260 Test path auditing (issue5818)
261
261
262 $ mkdir lib_
262 $ mkdir lib_
263 $ ln -s lib_ lib
263 $ ln -s lib_ lib
264 $ hg init repo
264 $ hg init repo
265 $ cd repo
265 $ cd repo
266 $ mkdir -p ".$TESTTMP/lib"
266 $ mkdir -p ".$TESTTMP/lib"
267 $ touch ".$TESTTMP/lib/a"
267 $ touch ".$TESTTMP/lib/a"
268 $ hg add ".$TESTTMP/lib/a"
268 $ hg add ".$TESTTMP/lib/a"
269 $ hg ci -m 'a'
269 $ hg ci -m 'a'
270
270
271 $ touch ".$TESTTMP/lib/b"
271 $ touch ".$TESTTMP/lib/b"
272 $ hg add ".$TESTTMP/lib/b"
272 $ hg add ".$TESTTMP/lib/b"
273 $ hg ci -m 'b'
273 $ hg ci -m 'b'
274
274
275 $ hg up -q '.^'
275 $ hg up -q '.^'
276 $ touch ".$TESTTMP/lib/c"
276 $ touch ".$TESTTMP/lib/c"
277 $ hg add ".$TESTTMP/lib/c"
277 $ hg add ".$TESTTMP/lib/c"
278 $ hg ci -m 'c'
278 $ hg ci -m 'c'
279 created new head
279 created new head
280 $ hg rebase -s 1 -d .
280 $ hg rebase -s 1 -d .
281 rebasing 1:* "b" (glob)
281 rebasing 1:* "b" (glob)
282 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-rebase.hg (glob)
282 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-rebase.hg (glob)
283 $ cd ..
283 $ cd ..
284
284
285 Test dry-run rebasing
285 Test dry-run rebasing
286
286
287 $ hg init repo3
287 $ hg init repo3
288 $ cd repo3
288 $ cd repo3
289 $ echo a>a
289 $ echo a>a
290 $ hg ci -Aqma
290 $ hg ci -Aqma
291 $ echo b>b
291 $ echo b>b
292 $ hg ci -Aqmb
292 $ hg ci -Aqmb
293 $ echo c>c
293 $ echo c>c
294 $ hg ci -Aqmc
294 $ hg ci -Aqmc
295 $ echo d>d
295 $ echo d>d
296 $ hg ci -Aqmd
296 $ hg ci -Aqmd
297 $ echo e>e
297 $ echo e>e
298 $ hg ci -Aqme
298 $ hg ci -Aqme
299
299
300 $ hg up 1 -q
300 $ hg up 1 -q
301 $ echo f>f
301 $ echo f>f
302 $ hg ci -Amf
302 $ hg ci -Amf
303 adding f
303 adding f
304 created new head
304 created new head
305 $ echo g>g
305 $ echo g>g
306 $ hg ci -Aqmg
306 $ hg ci -Aqmg
307 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
307 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
308 @ 6:baf10c5166d4 test
308 @ 6:baf10c5166d4 test
309 | g
309 | g
310 |
310 |
311 o 5:6343ca3eff20 test
311 o 5:6343ca3eff20 test
312 | f
312 | f
313 |
313 |
314 | o 4:e860deea161a test
314 | o 4:e860deea161a test
315 | | e
315 | | e
316 | |
316 | |
317 | o 3:055a42cdd887 test
317 | o 3:055a42cdd887 test
318 | | d
318 | | d
319 | |
319 | |
320 | o 2:177f92b77385 test
320 | o 2:177f92b77385 test
321 |/ c
321 |/ c
322 |
322 |
323 o 1:d2ae7f538514 test
323 o 1:d2ae7f538514 test
324 | b
324 | b
325 |
325 |
326 o 0:cb9a9f314b8b test
326 o 0:cb9a9f314b8b test
327 a
327 a
328
328
329 Make sure it throws error while passing --continue or --abort with --dry-run
329 Make sure it throws error while passing --continue or --abort with --dry-run
330 $ hg rebase -s 2 -d 6 -n --continue
330 $ hg rebase -s 2 -d 6 -n --continue
331 abort: cannot specify both --dry-run and --continue
331 abort: cannot specify both --dry-run and --continue
332 [255]
332 [255]
333 $ hg rebase -s 2 -d 6 -n --abort
333 $ hg rebase -s 2 -d 6 -n --abort
334 abort: cannot specify both --dry-run and --abort
334 abort: cannot specify both --dry-run and --abort
335 [255]
335 [255]
336
336
337 Check dryrun gives correct results when there is no conflict in rebasing
337 Check dryrun gives correct results when there is no conflict in rebasing
338 $ hg rebase -s 2 -d 6 -n
338 $ hg rebase -s 2 -d 6 -n
339 starting dry-run rebase; repository will not be changed
339 starting dry-run rebase; repository will not be changed
340 rebasing 2:177f92b77385 "c"
340 rebasing 2:177f92b77385 "c"
341 rebasing 3:055a42cdd887 "d"
341 rebasing 3:055a42cdd887 "d"
342 rebasing 4:e860deea161a "e"
342 rebasing 4:e860deea161a "e"
343 dry-run rebase completed successfully; run without -n/--dry-run to perform this rebase
343 dry-run rebase completed successfully; run without -n/--dry-run to perform this rebase
344
344
345 $ hg diff
345 $ hg diff
346 $ hg status
346 $ hg status
347
347
348 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
348 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
349 @ 6:baf10c5166d4 test
349 @ 6:baf10c5166d4 test
350 | g
350 | g
351 |
351 |
352 o 5:6343ca3eff20 test
352 o 5:6343ca3eff20 test
353 | f
353 | f
354 |
354 |
355 | o 4:e860deea161a test
355 | o 4:e860deea161a test
356 | | e
356 | | e
357 | |
357 | |
358 | o 3:055a42cdd887 test
358 | o 3:055a42cdd887 test
359 | | d
359 | | d
360 | |
360 | |
361 | o 2:177f92b77385 test
361 | o 2:177f92b77385 test
362 |/ c
362 |/ c
363 |
363 |
364 o 1:d2ae7f538514 test
364 o 1:d2ae7f538514 test
365 | b
365 | b
366 |
366 |
367 o 0:cb9a9f314b8b test
367 o 0:cb9a9f314b8b test
368 a
368 a
369
369
370 Check dryrun working with --collapse when there is no conflict
370 Check dryrun working with --collapse when there is no conflict
371 $ hg rebase -s 2 -d 6 -n --collapse
371 $ hg rebase -s 2 -d 6 -n --collapse
372 starting dry-run rebase; repository will not be changed
372 starting dry-run rebase; repository will not be changed
373 rebasing 2:177f92b77385 "c"
373 rebasing 2:177f92b77385 "c"
374 rebasing 3:055a42cdd887 "d"
374 rebasing 3:055a42cdd887 "d"
375 rebasing 4:e860deea161a "e"
375 rebasing 4:e860deea161a "e"
376 dry-run rebase completed successfully; run without -n/--dry-run to perform this rebase
376 dry-run rebase completed successfully; run without -n/--dry-run to perform this rebase
377
377
378 Check dryrun gives correct results when there is conflict in rebasing
378 Check dryrun gives correct results when there is conflict in rebasing
379 Make a conflict:
379 Make a conflict:
380 $ hg up 6 -q
380 $ hg up 6 -q
381 $ echo conflict>e
381 $ echo conflict>e
382 $ hg ci -Aqm "conflict with e"
382 $ hg ci -Aqm "conflict with e"
383 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
383 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
384 @ 7:d2c195b28050 test
384 @ 7:d2c195b28050 test
385 | conflict with e
385 | conflict with e
386 |
386 |
387 o 6:baf10c5166d4 test
387 o 6:baf10c5166d4 test
388 | g
388 | g
389 |
389 |
390 o 5:6343ca3eff20 test
390 o 5:6343ca3eff20 test
391 | f
391 | f
392 |
392 |
393 | o 4:e860deea161a test
393 | o 4:e860deea161a test
394 | | e
394 | | e
395 | |
395 | |
396 | o 3:055a42cdd887 test
396 | o 3:055a42cdd887 test
397 | | d
397 | | d
398 | |
398 | |
399 | o 2:177f92b77385 test
399 | o 2:177f92b77385 test
400 |/ c
400 |/ c
401 |
401 |
402 o 1:d2ae7f538514 test
402 o 1:d2ae7f538514 test
403 | b
403 | b
404 |
404 |
405 o 0:cb9a9f314b8b test
405 o 0:cb9a9f314b8b test
406 a
406 a
407
407
408 $ hg rebase -s 2 -d 7 -n
408 $ hg rebase -s 2 -d 7 -n
409 starting dry-run rebase; repository will not be changed
409 starting dry-run rebase; repository will not be changed
410 rebasing 2:177f92b77385 "c"
410 rebasing 2:177f92b77385 "c"
411 rebasing 3:055a42cdd887 "d"
411 rebasing 3:055a42cdd887 "d"
412 rebasing 4:e860deea161a "e"
412 rebasing 4:e860deea161a "e"
413 merging e
413 merging e
414 transaction abort!
414 transaction abort!
415 rollback completed
415 rollback completed
416 hit a merge conflict
416 hit a merge conflict
417 [1]
417 [1]
418 $ hg diff
418 $ hg diff
419 $ hg status
419 $ hg status
420 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
420 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
421 @ 7:d2c195b28050 test
421 @ 7:d2c195b28050 test
422 | conflict with e
422 | conflict with e
423 |
423 |
424 o 6:baf10c5166d4 test
424 o 6:baf10c5166d4 test
425 | g
425 | g
426 |
426 |
427 o 5:6343ca3eff20 test
427 o 5:6343ca3eff20 test
428 | f
428 | f
429 |
429 |
430 | o 4:e860deea161a test
430 | o 4:e860deea161a test
431 | | e
431 | | e
432 | |
432 | |
433 | o 3:055a42cdd887 test
433 | o 3:055a42cdd887 test
434 | | d
434 | | d
435 | |
435 | |
436 | o 2:177f92b77385 test
436 | o 2:177f92b77385 test
437 |/ c
437 |/ c
438 |
438 |
439 o 1:d2ae7f538514 test
439 o 1:d2ae7f538514 test
440 | b
440 | b
441 |
441 |
442 o 0:cb9a9f314b8b test
442 o 0:cb9a9f314b8b test
443 a
443 a
444
444
445 Check dryrun working with --collapse when there is conflicts
445 Check dryrun working with --collapse when there is conflicts
446 $ hg rebase -s 2 -d 7 -n --collapse
446 $ hg rebase -s 2 -d 7 -n --collapse
447 starting dry-run rebase; repository will not be changed
447 starting dry-run rebase; repository will not be changed
448 rebasing 2:177f92b77385 "c"
448 rebasing 2:177f92b77385 "c"
449 rebasing 3:055a42cdd887 "d"
449 rebasing 3:055a42cdd887 "d"
450 rebasing 4:e860deea161a "e"
450 rebasing 4:e860deea161a "e"
451 merging e
451 merging e
452 hit a merge conflict
452 hit a merge conflict
453 [1]
453 [1]
454
454
455 In-memory rebase that fails due to merge conflicts
455 In-memory rebase that fails due to merge conflicts
456
456
457 $ hg rebase -s 2 -d 7
457 $ hg rebase -s 2 -d 7
458 rebasing 2:177f92b77385 "c"
458 rebasing 2:177f92b77385 "c"
459 rebasing 3:055a42cdd887 "d"
459 rebasing 3:055a42cdd887 "d"
460 rebasing 4:e860deea161a "e"
460 rebasing 4:e860deea161a "e"
461 merging e
461 merging e
462 transaction abort!
462 transaction abort!
463 rollback completed
463 rollback completed
464 hit merge conflicts; re-running rebase without in-memory merge
464 hit merge conflicts; re-running rebase without in-memory merge
465 rebasing 2:177f92b77385 "c"
465 rebasing 2:177f92b77385 "c"
466 rebasing 3:055a42cdd887 "d"
466 rebasing 3:055a42cdd887 "d"
467 rebasing 4:e860deea161a "e"
467 rebasing 4:e860deea161a "e"
468 merging e
468 merging e
469 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
469 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
470 unresolved conflicts (see hg resolve, then hg rebase --continue)
470 unresolved conflicts (see hg resolve, then hg rebase --continue)
471 [1]
471 [1]
472 $ hg rebase --abort
472 $ hg rebase --abort
473 saved backup bundle to $TESTTMP/repo3/.hg/strip-backup/c1e524d4287c-f91f82e1-backup.hg
473 saved backup bundle to $TESTTMP/repo3/.hg/strip-backup/c1e524d4287c-f91f82e1-backup.hg
474 rebase aborted
474 rebase aborted
475
475
476 Retrying without in-memory merge won't lose working copy changes
476 Retrying without in-memory merge won't lose working copy changes
477 $ cd ..
477 $ cd ..
478 $ hg clone repo3 repo3-dirty -q
478 $ hg clone repo3 repo3-dirty -q
479 $ cd repo3-dirty
479 $ cd repo3-dirty
480 $ echo dirty > a
480 $ echo dirty > a
481 $ hg rebase -s 2 -d 7
481 $ hg rebase -s 2 -d 7
482 rebasing 2:177f92b77385 "c"
482 rebasing 2:177f92b77385 "c"
483 rebasing 3:055a42cdd887 "d"
483 rebasing 3:055a42cdd887 "d"
484 rebasing 4:e860deea161a "e"
484 rebasing 4:e860deea161a "e"
485 merging e
485 merging e
486 transaction abort!
486 transaction abort!
487 rollback completed
487 rollback completed
488 hit merge conflicts; re-running rebase without in-memory merge
488 hit merge conflicts; re-running rebase without in-memory merge
489 abort: uncommitted changes
489 abort: uncommitted changes
490 [255]
490 [255]
491 $ cat a
491 $ cat a
492 dirty
492 dirty
493
493
494 Retrying without in-memory merge won't lose merge state
494 Retrying without in-memory merge won't lose merge state
495 $ cd ..
495 $ cd ..
496 $ hg clone repo3 repo3-merge-state -q
496 $ hg clone repo3 repo3-merge-state -q
497 $ cd repo3-merge-state
497 $ cd repo3-merge-state
498 $ hg merge 4
498 $ hg merge 4
499 merging e
499 merging e
500 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
500 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
501 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
501 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
502 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
502 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
503 [1]
503 [1]
504 $ hg resolve -l
504 $ hg resolve -l
505 U e
505 U e
506 $ hg rebase -s 2 -d 7
506 $ hg rebase -s 2 -d 7
507 rebasing 2:177f92b77385 "c"
507 rebasing 2:177f92b77385 "c"
508 abort: outstanding merge conflicts
508 abort: outstanding merge conflicts
509 [255]
509 [255]
510 $ hg resolve -l
510 $ hg resolve -l
511 U e
511 U e
512
512
513 ==========================
513 ==========================
514 Test for --confirm option|
514 Test for --confirm option|
515 ==========================
515 ==========================
516 $ cd ..
516 $ cd ..
517 $ hg clone repo3 repo4 -q
517 $ hg clone repo3 repo4 -q
518 $ cd repo4
518 $ cd repo4
519 $ hg strip 7 -q
519 $ hg strip 7 -q
520 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
520 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
521 @ 6:baf10c5166d4 test
521 @ 6:baf10c5166d4 test
522 | g
522 | g
523 |
523 |
524 o 5:6343ca3eff20 test
524 o 5:6343ca3eff20 test
525 | f
525 | f
526 |
526 |
527 | o 4:e860deea161a test
527 | o 4:e860deea161a test
528 | | e
528 | | e
529 | |
529 | |
530 | o 3:055a42cdd887 test
530 | o 3:055a42cdd887 test
531 | | d
531 | | d
532 | |
532 | |
533 | o 2:177f92b77385 test
533 | o 2:177f92b77385 test
534 |/ c
534 |/ c
535 |
535 |
536 o 1:d2ae7f538514 test
536 o 1:d2ae7f538514 test
537 | b
537 | b
538 |
538 |
539 o 0:cb9a9f314b8b test
539 o 0:cb9a9f314b8b test
540 a
540 a
541
541
542 Check it gives error when both --dryrun and --confirm is used:
542 Check it gives error when both --dryrun and --confirm is used:
543 $ hg rebase -s 2 -d . --confirm --dry-run
543 $ hg rebase -s 2 -d . --confirm --dry-run
544 abort: cannot specify both --confirm and --dry-run
544 abort: cannot specify both --confirm and --dry-run
545 [255]
545 [255]
546 $ hg rebase -s 2 -d . --confirm --abort
546 $ hg rebase -s 2 -d . --confirm --abort
547 abort: cannot specify both --confirm and --abort
547 abort: cannot specify both --confirm and --abort
548 [255]
548 [255]
549 $ hg rebase -s 2 -d . --confirm --continue
549 $ hg rebase -s 2 -d . --confirm --continue
550 abort: cannot specify both --confirm and --continue
550 abort: cannot specify both --confirm and --continue
551 [255]
551 [255]
552
552
553 Test --confirm option when there are no conflicts:
553 Test --confirm option when there are no conflicts:
554 $ hg rebase -s 2 -d . --keep --config ui.interactive=True --confirm << EOF
554 $ hg rebase -s 2 -d . --keep --config ui.interactive=True --confirm << EOF
555 > n
555 > n
556 > EOF
556 > EOF
557 starting in-memory rebase
557 starting in-memory rebase
558 rebasing 2:177f92b77385 "c"
558 rebasing 2:177f92b77385 "c"
559 rebasing 3:055a42cdd887 "d"
559 rebasing 3:055a42cdd887 "d"
560 rebasing 4:e860deea161a "e"
560 rebasing 4:e860deea161a "e"
561 rebase completed successfully
561 rebase completed successfully
562 apply changes (yn)? n
562 apply changes (yn)? n
563 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
563 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
564 @ 6:baf10c5166d4 test
564 @ 6:baf10c5166d4 test
565 | g
565 | g
566 |
566 |
567 o 5:6343ca3eff20 test
567 o 5:6343ca3eff20 test
568 | f
568 | f
569 |
569 |
570 | o 4:e860deea161a test
570 | o 4:e860deea161a test
571 | | e
571 | | e
572 | |
572 | |
573 | o 3:055a42cdd887 test
573 | o 3:055a42cdd887 test
574 | | d
574 | | d
575 | |
575 | |
576 | o 2:177f92b77385 test
576 | o 2:177f92b77385 test
577 |/ c
577 |/ c
578 |
578 |
579 o 1:d2ae7f538514 test
579 o 1:d2ae7f538514 test
580 | b
580 | b
581 |
581 |
582 o 0:cb9a9f314b8b test
582 o 0:cb9a9f314b8b test
583 a
583 a
584
584
585 $ hg rebase -s 2 -d . --keep --config ui.interactive=True --confirm << EOF
585 $ hg rebase -s 2 -d . --keep --config ui.interactive=True --confirm << EOF
586 > y
586 > y
587 > EOF
587 > EOF
588 starting in-memory rebase
588 starting in-memory rebase
589 rebasing 2:177f92b77385 "c"
589 rebasing 2:177f92b77385 "c"
590 rebasing 3:055a42cdd887 "d"
590 rebasing 3:055a42cdd887 "d"
591 rebasing 4:e860deea161a "e"
591 rebasing 4:e860deea161a "e"
592 rebase completed successfully
592 rebase completed successfully
593 apply changes (yn)? y
593 apply changes (yn)? y
594 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
594 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
595 o 9:9fd28f55f6dc test
595 o 9:9fd28f55f6dc test
596 | e
596 | e
597 |
597 |
598 o 8:12cbf031f469 test
598 o 8:12cbf031f469 test
599 | d
599 | d
600 |
600 |
601 o 7:c83b1da5b1ae test
601 o 7:c83b1da5b1ae test
602 | c
602 | c
603 |
603 |
604 @ 6:baf10c5166d4 test
604 @ 6:baf10c5166d4 test
605 | g
605 | g
606 |
606 |
607 o 5:6343ca3eff20 test
607 o 5:6343ca3eff20 test
608 | f
608 | f
609 |
609 |
610 | o 4:e860deea161a test
610 | o 4:e860deea161a test
611 | | e
611 | | e
612 | |
612 | |
613 | o 3:055a42cdd887 test
613 | o 3:055a42cdd887 test
614 | | d
614 | | d
615 | |
615 | |
616 | o 2:177f92b77385 test
616 | o 2:177f92b77385 test
617 |/ c
617 |/ c
618 |
618 |
619 o 1:d2ae7f538514 test
619 o 1:d2ae7f538514 test
620 | b
620 | b
621 |
621 |
622 o 0:cb9a9f314b8b test
622 o 0:cb9a9f314b8b test
623 a
623 a
624
624
625 Test --confirm option when there is a conflict
625 Test --confirm option when there is a conflict
626 $ hg up tip -q
626 $ hg up tip -q
627 $ echo ee>e
627 $ echo ee>e
628 $ hg ci --amend -m "conflict with e" -q
628 $ hg ci --amend -m "conflict with e" -q
629 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
629 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
630 @ 9:906d72f66a59 test
630 @ 9:906d72f66a59 test
631 | conflict with e
631 | conflict with e
632 |
632 |
633 o 8:12cbf031f469 test
633 o 8:12cbf031f469 test
634 | d
634 | d
635 |
635 |
636 o 7:c83b1da5b1ae test
636 o 7:c83b1da5b1ae test
637 | c
637 | c
638 |
638 |
639 o 6:baf10c5166d4 test
639 o 6:baf10c5166d4 test
640 | g
640 | g
641 |
641 |
642 o 5:6343ca3eff20 test
642 o 5:6343ca3eff20 test
643 | f
643 | f
644 |
644 |
645 | o 4:e860deea161a test
645 | o 4:e860deea161a test
646 | | e
646 | | e
647 | |
647 | |
648 | o 3:055a42cdd887 test
648 | o 3:055a42cdd887 test
649 | | d
649 | | d
650 | |
650 | |
651 | o 2:177f92b77385 test
651 | o 2:177f92b77385 test
652 |/ c
652 |/ c
653 |
653 |
654 o 1:d2ae7f538514 test
654 o 1:d2ae7f538514 test
655 | b
655 | b
656 |
656 |
657 o 0:cb9a9f314b8b test
657 o 0:cb9a9f314b8b test
658 a
658 a
659
659
660 $ hg rebase -s 4 -d . --keep --confirm
660 $ hg rebase -s 4 -d . --keep --confirm
661 starting in-memory rebase
661 starting in-memory rebase
662 rebasing 4:e860deea161a "e"
662 rebasing 4:e860deea161a "e"
663 merging e
663 merging e
664 hit a merge conflict
664 hit a merge conflict
665 [1]
665 [1]
666 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
666 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
667 @ 9:906d72f66a59 test
667 @ 9:906d72f66a59 test
668 | conflict with e
668 | conflict with e
669 |
669 |
670 o 8:12cbf031f469 test
670 o 8:12cbf031f469 test
671 | d
671 | d
672 |
672 |
673 o 7:c83b1da5b1ae test
673 o 7:c83b1da5b1ae test
674 | c
674 | c
675 |
675 |
676 o 6:baf10c5166d4 test
676 o 6:baf10c5166d4 test
677 | g
677 | g
678 |
678 |
679 o 5:6343ca3eff20 test
679 o 5:6343ca3eff20 test
680 | f
680 | f
681 |
681 |
682 | o 4:e860deea161a test
682 | o 4:e860deea161a test
683 | | e
683 | | e
684 | |
684 | |
685 | o 3:055a42cdd887 test
685 | o 3:055a42cdd887 test
686 | | d
686 | | d
687 | |
687 | |
688 | o 2:177f92b77385 test
688 | o 2:177f92b77385 test
689 |/ c
689 |/ c
690 |
690 |
691 o 1:d2ae7f538514 test
691 o 1:d2ae7f538514 test
692 | b
692 | b
693 |
693 |
694 o 0:cb9a9f314b8b test
694 o 0:cb9a9f314b8b test
695 a
695 a
696
696
697 Test a metadata-only in-memory merge
697 Test a metadata-only in-memory merge
698 $ cd $TESTTMP
698 $ cd $TESTTMP
699 $ hg init no_exception
699 $ hg init no_exception
700 $ cd no_exception
700 $ cd no_exception
701 # Produce the following graph:
701 # Produce the following graph:
702 # o 'add +x to foo.txt'
702 # o 'add +x to foo.txt'
703 # | o r1 (adds bar.txt, just for something to rebase to)
703 # | o r1 (adds bar.txt, just for something to rebase to)
704 # |/
704 # |/
705 # o r0 (adds foo.txt, no +x)
705 # o r0 (adds foo.txt, no +x)
706 $ echo hi > foo.txt
706 $ echo hi > foo.txt
707 $ hg ci -qAm r0
707 $ hg ci -qAm r0
708 $ echo hi > bar.txt
708 $ echo hi > bar.txt
709 $ hg ci -qAm r1
709 $ hg ci -qAm r1
710 $ hg co -qr ".^"
710 $ hg co -qr ".^"
711 $ chmod +x foo.txt
711 $ chmod +x foo.txt
712 $ hg ci -qAm 'add +x to foo.txt'
712 $ hg ci -qAm 'add +x to foo.txt'
713 issue5960: this was raising an AttributeError exception
713 issue5960: this was raising an AttributeError exception
714 $ hg rebase -r . -d 1
714 $ hg rebase -r . -d 1
715 rebasing 2:539b93e77479 "add +x to foo.txt" (tip)
715 rebasing 2:539b93e77479 "add +x to foo.txt" (tip)
716 saved backup bundle to $TESTTMP/no_exception/.hg/strip-backup/*.hg (glob)
716 saved backup bundle to $TESTTMP/no_exception/.hg/strip-backup/*.hg (glob)
717 $ hg diff -c tip
717 $ hg diff -c tip
718 diff --git a/foo.txt b/foo.txt
718 diff --git a/foo.txt b/foo.txt
719 old mode 100644
719 old mode 100644
720 new mode 100755
720 new mode 100755
721
721
722 Test rebasing a commit with copy information, but no content changes
722 Test rebasing a commit with copy information, but no content changes
723
723
724 $ cd ..
724 $ cd ..
725 $ hg clone -q repo1 merge-and-rename
725 $ hg clone -q repo1 merge-and-rename
726 $ cd merge-and-rename
726 $ cd merge-and-rename
727 $ cat << EOF >> .hg/hgrc
727 $ cat << EOF >> .hg/hgrc
728 > [experimental]
728 > [experimental]
729 > evolution.createmarkers=True
729 > evolution.createmarkers=True
730 > evolution.allowunstable=True
730 > evolution.allowunstable=True
731 > EOF
731 > EOF
732 $ hg co -q 1
732 $ hg co -q 1
733 $ hg mv d e
733 $ hg mv d e
734 $ hg ci -qm 'rename d to e'
734 $ hg ci -qm 'rename d to e'
735 $ hg co -q 3
735 $ hg co -q 3
736 $ hg merge -q 4
736 $ hg merge -q 4
737 $ hg ci -m 'merge'
737 $ hg ci -m 'merge'
738 $ hg co -q 2
738 $ hg co -q 2
739 $ mv d e
739 $ mv d e
740 $ hg addremove -qs 0
740 $ hg addremove -qs 0
741 $ hg ci -qm 'untracked rename of d to e'
741 $ hg ci -qm 'untracked rename of d to e'
742 $ hg debugobsolete -q `hg log -T '{node}' -r 4` `hg log -T '{node}' -r .`
742 $ hg debugobsolete -q `hg log -T '{node}' -r 4` `hg log -T '{node}' -r .`
743 1 new orphan changesets
743 1 new orphan changesets
744 $ hg tglog
744 $ hg tglog
745 @ 6: 676538af172d 'untracked rename of d to e'
745 @ 6: 676538af172d 'untracked rename of d to e'
746 |
746 |
747 | * 5: 71cb43376053 'merge'
747 | * 5: 71cb43376053 'merge'
748 | |\
748 | |\
749 | | x 4: 2c8b5dad7956 'rename d to e'
749 | | x 4: 2c8b5dad7956 'rename d to e'
750 | | |
750 | | |
751 | o | 3: ca58782ad1e4 'b'
751 | o | 3: ca58782ad1e4 'b'
752 |/ /
752 |/ /
753 o / 2: 814f6bd05178 'c'
753 o / 2: 814f6bd05178 'c'
754 |/
754 |/
755 o 1: 02952614a83d 'd'
755 o 1: 02952614a83d 'd'
756 |
756 |
757 o 0: b173517d0057 'a'
757 o 0: b173517d0057 'a'
758
758
759 $ hg rebase -b 5 -d tip
759 $ hg rebase -b 5 -d tip
760 rebasing 3:ca58782ad1e4 "b"
760 rebasing 3:ca58782ad1e4 "b"
761 rebasing 5:71cb43376053 "merge"
761 rebasing 5:71cb43376053 "merge"
762 note: not rebasing 5:71cb43376053 "merge", its destination already has all its changes
762 note: not rebasing 5:71cb43376053 "merge", its destination already has all its changes
763
764 $ cd ..
765
766 Test rebasing when the file we are merging in destination is empty
767
768 $ hg init test
769 $ cd test
770 $ echo a > foo
771 $ hg ci -Aqm 'added a to foo'
772
773 $ rm foo
774 $ touch foo
775 $ hg di
776 diff --git a/foo b/foo
777 --- a/foo
778 +++ b/foo
779 @@ -1,1 +0,0 @@
780 -a
781
782 $ hg ci -m "make foo an empty file"
783
784 $ hg up '.^'
785 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
786 $ echo b > foo
787 $ hg di
788 diff --git a/foo b/foo
789 --- a/foo
790 +++ b/foo
791 @@ -1,1 +1,1 @@
792 -a
793 +b
794 $ hg ci -m "add b to foo"
795 created new head
796
797 $ hg rebase -r . -d 1 --config ui.merge=internal:merge3
798 rebasing 2:fb62b706688e "add b to foo" (tip)
799 merging foo
800 hit merge conflicts; re-running rebase without in-memory merge
801 rebasing 2:fb62b706688e "add b to foo" (tip)
802 merging foo
803 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
804 unresolved conflicts (see hg resolve, then hg rebase --continue)
805 [1]
General Comments 0
You need to be logged in to leave comments. Login now