##// END OF EJS Templates
branching: merge with stable
marmoute -
r51579:a41eeb87 merge default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,246 +1,247 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,262 +1,263 b''
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
208 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1
208 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1
209 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2
209 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2
210 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0
210 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0
211 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4
211 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4
212 065704cbdbdbb05dcd6bb814eb9bbdd982211b28 5.4.1
212 065704cbdbdbb05dcd6bb814eb9bbdd982211b28 5.4.1
213 0ea9c86fac8974cd74dc12ea681c8986eb6da6c4 5.4.2
213 0ea9c86fac8974cd74dc12ea681c8986eb6da6c4 5.4.2
214 28163c5de797e5416f9b588940f4608269b4d50a 5.5rc0
214 28163c5de797e5416f9b588940f4608269b4d50a 5.5rc0
215 7fc3c5fbc65f6fe85d70ea63923b8767dda4f2e0 5.5
215 7fc3c5fbc65f6fe85d70ea63923b8767dda4f2e0 5.5
216 f62bb5d07848ca598aa860a517394130b61bf2ee 5.5.1
216 f62bb5d07848ca598aa860a517394130b61bf2ee 5.5.1
217 07731064ac41dacdf0ec869ebd05c2e848c14fbf 5.5.2
217 07731064ac41dacdf0ec869ebd05c2e848c14fbf 5.5.2
218 0e06a7ab9e0d5c65af4e511aee1e0342998799df 5.6rc0
218 0e06a7ab9e0d5c65af4e511aee1e0342998799df 5.6rc0
219 18c17d63fdabd009e70bf994e5efb7db422f4f7f 5.6
219 18c17d63fdabd009e70bf994e5efb7db422f4f7f 5.6
220 1d5189a57405ceca5aa244052c9f948977f4699b 5.6.1
220 1d5189a57405ceca5aa244052c9f948977f4699b 5.6.1
221 9da65e3cf3706ff41e08b311381c588440c27baf 5.7rc0
221 9da65e3cf3706ff41e08b311381c588440c27baf 5.7rc0
222 0e2e7300f4302b02412b0b734717697049494c4c 5.7
222 0e2e7300f4302b02412b0b734717697049494c4c 5.7
223 d5d9177c0045d206db575bae6daa98e2cb2fe5bc 5.7.1
223 d5d9177c0045d206db575bae6daa98e2cb2fe5bc 5.7.1
224 f67b8946bb1b6cfa8328dbf8d6a9128b69ccdcb4 5.8rc0
224 f67b8946bb1b6cfa8328dbf8d6a9128b69ccdcb4 5.8rc0
225 8d2b62d716b095507effaa8d56f87cd27ba659ab 5.8rc1
225 8d2b62d716b095507effaa8d56f87cd27ba659ab 5.8rc1
226 067f2c53fb24506c9e9fb4639871b13b19a85f8a 5.8
226 067f2c53fb24506c9e9fb4639871b13b19a85f8a 5.8
227 411dc27fd9fd076d6a031a08fcaace659afe2fe3 5.8.1
227 411dc27fd9fd076d6a031a08fcaace659afe2fe3 5.8.1
228 d7515d29761d5ada7d9c765f517db67db75dea9a 5.9rc0
228 d7515d29761d5ada7d9c765f517db67db75dea9a 5.9rc0
229 2813d406b03607cdb8c06cb04c44efcc9a79d9a2 5.9rc1
229 2813d406b03607cdb8c06cb04c44efcc9a79d9a2 5.9rc1
230 53221078e0de65d1a821ce5311dec45a7a978301 5.9
230 53221078e0de65d1a821ce5311dec45a7a978301 5.9
231 86a60679cf619e14cee9442f865fcf31b142cb9f 5.9.1
231 86a60679cf619e14cee9442f865fcf31b142cb9f 5.9.1
232 750920b18aaaddd654756be40dec59d90f2643be 5.9.2
232 750920b18aaaddd654756be40dec59d90f2643be 5.9.2
233 6ee0244fc1cf889ae543d2ce0ec45201ae0be6e1 5.9.3
233 6ee0244fc1cf889ae543d2ce0ec45201ae0be6e1 5.9.3
234 a44bb185f6bdbecc754996d8386722e2f0123b0a 6.0rc0
234 a44bb185f6bdbecc754996d8386722e2f0123b0a 6.0rc0
235 5d08b289e2e526259d7d5ea32b70fe76d5b327d7 6.0
235 5d08b289e2e526259d7d5ea32b70fe76d5b327d7 6.0
236 799fdf4cca80cb9ae40537a90995e6bd163ebc0b 6.0.1
236 799fdf4cca80cb9ae40537a90995e6bd163ebc0b 6.0.1
237 75676122c2bf7594ac732b7388db4c74c648b365 6.0.2
237 75676122c2bf7594ac732b7388db4c74c648b365 6.0.2
238 dcec16e799ddb6d33fcd11b04af530250a417a58 6.0.3
238 dcec16e799ddb6d33fcd11b04af530250a417a58 6.0.3
239 c00d3ce4e94bb0ee8d809e25e1dcb2a5fab84e2c 6.1rc0
239 c00d3ce4e94bb0ee8d809e25e1dcb2a5fab84e2c 6.1rc0
240 d4486810a1795fba9521449b8885ced034f3a6dd 6.1
240 d4486810a1795fba9521449b8885ced034f3a6dd 6.1
241 5bd6bcd31dd1ebb63b8914b00064f96297267af7 6.1.1
241 5bd6bcd31dd1ebb63b8914b00064f96297267af7 6.1.1
242 0ddd5e1f5f67438af85d12e4ce6c39021dde9916 6.1.2
242 0ddd5e1f5f67438af85d12e4ce6c39021dde9916 6.1.2
243 6b10151b962108f65bfa12b3918b1021ca334f73 6.1.3
243 6b10151b962108f65bfa12b3918b1021ca334f73 6.1.3
244 0cc5f74ff7f0f4ac2427096bddbe102dbc2453ae 6.1.4
244 0cc5f74ff7f0f4ac2427096bddbe102dbc2453ae 6.1.4
245 288de6f5d724bba7bf1669e2838f196962bb7528 6.2rc0
245 288de6f5d724bba7bf1669e2838f196962bb7528 6.2rc0
246 094a5fa3cf52f936e0de3f1e507c818bee5ece6b 6.2
246 094a5fa3cf52f936e0de3f1e507c818bee5ece6b 6.2
247 f69bffd00abe3a1b94d1032eb2c92e611d16a192 6.2.1
247 f69bffd00abe3a1b94d1032eb2c92e611d16a192 6.2.1
248 b5c8524827d20fe2e0ca8fb1234a0fe35a1a36c7 6.2.2
248 b5c8524827d20fe2e0ca8fb1234a0fe35a1a36c7 6.2.2
249 dbdee8ac3e3fcdda1fa55b90c0a235125b7f8e6f 6.2.3
249 dbdee8ac3e3fcdda1fa55b90c0a235125b7f8e6f 6.2.3
250 a3356ab610fc50000cf0ba55c424a4d96da11db7 6.3rc0
250 a3356ab610fc50000cf0ba55c424a4d96da11db7 6.3rc0
251 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
251 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
252 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3
252 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3
253 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
253 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
254 0000000000000000000000000000000000000000 6.3.0
254 0000000000000000000000000000000000000000 6.3.0
255 c890d8b8bc59b18e5febf60caada629df5356ee2 6.3.1
255 c890d8b8bc59b18e5febf60caada629df5356ee2 6.3.1
256 59466b13a3ae0e29a5d4f485393e516cfbb057d0 6.3.2
256 59466b13a3ae0e29a5d4f485393e516cfbb057d0 6.3.2
257 8830004967ad865ead89c28a410405a6e71e0796 6.3.3
257 8830004967ad865ead89c28a410405a6e71e0796 6.3.3
258 05de4896508e8ec387b33eb30d8aab78d1c8e9e4 6.4rc0
258 05de4896508e8ec387b33eb30d8aab78d1c8e9e4 6.4rc0
259 f14864fffdcab725d9eac6d4f4c07be05a35f59a 6.4
259 f14864fffdcab725d9eac6d4f4c07be05a35f59a 6.4
260 83ea6ce48b4fd09fb79c4e34cc5750c805699a53 6.4.1
260 83ea6ce48b4fd09fb79c4e34cc5750c805699a53 6.4.1
261 f952be90b0514a576dcc8bbe758ce3847faba9bb 6.4.2
261 f952be90b0514a576dcc8bbe758ce3847faba9bb 6.4.2
262 fc445f8abcf90b33db7c463816a1b3560681767f 6.4.3
262 fc445f8abcf90b33db7c463816a1b3560681767f 6.4.3
263 da372c745e0f053bb7a64e74cccd15810d96341d 6.4.4
@@ -1,1034 +1,1036 b''
1 # This software may be used and distributed according to the terms of the
1 # This software may be used and distributed according to the terms of the
2 # GNU General Public License version 2 or any later version.
2 # GNU General Public License version 2 or any later version.
3
3
4 """advertise pre-generated bundles to seed clones
4 """advertise pre-generated bundles to seed clones
5
5
6 "clonebundles" is a server-side extension used to advertise the existence
6 "clonebundles" is a server-side extension used to advertise the existence
7 of pre-generated, externally hosted bundle files to clients that are
7 of pre-generated, externally hosted bundle files to clients that are
8 cloning so that cloning can be faster, more reliable, and require less
8 cloning so that cloning can be faster, more reliable, and require less
9 resources on the server. "pullbundles" is a related feature for sending
9 resources on the server. "pullbundles" is a related feature for sending
10 pre-generated bundle files to clients as part of pull operations.
10 pre-generated bundle files to clients as part of pull operations.
11
11
12 Cloning can be a CPU and I/O intensive operation on servers. Traditionally,
12 Cloning can be a CPU and I/O intensive operation on servers. Traditionally,
13 the server, in response to a client's request to clone, dynamically generates
13 the server, in response to a client's request to clone, dynamically generates
14 a bundle containing the entire repository content and sends it to the client.
14 a bundle containing the entire repository content and sends it to the client.
15 There is no caching on the server and the server will have to redundantly
15 There is no caching on the server and the server will have to redundantly
16 generate the same outgoing bundle in response to each clone request. For
16 generate the same outgoing bundle in response to each clone request. For
17 servers with large repositories or with high clone volume, the load from
17 servers with large repositories or with high clone volume, the load from
18 clones can make scaling the server challenging and costly.
18 clones can make scaling the server challenging and costly.
19
19
20 This extension provides server operators the ability to offload
20 This extension provides server operators the ability to offload
21 potentially expensive clone load to an external service. Pre-generated
21 potentially expensive clone load to an external service. Pre-generated
22 bundles also allow using more CPU intensive compression, reducing the
22 bundles also allow using more CPU intensive compression, reducing the
23 effective bandwidth requirements.
23 effective bandwidth requirements.
24
24
25 Here's how clone bundles work:
25 Here's how clone bundles work:
26
26
27 1. A server operator establishes a mechanism for making bundle files available
27 1. A server operator establishes a mechanism for making bundle files available
28 on a hosting service where Mercurial clients can fetch them.
28 on a hosting service where Mercurial clients can fetch them.
29 2. A manifest file listing available bundle URLs and some optional metadata
29 2. A manifest file listing available bundle URLs and some optional metadata
30 is added to the Mercurial repository on the server.
30 is added to the Mercurial repository on the server.
31 3. A client initiates a clone against a clone bundles aware server.
31 3. A client initiates a clone against a clone bundles aware server.
32 4. The client sees the server is advertising clone bundles and fetches the
32 4. The client sees the server is advertising clone bundles and fetches the
33 manifest listing available bundles.
33 manifest listing available bundles.
34 5. The client filters and sorts the available bundles based on what it
34 5. The client filters and sorts the available bundles based on what it
35 supports and prefers.
35 supports and prefers.
36 6. The client downloads and applies an available bundle from the
36 6. The client downloads and applies an available bundle from the
37 server-specified URL.
37 server-specified URL.
38 7. The client reconnects to the original server and performs the equivalent
38 7. The client reconnects to the original server and performs the equivalent
39 of :hg:`pull` to retrieve all repository data not in the bundle. (The
39 of :hg:`pull` to retrieve all repository data not in the bundle. (The
40 repository could have been updated between when the bundle was created
40 repository could have been updated between when the bundle was created
41 and when the client started the clone.) This may use "pullbundles".
41 and when the client started the clone.) This may use "pullbundles".
42
42
43 Instead of the server generating full repository bundles for every clone
43 Instead of the server generating full repository bundles for every clone
44 request, it generates full bundles once and they are subsequently reused to
44 request, it generates full bundles once and they are subsequently reused to
45 bootstrap new clones. The server may still transfer data at clone time.
45 bootstrap new clones. The server may still transfer data at clone time.
46 However, this is only data that has been added/changed since the bundle was
46 However, this is only data that has been added/changed since the bundle was
47 created. For large, established repositories, this can reduce server load for
47 created. For large, established repositories, this can reduce server load for
48 clones to less than 1% of original.
48 clones to less than 1% of original.
49
49
50 Here's how pullbundles work:
50 Here's how pullbundles work:
51
51
52 1. A manifest file listing available bundles and describing the revisions
52 1. A manifest file listing available bundles and describing the revisions
53 is added to the Mercurial repository on the server.
53 is added to the Mercurial repository on the server.
54 2. A new-enough client informs the server that it supports partial pulls
54 2. A new-enough client informs the server that it supports partial pulls
55 and initiates a pull.
55 and initiates a pull.
56 3. If the server has pull bundles enabled and sees the client advertising
56 3. If the server has pull bundles enabled and sees the client advertising
57 partial pulls, it checks for a matching pull bundle in the manifest.
57 partial pulls, it checks for a matching pull bundle in the manifest.
58 A bundle matches if the format is supported by the client, the client
58 A bundle matches if the format is supported by the client, the client
59 has the required revisions already and needs something from the bundle.
59 has the required revisions already and needs something from the bundle.
60 4. If there is at least one matching bundle, the server sends it to the client.
60 4. If there is at least one matching bundle, the server sends it to the client.
61 5. The client applies the bundle and notices that the server reply was
61 5. The client applies the bundle and notices that the server reply was
62 incomplete. It initiates another pull.
62 incomplete. It initiates another pull.
63
63
64 To work, this extension requires the following of server operators:
64 To work, this extension requires the following of server operators:
65
65
66 * Generating bundle files of repository content (typically periodically,
66 * Generating bundle files of repository content (typically periodically,
67 such as once per day).
67 such as once per day).
68 * Clone bundles: A file server that clients have network access to and that
68 * Clone bundles: A file server that clients have network access to and that
69 Python knows how to talk to through its normal URL handling facility
69 Python knows how to talk to through its normal URL handling facility
70 (typically an HTTP/HTTPS server).
70 (typically an HTTP/HTTPS server).
71 * A process for keeping the bundles manifest in sync with available bundle
71 * A process for keeping the bundles manifest in sync with available bundle
72 files.
72 files.
73
73
74 Strictly speaking, using a static file hosting server isn't required: a server
74 Strictly speaking, using a static file hosting server isn't required: a server
75 operator could use a dynamic service for retrieving bundle data. However,
75 operator could use a dynamic service for retrieving bundle data. However,
76 static file hosting services are simple and scalable and should be sufficient
76 static file hosting services are simple and scalable and should be sufficient
77 for most needs.
77 for most needs.
78
78
79 Bundle files can be generated with the :hg:`bundle` command. Typically
79 Bundle files can be generated with the :hg:`bundle` command. Typically
80 :hg:`bundle --all` is used to produce a bundle of the entire repository.
80 :hg:`bundle --all` is used to produce a bundle of the entire repository.
81
81
82 :hg:`debugcreatestreamclonebundle` can be used to produce a special
82 The bundlespec option `stream` (see :hg:`help bundlespec`)
83 *streaming clonebundle*. These are bundle files that are extremely efficient
83 can be used to produce a special *streaming clonebundle*, typically using
84 :hg:`bundle --all --type="none-streamv2"`.
85 These are bundle files that are extremely efficient
84 to produce and consume (read: fast). However, they are larger than
86 to produce and consume (read: fast). However, they are larger than
85 traditional bundle formats and require that clients support the exact set
87 traditional bundle formats and require that clients support the exact set
86 of repository data store formats in use by the repository that created them.
88 of repository data store formats in use by the repository that created them.
87 Typically, a newer server can serve data that is compatible with older clients.
89 Typically, a newer server can serve data that is compatible with older clients.
88 However, *streaming clone bundles* don't have this guarantee. **Server
90 However, *streaming clone bundles* don't have this guarantee. **Server
89 operators need to be aware that newer versions of Mercurial may produce
91 operators need to be aware that newer versions of Mercurial may produce
90 streaming clone bundles incompatible with older Mercurial versions.**
92 streaming clone bundles incompatible with older Mercurial versions.**
91
93
92 A server operator is responsible for creating a ``.hg/clonebundles.manifest``
94 A server operator is responsible for creating a ``.hg/clonebundles.manifest``
93 file containing the list of available bundle files suitable for seeding
95 file containing the list of available bundle files suitable for seeding
94 clones. If this file does not exist, the repository will not advertise the
96 clones. If this file does not exist, the repository will not advertise the
95 existence of clone bundles when clients connect. For pull bundles,
97 existence of clone bundles when clients connect. For pull bundles,
96 ``.hg/pullbundles.manifest`` is used.
98 ``.hg/pullbundles.manifest`` is used.
97
99
98 The manifest file contains a newline (\\n) delimited list of entries.
100 The manifest file contains a newline (\\n) delimited list of entries.
99
101
100 Each line in this file defines an available bundle. Lines have the format:
102 Each line in this file defines an available bundle. Lines have the format:
101
103
102 <URL> [<key>=<value>[ <key>=<value>]]
104 <URL> [<key>=<value>[ <key>=<value>]]
103
105
104 That is, a URL followed by an optional, space-delimited list of key=value
106 That is, a URL followed by an optional, space-delimited list of key=value
105 pairs describing additional properties of this bundle. Both keys and values
107 pairs describing additional properties of this bundle. Both keys and values
106 are URI encoded.
108 are URI encoded.
107
109
108 For pull bundles, the URL is a path under the ``.hg`` directory of the
110 For pull bundles, the URL is a path under the ``.hg`` directory of the
109 repository.
111 repository.
110
112
111 Keys in UPPERCASE are reserved for use by Mercurial and are defined below.
113 Keys in UPPERCASE are reserved for use by Mercurial and are defined below.
112 All non-uppercase keys can be used by site installations. An example use
114 All non-uppercase keys can be used by site installations. An example use
113 for custom properties is to use the *datacenter* attribute to define which
115 for custom properties is to use the *datacenter* attribute to define which
114 data center a file is hosted in. Clients could then prefer a server in the
116 data center a file is hosted in. Clients could then prefer a server in the
115 data center closest to them.
117 data center closest to them.
116
118
117 The following reserved keys are currently defined:
119 The following reserved keys are currently defined:
118
120
119 BUNDLESPEC
121 BUNDLESPEC
120 A "bundle specification" string that describes the type of the bundle.
122 A "bundle specification" string that describes the type of the bundle.
121
123
122 These are string values that are accepted by the "--type" argument of
124 These are string values that are accepted by the "--type" argument of
123 :hg:`bundle`.
125 :hg:`bundle`.
124
126
125 The values are parsed in strict mode, which means they must be of the
127 The values are parsed in strict mode, which means they must be of the
126 "<compression>-<type>" form. See
128 "<compression>-<type>" form. See
127 mercurial.exchange.parsebundlespec() for more details.
129 mercurial.exchange.parsebundlespec() for more details.
128
130
129 :hg:`debugbundle --spec` can be used to print the bundle specification
131 :hg:`debugbundle --spec` can be used to print the bundle specification
130 string for a bundle file. The output of this command can be used verbatim
132 string for a bundle file. The output of this command can be used verbatim
131 for the value of ``BUNDLESPEC`` (it is already escaped).
133 for the value of ``BUNDLESPEC`` (it is already escaped).
132
134
133 Clients will automatically filter out specifications that are unknown or
135 Clients will automatically filter out specifications that are unknown or
134 unsupported so they won't attempt to download something that likely won't
136 unsupported so they won't attempt to download something that likely won't
135 apply.
137 apply.
136
138
137 The actual value doesn't impact client behavior beyond filtering:
139 The actual value doesn't impact client behavior beyond filtering:
138 clients will still sniff the bundle type from the header of downloaded
140 clients will still sniff the bundle type from the header of downloaded
139 files.
141 files.
140
142
141 **Use of this key is highly recommended**, as it allows clients to
143 **Use of this key is highly recommended**, as it allows clients to
142 easily skip unsupported bundles. If this key is not defined, an old
144 easily skip unsupported bundles. If this key is not defined, an old
143 client may attempt to apply a bundle that it is incapable of reading.
145 client may attempt to apply a bundle that it is incapable of reading.
144
146
145 REQUIRESNI
147 REQUIRESNI
146 Whether Server Name Indication (SNI) is required to connect to the URL.
148 Whether Server Name Indication (SNI) is required to connect to the URL.
147 SNI allows servers to use multiple certificates on the same IP. It is
149 SNI allows servers to use multiple certificates on the same IP. It is
148 somewhat common in CDNs and other hosting providers. Older Python
150 somewhat common in CDNs and other hosting providers. Older Python
149 versions do not support SNI. Defining this attribute enables clients
151 versions do not support SNI. Defining this attribute enables clients
150 with older Python versions to filter this entry without experiencing
152 with older Python versions to filter this entry without experiencing
151 an opaque SSL failure at connection time.
153 an opaque SSL failure at connection time.
152
154
153 If this is defined, it is important to advertise a non-SNI fallback
155 If this is defined, it is important to advertise a non-SNI fallback
154 URL or clients running old Python releases may not be able to clone
156 URL or clients running old Python releases may not be able to clone
155 with the clonebundles facility.
157 with the clonebundles facility.
156
158
157 Value should be "true".
159 Value should be "true".
158
160
159 REQUIREDRAM
161 REQUIREDRAM
160 Value specifies expected memory requirements to decode the payload.
162 Value specifies expected memory requirements to decode the payload.
161 Values can have suffixes for common bytes sizes. e.g. "64MB".
163 Values can have suffixes for common bytes sizes. e.g. "64MB".
162
164
163 This key is often used with zstd-compressed bundles using a high
165 This key is often used with zstd-compressed bundles using a high
164 compression level / window size, which can require 100+ MB of memory
166 compression level / window size, which can require 100+ MB of memory
165 to decode.
167 to decode.
166
168
167 heads
169 heads
168 Used for pull bundles. This contains the ``;`` separated changeset
170 Used for pull bundles. This contains the ``;`` separated changeset
169 hashes of the heads of the bundle content.
171 hashes of the heads of the bundle content.
170
172
171 bases
173 bases
172 Used for pull bundles. This contains the ``;`` separated changeset
174 Used for pull bundles. This contains the ``;`` separated changeset
173 hashes of the roots of the bundle content. This can be skipped if
175 hashes of the roots of the bundle content. This can be skipped if
174 the bundle was created without ``--base``.
176 the bundle was created without ``--base``.
175
177
176 Manifests can contain multiple entries. Assuming metadata is defined, clients
178 Manifests can contain multiple entries. Assuming metadata is defined, clients
177 will filter entries from the manifest that they don't support. The remaining
179 will filter entries from the manifest that they don't support. The remaining
178 entries are optionally sorted by client preferences
180 entries are optionally sorted by client preferences
179 (``ui.clonebundleprefers`` config option). The client then attempts
181 (``ui.clonebundleprefers`` config option). The client then attempts
180 to fetch the bundle at the first URL in the remaining list.
182 to fetch the bundle at the first URL in the remaining list.
181
183
182 **Errors when downloading a bundle will fail the entire clone operation:
184 **Errors when downloading a bundle will fail the entire clone operation:
183 clients do not automatically fall back to a traditional clone.** The reason
185 clients do not automatically fall back to a traditional clone.** The reason
184 for this is that if a server is using clone bundles, it is probably doing so
186 for this is that if a server is using clone bundles, it is probably doing so
185 because the feature is necessary to help it scale. In other words, there
187 because the feature is necessary to help it scale. In other words, there
186 is an assumption that clone load will be offloaded to another service and
188 is an assumption that clone load will be offloaded to another service and
187 that the Mercurial server isn't responsible for serving this clone load.
189 that the Mercurial server isn't responsible for serving this clone load.
188 If that other service experiences issues and clients start mass falling back to
190 If that other service experiences issues and clients start mass falling back to
189 the original Mercurial server, the added clone load could overwhelm the server
191 the original Mercurial server, the added clone load could overwhelm the server
190 due to unexpected load and effectively take it offline. Not having clients
192 due to unexpected load and effectively take it offline. Not having clients
191 automatically fall back to cloning from the original server mitigates this
193 automatically fall back to cloning from the original server mitigates this
192 scenario.
194 scenario.
193
195
194 Because there is no automatic Mercurial server fallback on failure of the
196 Because there is no automatic Mercurial server fallback on failure of the
195 bundle hosting service, it is important for server operators to view the bundle
197 bundle hosting service, it is important for server operators to view the bundle
196 hosting service as an extension of the Mercurial server in terms of
198 hosting service as an extension of the Mercurial server in terms of
197 availability and service level agreements: if the bundle hosting service goes
199 availability and service level agreements: if the bundle hosting service goes
198 down, so does the ability for clients to clone. Note: clients will see a
200 down, so does the ability for clients to clone. Note: clients will see a
199 message informing them how to bypass the clone bundles facility when a failure
201 message informing them how to bypass the clone bundles facility when a failure
200 occurs. So server operators should prepare for some people to follow these
202 occurs. So server operators should prepare for some people to follow these
201 instructions when a failure occurs, thus driving more load to the original
203 instructions when a failure occurs, thus driving more load to the original
202 Mercurial server when the bundle hosting service fails.
204 Mercurial server when the bundle hosting service fails.
203
205
204
206
205 inline clonebundles
207 inline clonebundles
206 -------------------
208 -------------------
207
209
208 It is possible to transmit clonebundles inline in case repositories are
210 It is possible to transmit clonebundles inline in case repositories are
209 accessed over SSH. This avoids having to setup an external HTTPS server
211 accessed over SSH. This avoids having to setup an external HTTPS server
210 and results in the same access control as already present for the SSH setup.
212 and results in the same access control as already present for the SSH setup.
211
213
212 Inline clonebundles should be placed into the `.hg/bundle-cache` directory.
214 Inline clonebundles should be placed into the `.hg/bundle-cache` directory.
213 A clonebundle at `.hg/bundle-cache/mybundle.bundle` is referred to
215 A clonebundle at `.hg/bundle-cache/mybundle.bundle` is referred to
214 in the `clonebundles.manifest` file as `peer-bundle-cache://mybundle.bundle`.
216 in the `clonebundles.manifest` file as `peer-bundle-cache://mybundle.bundle`.
215
217
216
218
217 auto-generation of clone bundles
219 auto-generation of clone bundles
218 --------------------------------
220 --------------------------------
219
221
220 It is possible to set Mercurial to automatically re-generate clone bundles when
222 It is possible to set Mercurial to automatically re-generate clone bundles when
221 enough new content is available.
223 enough new content is available.
222
224
223 Mercurial will take care of the process asynchronously. The defined list of
225 Mercurial will take care of the process asynchronously. The defined list of
224 bundle-type will be generated, uploaded, and advertised. Older bundles will get
226 bundle-type will be generated, uploaded, and advertised. Older bundles will get
225 decommissioned as newer ones replace them.
227 decommissioned as newer ones replace them.
226
228
227 Bundles Generation:
229 Bundles Generation:
228 ...................
230 ...................
229
231
230 The extension can generate multiple variants of the clone bundle. Each
232 The extension can generate multiple variants of the clone bundle. Each
231 different variant will be defined by the "bundle-spec" they use::
233 different variant will be defined by the "bundle-spec" they use::
232
234
233 [clone-bundles]
235 [clone-bundles]
234 auto-generate.formats= zstd-v2, gzip-v2
236 auto-generate.formats= zstd-v2, gzip-v2
235
237
236 See `hg help bundlespec` for details about available options.
238 See `hg help bundlespec` for details about available options.
237
239
238 By default, new bundles are generated when 5% of the repository contents or at
240 By default, new bundles are generated when 5% of the repository contents or at
239 least 1000 revisions are not contained in the cached bundles. This option can
241 least 1000 revisions are not contained in the cached bundles. This option can
240 be controlled by the `clone-bundles.trigger.below-bundled-ratio` option
242 be controlled by the `clone-bundles.trigger.below-bundled-ratio` option
241 (default 0.95) and the `clone-bundles.trigger.revs` option (default 1000)::
243 (default 0.95) and the `clone-bundles.trigger.revs` option (default 1000)::
242
244
243 [clone-bundles]
245 [clone-bundles]
244 trigger.below-bundled-ratio=0.95
246 trigger.below-bundled-ratio=0.95
245 trigger.revs=1000
247 trigger.revs=1000
246
248
247 This logic can be manually triggered using the `admin::clone-bundles-refresh`
249 This logic can be manually triggered using the `admin::clone-bundles-refresh`
248 command, or automatically on each repository change if
250 command, or automatically on each repository change if
249 `clone-bundles.auto-generate.on-change` is set to `yes`.
251 `clone-bundles.auto-generate.on-change` is set to `yes`.
250
252
251 [clone-bundles]
253 [clone-bundles]
252 auto-generate.on-change=yes
254 auto-generate.on-change=yes
253 auto-generate.formats= zstd-v2, gzip-v2
255 auto-generate.formats= zstd-v2, gzip-v2
254
256
255 Bundles Upload and Serving:
257 Bundles Upload and Serving:
256 ...........................
258 ...........................
257
259
258 The generated bundles need to be made available to users through a "public" URL.
260 The generated bundles need to be made available to users through a "public" URL.
259 This should be donne through `clone-bundles.upload-command` configuration. The
261 This should be donne through `clone-bundles.upload-command` configuration. The
260 value of this command should be a shell command. It will have access to the
262 value of this command should be a shell command. It will have access to the
261 bundle file path through the `$HGCB_BUNDLE_PATH` variable. And the expected
263 bundle file path through the `$HGCB_BUNDLE_PATH` variable. And the expected
262 basename in the "public" URL is accessible at::
264 basename in the "public" URL is accessible at::
263
265
264 [clone-bundles]
266 [clone-bundles]
265 upload-command=sftp put $HGCB_BUNDLE_PATH \
267 upload-command=sftp put $HGCB_BUNDLE_PATH \
266 sftp://bundles.host/clone-bundles/$HGCB_BUNDLE_BASENAME
268 sftp://bundles.host/clone-bundles/$HGCB_BUNDLE_BASENAME
267
269
268 If the file was already uploaded, the command must still succeed.
270 If the file was already uploaded, the command must still succeed.
269
271
270 After upload, the file should be available at an url defined by
272 After upload, the file should be available at an url defined by
271 `clone-bundles.url-template`.
273 `clone-bundles.url-template`.
272
274
273 [clone-bundles]
275 [clone-bundles]
274 url-template=https://bundles.host/cache/clone-bundles/{basename}
276 url-template=https://bundles.host/cache/clone-bundles/{basename}
275
277
276 Old bundles cleanup:
278 Old bundles cleanup:
277 ....................
279 ....................
278
280
279 When new bundles are generated, the older ones are no longer necessary and can
281 When new bundles are generated, the older ones are no longer necessary and can
280 be removed from storage. This is done through the `clone-bundles.delete-command`
282 be removed from storage. This is done through the `clone-bundles.delete-command`
281 configuration. The command is given the url of the artifact to delete through
283 configuration. The command is given the url of the artifact to delete through
282 the `$HGCB_BUNDLE_URL` environment variable.
284 the `$HGCB_BUNDLE_URL` environment variable.
283
285
284 [clone-bundles]
286 [clone-bundles]
285 delete-command=sftp rm sftp://bundles.host/clone-bundles/$HGCB_BUNDLE_BASENAME
287 delete-command=sftp rm sftp://bundles.host/clone-bundles/$HGCB_BUNDLE_BASENAME
286
288
287 If the file was already deleted, the command must still succeed.
289 If the file was already deleted, the command must still succeed.
288 """
290 """
289
291
290
292
291 import os
293 import os
292 import weakref
294 import weakref
293
295
294 from mercurial.i18n import _
296 from mercurial.i18n import _
295
297
296 from mercurial import (
298 from mercurial import (
297 bundlecaches,
299 bundlecaches,
298 commands,
300 commands,
299 error,
301 error,
300 extensions,
302 extensions,
301 localrepo,
303 localrepo,
302 lock,
304 lock,
303 node,
305 node,
304 registrar,
306 registrar,
305 util,
307 util,
306 wireprotov1server,
308 wireprotov1server,
307 )
309 )
308
310
309
311
310 from mercurial.utils import (
312 from mercurial.utils import (
311 procutil,
313 procutil,
312 )
314 )
313
315
314 testedwith = b'ships-with-hg-core'
316 testedwith = b'ships-with-hg-core'
315
317
316
318
317 def capabilities(orig, repo, proto):
319 def capabilities(orig, repo, proto):
318 caps = orig(repo, proto)
320 caps = orig(repo, proto)
319
321
320 # Only advertise if a manifest exists. This does add some I/O to requests.
322 # Only advertise if a manifest exists. This does add some I/O to requests.
321 # But this should be cheaper than a wasted network round trip due to
323 # But this should be cheaper than a wasted network round trip due to
322 # missing file.
324 # missing file.
323 if repo.vfs.exists(bundlecaches.CB_MANIFEST_FILE):
325 if repo.vfs.exists(bundlecaches.CB_MANIFEST_FILE):
324 caps.append(b'clonebundles')
326 caps.append(b'clonebundles')
325
327
326 return caps
328 return caps
327
329
328
330
329 def extsetup(ui):
331 def extsetup(ui):
330 extensions.wrapfunction(wireprotov1server, b'_capabilities', capabilities)
332 extensions.wrapfunction(wireprotov1server, b'_capabilities', capabilities)
331
333
332
334
333 # logic for bundle auto-generation
335 # logic for bundle auto-generation
334
336
335
337
336 configtable = {}
338 configtable = {}
337 configitem = registrar.configitem(configtable)
339 configitem = registrar.configitem(configtable)
338
340
339 cmdtable = {}
341 cmdtable = {}
340 command = registrar.command(cmdtable)
342 command = registrar.command(cmdtable)
341
343
342 configitem(b'clone-bundles', b'auto-generate.on-change', default=False)
344 configitem(b'clone-bundles', b'auto-generate.on-change', default=False)
343 configitem(b'clone-bundles', b'auto-generate.formats', default=list)
345 configitem(b'clone-bundles', b'auto-generate.formats', default=list)
344 configitem(b'clone-bundles', b'trigger.below-bundled-ratio', default=0.95)
346 configitem(b'clone-bundles', b'trigger.below-bundled-ratio', default=0.95)
345 configitem(b'clone-bundles', b'trigger.revs', default=1000)
347 configitem(b'clone-bundles', b'trigger.revs', default=1000)
346
348
347 configitem(b'clone-bundles', b'upload-command', default=None)
349 configitem(b'clone-bundles', b'upload-command', default=None)
348
350
349 configitem(b'clone-bundles', b'delete-command', default=None)
351 configitem(b'clone-bundles', b'delete-command', default=None)
350
352
351 configitem(b'clone-bundles', b'url-template', default=None)
353 configitem(b'clone-bundles', b'url-template', default=None)
352
354
353 configitem(b'devel', b'debug.clonebundles', default=False)
355 configitem(b'devel', b'debug.clonebundles', default=False)
354
356
355
357
356 # category for the post-close transaction hooks
358 # category for the post-close transaction hooks
357 CAT_POSTCLOSE = b"clonebundles-autobundles"
359 CAT_POSTCLOSE = b"clonebundles-autobundles"
358
360
359 # template for bundle file names
361 # template for bundle file names
360 BUNDLE_MASK = (
362 BUNDLE_MASK = (
361 b"full-%(bundle_type)s-%(revs)d_revs-%(tip_short)s_tip-%(op_id)s.hg"
363 b"full-%(bundle_type)s-%(revs)d_revs-%(tip_short)s_tip-%(op_id)s.hg"
362 )
364 )
363
365
364
366
365 # file in .hg/ use to track clonebundles being auto-generated
367 # file in .hg/ use to track clonebundles being auto-generated
366 AUTO_GEN_FILE = b'clonebundles.auto-gen'
368 AUTO_GEN_FILE = b'clonebundles.auto-gen'
367
369
368
370
369 class BundleBase(object):
371 class BundleBase(object):
370 """represents the core of properties that matters for us in a bundle
372 """represents the core of properties that matters for us in a bundle
371
373
372 :bundle_type: the bundlespec (see hg help bundlespec)
374 :bundle_type: the bundlespec (see hg help bundlespec)
373 :revs: the number of revisions in the repo at bundle creation time
375 :revs: the number of revisions in the repo at bundle creation time
374 :tip_rev: the rev-num of the tip revision
376 :tip_rev: the rev-num of the tip revision
375 :tip_node: the node id of the tip-most revision in the bundle
377 :tip_node: the node id of the tip-most revision in the bundle
376
378
377 :ready: True if the bundle is ready to be served
379 :ready: True if the bundle is ready to be served
378 """
380 """
379
381
380 ready = False
382 ready = False
381
383
382 def __init__(self, bundle_type, revs, tip_rev, tip_node):
384 def __init__(self, bundle_type, revs, tip_rev, tip_node):
383 self.bundle_type = bundle_type
385 self.bundle_type = bundle_type
384 self.revs = revs
386 self.revs = revs
385 self.tip_rev = tip_rev
387 self.tip_rev = tip_rev
386 self.tip_node = tip_node
388 self.tip_node = tip_node
387
389
388 def valid_for(self, repo):
390 def valid_for(self, repo):
389 """is this bundle applicable to the current repository
391 """is this bundle applicable to the current repository
390
392
391 This is useful for detecting bundles made irrelevant by stripping.
393 This is useful for detecting bundles made irrelevant by stripping.
392 """
394 """
393 tip_node = node.bin(self.tip_node)
395 tip_node = node.bin(self.tip_node)
394 return repo.changelog.index.get_rev(tip_node) == self.tip_rev
396 return repo.changelog.index.get_rev(tip_node) == self.tip_rev
395
397
396 def __eq__(self, other):
398 def __eq__(self, other):
397 left = (self.ready, self.bundle_type, self.tip_rev, self.tip_node)
399 left = (self.ready, self.bundle_type, self.tip_rev, self.tip_node)
398 right = (other.ready, other.bundle_type, other.tip_rev, other.tip_node)
400 right = (other.ready, other.bundle_type, other.tip_rev, other.tip_node)
399 return left == right
401 return left == right
400
402
401 def __neq__(self, other):
403 def __neq__(self, other):
402 return not self == other
404 return not self == other
403
405
404 def __cmp__(self, other):
406 def __cmp__(self, other):
405 if self == other:
407 if self == other:
406 return 0
408 return 0
407 return -1
409 return -1
408
410
409
411
410 class RequestedBundle(BundleBase):
412 class RequestedBundle(BundleBase):
411 """A bundle that should be generated.
413 """A bundle that should be generated.
412
414
413 Additional attributes compared to BundleBase
415 Additional attributes compared to BundleBase
414 :heads: list of head revisions (as rev-num)
416 :heads: list of head revisions (as rev-num)
415 :op_id: a "unique" identifier for the operation triggering the change
417 :op_id: a "unique" identifier for the operation triggering the change
416 """
418 """
417
419
418 def __init__(self, bundle_type, revs, tip_rev, tip_node, head_revs, op_id):
420 def __init__(self, bundle_type, revs, tip_rev, tip_node, head_revs, op_id):
419 self.head_revs = head_revs
421 self.head_revs = head_revs
420 self.op_id = op_id
422 self.op_id = op_id
421 super(RequestedBundle, self).__init__(
423 super(RequestedBundle, self).__init__(
422 bundle_type,
424 bundle_type,
423 revs,
425 revs,
424 tip_rev,
426 tip_rev,
425 tip_node,
427 tip_node,
426 )
428 )
427
429
428 @property
430 @property
429 def suggested_filename(self):
431 def suggested_filename(self):
430 """A filename that can be used for the generated bundle"""
432 """A filename that can be used for the generated bundle"""
431 data = {
433 data = {
432 b'bundle_type': self.bundle_type,
434 b'bundle_type': self.bundle_type,
433 b'revs': self.revs,
435 b'revs': self.revs,
434 b'heads': self.head_revs,
436 b'heads': self.head_revs,
435 b'tip_rev': self.tip_rev,
437 b'tip_rev': self.tip_rev,
436 b'tip_node': self.tip_node,
438 b'tip_node': self.tip_node,
437 b'tip_short': self.tip_node[:12],
439 b'tip_short': self.tip_node[:12],
438 b'op_id': self.op_id,
440 b'op_id': self.op_id,
439 }
441 }
440 return BUNDLE_MASK % data
442 return BUNDLE_MASK % data
441
443
442 def generate_bundle(self, repo, file_path):
444 def generate_bundle(self, repo, file_path):
443 """generate the bundle at `filepath`"""
445 """generate the bundle at `filepath`"""
444 commands.bundle(
446 commands.bundle(
445 repo.ui,
447 repo.ui,
446 repo,
448 repo,
447 file_path,
449 file_path,
448 base=[b"null"],
450 base=[b"null"],
449 rev=self.head_revs,
451 rev=self.head_revs,
450 type=self.bundle_type,
452 type=self.bundle_type,
451 quiet=True,
453 quiet=True,
452 )
454 )
453
455
454 def generating(self, file_path, hostname=None, pid=None):
456 def generating(self, file_path, hostname=None, pid=None):
455 """return a GeneratingBundle object from this object"""
457 """return a GeneratingBundle object from this object"""
456 if pid is None:
458 if pid is None:
457 pid = os.getpid()
459 pid = os.getpid()
458 if hostname is None:
460 if hostname is None:
459 hostname = lock._getlockprefix()
461 hostname = lock._getlockprefix()
460 return GeneratingBundle(
462 return GeneratingBundle(
461 self.bundle_type,
463 self.bundle_type,
462 self.revs,
464 self.revs,
463 self.tip_rev,
465 self.tip_rev,
464 self.tip_node,
466 self.tip_node,
465 hostname,
467 hostname,
466 pid,
468 pid,
467 file_path,
469 file_path,
468 )
470 )
469
471
470
472
471 class GeneratingBundle(BundleBase):
473 class GeneratingBundle(BundleBase):
472 """A bundle being generated
474 """A bundle being generated
473
475
474 extra attributes compared to BundleBase:
476 extra attributes compared to BundleBase:
475
477
476 :hostname: the hostname of the machine generating the bundle
478 :hostname: the hostname of the machine generating the bundle
477 :pid: the pid of the process generating the bundle
479 :pid: the pid of the process generating the bundle
478 :filepath: the target filename of the bundle
480 :filepath: the target filename of the bundle
479
481
480 These attributes exist to help detect stalled generation processes.
482 These attributes exist to help detect stalled generation processes.
481 """
483 """
482
484
483 ready = False
485 ready = False
484
486
485 def __init__(
487 def __init__(
486 self, bundle_type, revs, tip_rev, tip_node, hostname, pid, filepath
488 self, bundle_type, revs, tip_rev, tip_node, hostname, pid, filepath
487 ):
489 ):
488 self.hostname = hostname
490 self.hostname = hostname
489 self.pid = pid
491 self.pid = pid
490 self.filepath = filepath
492 self.filepath = filepath
491 super(GeneratingBundle, self).__init__(
493 super(GeneratingBundle, self).__init__(
492 bundle_type, revs, tip_rev, tip_node
494 bundle_type, revs, tip_rev, tip_node
493 )
495 )
494
496
495 @classmethod
497 @classmethod
496 def from_line(cls, line):
498 def from_line(cls, line):
497 """create an object by deserializing a line from AUTO_GEN_FILE"""
499 """create an object by deserializing a line from AUTO_GEN_FILE"""
498 assert line.startswith(b'PENDING-v1 ')
500 assert line.startswith(b'PENDING-v1 ')
499 (
501 (
500 __,
502 __,
501 bundle_type,
503 bundle_type,
502 revs,
504 revs,
503 tip_rev,
505 tip_rev,
504 tip_node,
506 tip_node,
505 hostname,
507 hostname,
506 pid,
508 pid,
507 filepath,
509 filepath,
508 ) = line.split()
510 ) = line.split()
509 hostname = util.urlreq.unquote(hostname)
511 hostname = util.urlreq.unquote(hostname)
510 filepath = util.urlreq.unquote(filepath)
512 filepath = util.urlreq.unquote(filepath)
511 revs = int(revs)
513 revs = int(revs)
512 tip_rev = int(tip_rev)
514 tip_rev = int(tip_rev)
513 pid = int(pid)
515 pid = int(pid)
514 return cls(
516 return cls(
515 bundle_type, revs, tip_rev, tip_node, hostname, pid, filepath
517 bundle_type, revs, tip_rev, tip_node, hostname, pid, filepath
516 )
518 )
517
519
518 def to_line(self):
520 def to_line(self):
519 """serialize the object to include as a line in AUTO_GEN_FILE"""
521 """serialize the object to include as a line in AUTO_GEN_FILE"""
520 templ = b"PENDING-v1 %s %d %d %s %s %d %s"
522 templ = b"PENDING-v1 %s %d %d %s %s %d %s"
521 data = (
523 data = (
522 self.bundle_type,
524 self.bundle_type,
523 self.revs,
525 self.revs,
524 self.tip_rev,
526 self.tip_rev,
525 self.tip_node,
527 self.tip_node,
526 util.urlreq.quote(self.hostname),
528 util.urlreq.quote(self.hostname),
527 self.pid,
529 self.pid,
528 util.urlreq.quote(self.filepath),
530 util.urlreq.quote(self.filepath),
529 )
531 )
530 return templ % data
532 return templ % data
531
533
532 def __eq__(self, other):
534 def __eq__(self, other):
533 if not super(GeneratingBundle, self).__eq__(other):
535 if not super(GeneratingBundle, self).__eq__(other):
534 return False
536 return False
535 left = (self.hostname, self.pid, self.filepath)
537 left = (self.hostname, self.pid, self.filepath)
536 right = (other.hostname, other.pid, other.filepath)
538 right = (other.hostname, other.pid, other.filepath)
537 return left == right
539 return left == right
538
540
539 def uploaded(self, url, basename):
541 def uploaded(self, url, basename):
540 """return a GeneratedBundle from this object"""
542 """return a GeneratedBundle from this object"""
541 return GeneratedBundle(
543 return GeneratedBundle(
542 self.bundle_type,
544 self.bundle_type,
543 self.revs,
545 self.revs,
544 self.tip_rev,
546 self.tip_rev,
545 self.tip_node,
547 self.tip_node,
546 url,
548 url,
547 basename,
549 basename,
548 )
550 )
549
551
550
552
551 class GeneratedBundle(BundleBase):
553 class GeneratedBundle(BundleBase):
552 """A bundle that is done being generated and can be served
554 """A bundle that is done being generated and can be served
553
555
554 extra attributes compared to BundleBase:
556 extra attributes compared to BundleBase:
555
557
556 :file_url: the url where the bundle is available.
558 :file_url: the url where the bundle is available.
557 :basename: the "basename" used to upload (useful for deletion)
559 :basename: the "basename" used to upload (useful for deletion)
558
560
559 These attributes exist to generate a bundle manifest
561 These attributes exist to generate a bundle manifest
560 (.hg/pullbundles.manifest)
562 (.hg/pullbundles.manifest)
561 """
563 """
562
564
563 ready = True
565 ready = True
564
566
565 def __init__(
567 def __init__(
566 self, bundle_type, revs, tip_rev, tip_node, file_url, basename
568 self, bundle_type, revs, tip_rev, tip_node, file_url, basename
567 ):
569 ):
568 self.file_url = file_url
570 self.file_url = file_url
569 self.basename = basename
571 self.basename = basename
570 super(GeneratedBundle, self).__init__(
572 super(GeneratedBundle, self).__init__(
571 bundle_type, revs, tip_rev, tip_node
573 bundle_type, revs, tip_rev, tip_node
572 )
574 )
573
575
574 @classmethod
576 @classmethod
575 def from_line(cls, line):
577 def from_line(cls, line):
576 """create an object by deserializing a line from AUTO_GEN_FILE"""
578 """create an object by deserializing a line from AUTO_GEN_FILE"""
577 assert line.startswith(b'DONE-v1 ')
579 assert line.startswith(b'DONE-v1 ')
578 (
580 (
579 __,
581 __,
580 bundle_type,
582 bundle_type,
581 revs,
583 revs,
582 tip_rev,
584 tip_rev,
583 tip_node,
585 tip_node,
584 file_url,
586 file_url,
585 basename,
587 basename,
586 ) = line.split()
588 ) = line.split()
587 revs = int(revs)
589 revs = int(revs)
588 tip_rev = int(tip_rev)
590 tip_rev = int(tip_rev)
589 file_url = util.urlreq.unquote(file_url)
591 file_url = util.urlreq.unquote(file_url)
590 return cls(bundle_type, revs, tip_rev, tip_node, file_url, basename)
592 return cls(bundle_type, revs, tip_rev, tip_node, file_url, basename)
591
593
592 def to_line(self):
594 def to_line(self):
593 """serialize the object to include as a line in AUTO_GEN_FILE"""
595 """serialize the object to include as a line in AUTO_GEN_FILE"""
594 templ = b"DONE-v1 %s %d %d %s %s %s"
596 templ = b"DONE-v1 %s %d %d %s %s %s"
595 data = (
597 data = (
596 self.bundle_type,
598 self.bundle_type,
597 self.revs,
599 self.revs,
598 self.tip_rev,
600 self.tip_rev,
599 self.tip_node,
601 self.tip_node,
600 util.urlreq.quote(self.file_url),
602 util.urlreq.quote(self.file_url),
601 self.basename,
603 self.basename,
602 )
604 )
603 return templ % data
605 return templ % data
604
606
605 def manifest_line(self):
607 def manifest_line(self):
606 """serialize the object to include as a line in pullbundles.manifest"""
608 """serialize the object to include as a line in pullbundles.manifest"""
607 templ = b"%s BUNDLESPEC=%s REQUIRESNI=true"
609 templ = b"%s BUNDLESPEC=%s REQUIRESNI=true"
608 return templ % (self.file_url, self.bundle_type)
610 return templ % (self.file_url, self.bundle_type)
609
611
610 def __eq__(self, other):
612 def __eq__(self, other):
611 if not super(GeneratedBundle, self).__eq__(other):
613 if not super(GeneratedBundle, self).__eq__(other):
612 return False
614 return False
613 return self.file_url == other.file_url
615 return self.file_url == other.file_url
614
616
615
617
616 def parse_auto_gen(content):
618 def parse_auto_gen(content):
617 """parse the AUTO_GEN_FILE to return a list of Bundle object"""
619 """parse the AUTO_GEN_FILE to return a list of Bundle object"""
618 bundles = []
620 bundles = []
619 for line in content.splitlines():
621 for line in content.splitlines():
620 if line.startswith(b'PENDING-v1 '):
622 if line.startswith(b'PENDING-v1 '):
621 bundles.append(GeneratingBundle.from_line(line))
623 bundles.append(GeneratingBundle.from_line(line))
622 elif line.startswith(b'DONE-v1 '):
624 elif line.startswith(b'DONE-v1 '):
623 bundles.append(GeneratedBundle.from_line(line))
625 bundles.append(GeneratedBundle.from_line(line))
624 return bundles
626 return bundles
625
627
626
628
627 def dumps_auto_gen(bundles):
629 def dumps_auto_gen(bundles):
628 """serialize a list of Bundle as a AUTO_GEN_FILE content"""
630 """serialize a list of Bundle as a AUTO_GEN_FILE content"""
629 lines = []
631 lines = []
630 for b in bundles:
632 for b in bundles:
631 lines.append(b"%s\n" % b.to_line())
633 lines.append(b"%s\n" % b.to_line())
632 lines.sort()
634 lines.sort()
633 return b"".join(lines)
635 return b"".join(lines)
634
636
635
637
636 def read_auto_gen(repo):
638 def read_auto_gen(repo):
637 """read the AUTO_GEN_FILE for the <repo> a list of Bundle object"""
639 """read the AUTO_GEN_FILE for the <repo> a list of Bundle object"""
638 data = repo.vfs.tryread(AUTO_GEN_FILE)
640 data = repo.vfs.tryread(AUTO_GEN_FILE)
639 if not data:
641 if not data:
640 return []
642 return []
641 return parse_auto_gen(data)
643 return parse_auto_gen(data)
642
644
643
645
644 def write_auto_gen(repo, bundles):
646 def write_auto_gen(repo, bundles):
645 """write a list of Bundle objects into the repo's AUTO_GEN_FILE"""
647 """write a list of Bundle objects into the repo's AUTO_GEN_FILE"""
646 assert repo._cb_lock_ref is not None
648 assert repo._cb_lock_ref is not None
647 data = dumps_auto_gen(bundles)
649 data = dumps_auto_gen(bundles)
648 with repo.vfs(AUTO_GEN_FILE, mode=b'wb', atomictemp=True) as f:
650 with repo.vfs(AUTO_GEN_FILE, mode=b'wb', atomictemp=True) as f:
649 f.write(data)
651 f.write(data)
650
652
651
653
652 def generate_manifest(bundles):
654 def generate_manifest(bundles):
653 """write a list of Bundle objects into the repo's AUTO_GEN_FILE"""
655 """write a list of Bundle objects into the repo's AUTO_GEN_FILE"""
654 bundles = list(bundles)
656 bundles = list(bundles)
655 bundles.sort(key=lambda b: b.bundle_type)
657 bundles.sort(key=lambda b: b.bundle_type)
656 lines = []
658 lines = []
657 for b in bundles:
659 for b in bundles:
658 lines.append(b"%s\n" % b.manifest_line())
660 lines.append(b"%s\n" % b.manifest_line())
659 return b"".join(lines)
661 return b"".join(lines)
660
662
661
663
662 def update_ondisk_manifest(repo):
664 def update_ondisk_manifest(repo):
663 """update the clonebundle manifest with latest url"""
665 """update the clonebundle manifest with latest url"""
664 with repo.clonebundles_lock():
666 with repo.clonebundles_lock():
665 bundles = read_auto_gen(repo)
667 bundles = read_auto_gen(repo)
666
668
667 per_types = {}
669 per_types = {}
668 for b in bundles:
670 for b in bundles:
669 if not (b.ready and b.valid_for(repo)):
671 if not (b.ready and b.valid_for(repo)):
670 continue
672 continue
671 current = per_types.get(b.bundle_type)
673 current = per_types.get(b.bundle_type)
672 if current is not None and current.revs >= b.revs:
674 if current is not None and current.revs >= b.revs:
673 continue
675 continue
674 per_types[b.bundle_type] = b
676 per_types[b.bundle_type] = b
675 manifest = generate_manifest(per_types.values())
677 manifest = generate_manifest(per_types.values())
676 with repo.vfs(
678 with repo.vfs(
677 bundlecaches.CB_MANIFEST_FILE, mode=b"wb", atomictemp=True
679 bundlecaches.CB_MANIFEST_FILE, mode=b"wb", atomictemp=True
678 ) as f:
680 ) as f:
679 f.write(manifest)
681 f.write(manifest)
680
682
681
683
682 def update_bundle_list(repo, new_bundles=(), del_bundles=()):
684 def update_bundle_list(repo, new_bundles=(), del_bundles=()):
683 """modify the repo's AUTO_GEN_FILE
685 """modify the repo's AUTO_GEN_FILE
684
686
685 This method also regenerates the clone bundle manifest when needed"""
687 This method also regenerates the clone bundle manifest when needed"""
686 with repo.clonebundles_lock():
688 with repo.clonebundles_lock():
687 bundles = read_auto_gen(repo)
689 bundles = read_auto_gen(repo)
688 if del_bundles:
690 if del_bundles:
689 bundles = [b for b in bundles if b not in del_bundles]
691 bundles = [b for b in bundles if b not in del_bundles]
690 new_bundles = [b for b in new_bundles if b not in bundles]
692 new_bundles = [b for b in new_bundles if b not in bundles]
691 bundles.extend(new_bundles)
693 bundles.extend(new_bundles)
692 write_auto_gen(repo, bundles)
694 write_auto_gen(repo, bundles)
693 all_changed = []
695 all_changed = []
694 all_changed.extend(new_bundles)
696 all_changed.extend(new_bundles)
695 all_changed.extend(del_bundles)
697 all_changed.extend(del_bundles)
696 if any(b.ready for b in all_changed):
698 if any(b.ready for b in all_changed):
697 update_ondisk_manifest(repo)
699 update_ondisk_manifest(repo)
698
700
699
701
700 def cleanup_tmp_bundle(repo, target):
702 def cleanup_tmp_bundle(repo, target):
701 """remove a GeneratingBundle file and entry"""
703 """remove a GeneratingBundle file and entry"""
702 assert not target.ready
704 assert not target.ready
703 with repo.clonebundles_lock():
705 with repo.clonebundles_lock():
704 repo.vfs.tryunlink(target.filepath)
706 repo.vfs.tryunlink(target.filepath)
705 update_bundle_list(repo, del_bundles=[target])
707 update_bundle_list(repo, del_bundles=[target])
706
708
707
709
708 def finalize_one_bundle(repo, target):
710 def finalize_one_bundle(repo, target):
709 """upload a generated bundle and advertise it in the clonebundles.manifest"""
711 """upload a generated bundle and advertise it in the clonebundles.manifest"""
710 with repo.clonebundles_lock():
712 with repo.clonebundles_lock():
711 bundles = read_auto_gen(repo)
713 bundles = read_auto_gen(repo)
712 if target in bundles and target.valid_for(repo):
714 if target in bundles and target.valid_for(repo):
713 result = upload_bundle(repo, target)
715 result = upload_bundle(repo, target)
714 update_bundle_list(repo, new_bundles=[result])
716 update_bundle_list(repo, new_bundles=[result])
715 cleanup_tmp_bundle(repo, target)
717 cleanup_tmp_bundle(repo, target)
716
718
717
719
718 def find_outdated_bundles(repo, bundles):
720 def find_outdated_bundles(repo, bundles):
719 """finds outdated bundles"""
721 """finds outdated bundles"""
720 olds = []
722 olds = []
721 per_types = {}
723 per_types = {}
722 for b in bundles:
724 for b in bundles:
723 if not b.valid_for(repo):
725 if not b.valid_for(repo):
724 olds.append(b)
726 olds.append(b)
725 continue
727 continue
726 l = per_types.setdefault(b.bundle_type, [])
728 l = per_types.setdefault(b.bundle_type, [])
727 l.append(b)
729 l.append(b)
728 for key in sorted(per_types):
730 for key in sorted(per_types):
729 all = per_types[key]
731 all = per_types[key]
730 if len(all) > 1:
732 if len(all) > 1:
731 all.sort(key=lambda b: b.revs, reverse=True)
733 all.sort(key=lambda b: b.revs, reverse=True)
732 olds.extend(all[1:])
734 olds.extend(all[1:])
733 return olds
735 return olds
734
736
735
737
736 def collect_garbage(repo):
738 def collect_garbage(repo):
737 """finds outdated bundles and get them deleted"""
739 """finds outdated bundles and get them deleted"""
738 with repo.clonebundles_lock():
740 with repo.clonebundles_lock():
739 bundles = read_auto_gen(repo)
741 bundles = read_auto_gen(repo)
740 olds = find_outdated_bundles(repo, bundles)
742 olds = find_outdated_bundles(repo, bundles)
741 for o in olds:
743 for o in olds:
742 delete_bundle(repo, o)
744 delete_bundle(repo, o)
743 update_bundle_list(repo, del_bundles=olds)
745 update_bundle_list(repo, del_bundles=olds)
744
746
745
747
746 def upload_bundle(repo, bundle):
748 def upload_bundle(repo, bundle):
747 """upload the result of a GeneratingBundle and return a GeneratedBundle
749 """upload the result of a GeneratingBundle and return a GeneratedBundle
748
750
749 The upload is done using the `clone-bundles.upload-command`
751 The upload is done using the `clone-bundles.upload-command`
750 """
752 """
751 cmd = repo.ui.config(b'clone-bundles', b'upload-command')
753 cmd = repo.ui.config(b'clone-bundles', b'upload-command')
752 url = repo.ui.config(b'clone-bundles', b'url-template')
754 url = repo.ui.config(b'clone-bundles', b'url-template')
753 basename = repo.vfs.basename(bundle.filepath)
755 basename = repo.vfs.basename(bundle.filepath)
754 filepath = procutil.shellquote(bundle.filepath)
756 filepath = procutil.shellquote(bundle.filepath)
755 variables = {
757 variables = {
756 b'HGCB_BUNDLE_PATH': filepath,
758 b'HGCB_BUNDLE_PATH': filepath,
757 b'HGCB_BUNDLE_BASENAME': basename,
759 b'HGCB_BUNDLE_BASENAME': basename,
758 }
760 }
759 env = procutil.shellenviron(environ=variables)
761 env = procutil.shellenviron(environ=variables)
760 ret = repo.ui.system(cmd, environ=env)
762 ret = repo.ui.system(cmd, environ=env)
761 if ret:
763 if ret:
762 raise error.Abort(b"command returned status %d: %s" % (ret, cmd))
764 raise error.Abort(b"command returned status %d: %s" % (ret, cmd))
763 url = (
765 url = (
764 url.decode('utf8')
766 url.decode('utf8')
765 .format(basename=basename.decode('utf8'))
767 .format(basename=basename.decode('utf8'))
766 .encode('utf8')
768 .encode('utf8')
767 )
769 )
768 return bundle.uploaded(url, basename)
770 return bundle.uploaded(url, basename)
769
771
770
772
771 def delete_bundle(repo, bundle):
773 def delete_bundle(repo, bundle):
772 """delete a bundle from storage"""
774 """delete a bundle from storage"""
773 assert bundle.ready
775 assert bundle.ready
774 msg = b'clone-bundles: deleting bundle %s\n'
776 msg = b'clone-bundles: deleting bundle %s\n'
775 msg %= bundle.basename
777 msg %= bundle.basename
776 if repo.ui.configbool(b'devel', b'debug.clonebundles'):
778 if repo.ui.configbool(b'devel', b'debug.clonebundles'):
777 repo.ui.write(msg)
779 repo.ui.write(msg)
778 else:
780 else:
779 repo.ui.debug(msg)
781 repo.ui.debug(msg)
780
782
781 cmd = repo.ui.config(b'clone-bundles', b'delete-command')
783 cmd = repo.ui.config(b'clone-bundles', b'delete-command')
782 variables = {
784 variables = {
783 b'HGCB_BUNDLE_URL': bundle.file_url,
785 b'HGCB_BUNDLE_URL': bundle.file_url,
784 b'HGCB_BASENAME': bundle.basename,
786 b'HGCB_BASENAME': bundle.basename,
785 }
787 }
786 env = procutil.shellenviron(environ=variables)
788 env = procutil.shellenviron(environ=variables)
787 ret = repo.ui.system(cmd, environ=env)
789 ret = repo.ui.system(cmd, environ=env)
788 if ret:
790 if ret:
789 raise error.Abort(b"command returned status %d: %s" % (ret, cmd))
791 raise error.Abort(b"command returned status %d: %s" % (ret, cmd))
790
792
791
793
792 def auto_bundle_needed_actions(repo, bundles, op_id):
794 def auto_bundle_needed_actions(repo, bundles, op_id):
793 """find the list of bundles that need action
795 """find the list of bundles that need action
794
796
795 returns a list of RequestedBundle objects that need to be generated and
797 returns a list of RequestedBundle objects that need to be generated and
796 uploaded."""
798 uploaded."""
797 create_bundles = []
799 create_bundles = []
798 delete_bundles = []
800 delete_bundles = []
799 repo = repo.filtered(b"immutable")
801 repo = repo.filtered(b"immutable")
800 targets = repo.ui.configlist(b'clone-bundles', b'auto-generate.formats')
802 targets = repo.ui.configlist(b'clone-bundles', b'auto-generate.formats')
801 ratio = float(
803 ratio = float(
802 repo.ui.config(b'clone-bundles', b'trigger.below-bundled-ratio')
804 repo.ui.config(b'clone-bundles', b'trigger.below-bundled-ratio')
803 )
805 )
804 abs_revs = repo.ui.configint(b'clone-bundles', b'trigger.revs')
806 abs_revs = repo.ui.configint(b'clone-bundles', b'trigger.revs')
805 revs = len(repo.changelog)
807 revs = len(repo.changelog)
806 generic_data = {
808 generic_data = {
807 'revs': revs,
809 'revs': revs,
808 'head_revs': repo.changelog.headrevs(),
810 'head_revs': repo.changelog.headrevs(),
809 'tip_rev': repo.changelog.tiprev(),
811 'tip_rev': repo.changelog.tiprev(),
810 'tip_node': node.hex(repo.changelog.tip()),
812 'tip_node': node.hex(repo.changelog.tip()),
811 'op_id': op_id,
813 'op_id': op_id,
812 }
814 }
813 for t in targets:
815 for t in targets:
814 if new_bundle_needed(repo, bundles, ratio, abs_revs, t, revs):
816 if new_bundle_needed(repo, bundles, ratio, abs_revs, t, revs):
815 data = generic_data.copy()
817 data = generic_data.copy()
816 data['bundle_type'] = t
818 data['bundle_type'] = t
817 b = RequestedBundle(**data)
819 b = RequestedBundle(**data)
818 create_bundles.append(b)
820 create_bundles.append(b)
819 delete_bundles.extend(find_outdated_bundles(repo, bundles))
821 delete_bundles.extend(find_outdated_bundles(repo, bundles))
820 return create_bundles, delete_bundles
822 return create_bundles, delete_bundles
821
823
822
824
823 def new_bundle_needed(repo, bundles, ratio, abs_revs, bundle_type, revs):
825 def new_bundle_needed(repo, bundles, ratio, abs_revs, bundle_type, revs):
824 """consider the current cached content and trigger new bundles if needed"""
826 """consider the current cached content and trigger new bundles if needed"""
825 threshold = max((revs * ratio), (revs - abs_revs))
827 threshold = max((revs * ratio), (revs - abs_revs))
826 for b in bundles:
828 for b in bundles:
827 if not b.valid_for(repo) or b.bundle_type != bundle_type:
829 if not b.valid_for(repo) or b.bundle_type != bundle_type:
828 continue
830 continue
829 if b.revs > threshold:
831 if b.revs > threshold:
830 return False
832 return False
831 return True
833 return True
832
834
833
835
834 def start_one_bundle(repo, bundle):
836 def start_one_bundle(repo, bundle):
835 """start the generation of a single bundle file
837 """start the generation of a single bundle file
836
838
837 the `bundle` argument should be a RequestedBundle object.
839 the `bundle` argument should be a RequestedBundle object.
838
840
839 This data is passed to the `debugmakeclonebundles` "as is".
841 This data is passed to the `debugmakeclonebundles` "as is".
840 """
842 """
841 data = util.pickle.dumps(bundle)
843 data = util.pickle.dumps(bundle)
842 cmd = [procutil.hgexecutable(), b'--cwd', repo.path, INTERNAL_CMD]
844 cmd = [procutil.hgexecutable(), b'--cwd', repo.path, INTERNAL_CMD]
843 env = procutil.shellenviron()
845 env = procutil.shellenviron()
844 msg = b'clone-bundles: starting bundle generation: %s\n'
846 msg = b'clone-bundles: starting bundle generation: %s\n'
845 stdout = None
847 stdout = None
846 stderr = None
848 stderr = None
847 waits = []
849 waits = []
848 record_wait = None
850 record_wait = None
849 if repo.ui.configbool(b'devel', b'debug.clonebundles'):
851 if repo.ui.configbool(b'devel', b'debug.clonebundles'):
850 stdout = procutil.stdout
852 stdout = procutil.stdout
851 stderr = procutil.stderr
853 stderr = procutil.stderr
852 repo.ui.write(msg % bundle.bundle_type)
854 repo.ui.write(msg % bundle.bundle_type)
853 record_wait = waits.append
855 record_wait = waits.append
854 else:
856 else:
855 repo.ui.debug(msg % bundle.bundle_type)
857 repo.ui.debug(msg % bundle.bundle_type)
856 bg = procutil.runbgcommand
858 bg = procutil.runbgcommand
857 bg(
859 bg(
858 cmd,
860 cmd,
859 env,
861 env,
860 stdin_bytes=data,
862 stdin_bytes=data,
861 stdout=stdout,
863 stdout=stdout,
862 stderr=stderr,
864 stderr=stderr,
863 record_wait=record_wait,
865 record_wait=record_wait,
864 )
866 )
865 for f in waits:
867 for f in waits:
866 f()
868 f()
867
869
868
870
869 INTERNAL_CMD = b'debug::internal-make-clone-bundles'
871 INTERNAL_CMD = b'debug::internal-make-clone-bundles'
870
872
871
873
872 @command(INTERNAL_CMD, [], b'')
874 @command(INTERNAL_CMD, [], b'')
873 def debugmakeclonebundles(ui, repo):
875 def debugmakeclonebundles(ui, repo):
874 """Internal command to auto-generate debug bundles"""
876 """Internal command to auto-generate debug bundles"""
875 requested_bundle = util.pickle.load(procutil.stdin)
877 requested_bundle = util.pickle.load(procutil.stdin)
876 procutil.stdin.close()
878 procutil.stdin.close()
877
879
878 collect_garbage(repo)
880 collect_garbage(repo)
879
881
880 fname = requested_bundle.suggested_filename
882 fname = requested_bundle.suggested_filename
881 fpath = repo.vfs.makedirs(b'tmp-bundles')
883 fpath = repo.vfs.makedirs(b'tmp-bundles')
882 fpath = repo.vfs.join(b'tmp-bundles', fname)
884 fpath = repo.vfs.join(b'tmp-bundles', fname)
883 bundle = requested_bundle.generating(fpath)
885 bundle = requested_bundle.generating(fpath)
884 update_bundle_list(repo, new_bundles=[bundle])
886 update_bundle_list(repo, new_bundles=[bundle])
885
887
886 requested_bundle.generate_bundle(repo, fpath)
888 requested_bundle.generate_bundle(repo, fpath)
887
889
888 repo.invalidate()
890 repo.invalidate()
889 finalize_one_bundle(repo, bundle)
891 finalize_one_bundle(repo, bundle)
890
892
891
893
892 def make_auto_bundler(source_repo):
894 def make_auto_bundler(source_repo):
893 reporef = weakref.ref(source_repo)
895 reporef = weakref.ref(source_repo)
894
896
895 def autobundle(tr):
897 def autobundle(tr):
896 repo = reporef()
898 repo = reporef()
897 assert repo is not None
899 assert repo is not None
898 bundles = read_auto_gen(repo)
900 bundles = read_auto_gen(repo)
899 new, __ = auto_bundle_needed_actions(repo, bundles, b"%d_txn" % id(tr))
901 new, __ = auto_bundle_needed_actions(repo, bundles, b"%d_txn" % id(tr))
900 for data in new:
902 for data in new:
901 start_one_bundle(repo, data)
903 start_one_bundle(repo, data)
902 return None
904 return None
903
905
904 return autobundle
906 return autobundle
905
907
906
908
907 def reposetup(ui, repo):
909 def reposetup(ui, repo):
908 """install the two pieces needed for automatic clonebundle generation
910 """install the two pieces needed for automatic clonebundle generation
909
911
910 - add a "post-close" hook that fires bundling when needed
912 - add a "post-close" hook that fires bundling when needed
911 - introduce a clone-bundle lock to let multiple processes meddle with the
913 - introduce a clone-bundle lock to let multiple processes meddle with the
912 state files.
914 state files.
913 """
915 """
914 if not repo.local():
916 if not repo.local():
915 return
917 return
916
918
917 class autobundlesrepo(repo.__class__):
919 class autobundlesrepo(repo.__class__):
918 def transaction(self, *args, **kwargs):
920 def transaction(self, *args, **kwargs):
919 tr = super(autobundlesrepo, self).transaction(*args, **kwargs)
921 tr = super(autobundlesrepo, self).transaction(*args, **kwargs)
920 enabled = repo.ui.configbool(
922 enabled = repo.ui.configbool(
921 b'clone-bundles',
923 b'clone-bundles',
922 b'auto-generate.on-change',
924 b'auto-generate.on-change',
923 )
925 )
924 targets = repo.ui.configlist(
926 targets = repo.ui.configlist(
925 b'clone-bundles', b'auto-generate.formats'
927 b'clone-bundles', b'auto-generate.formats'
926 )
928 )
927 if enabled and targets:
929 if enabled and targets:
928 tr.addpostclose(CAT_POSTCLOSE, make_auto_bundler(self))
930 tr.addpostclose(CAT_POSTCLOSE, make_auto_bundler(self))
929 return tr
931 return tr
930
932
931 @localrepo.unfilteredmethod
933 @localrepo.unfilteredmethod
932 def clonebundles_lock(self, wait=True):
934 def clonebundles_lock(self, wait=True):
933 '''Lock the repository file related to clone bundles'''
935 '''Lock the repository file related to clone bundles'''
934 if not util.safehasattr(self, '_cb_lock_ref'):
936 if not util.safehasattr(self, '_cb_lock_ref'):
935 self._cb_lock_ref = None
937 self._cb_lock_ref = None
936 l = self._currentlock(self._cb_lock_ref)
938 l = self._currentlock(self._cb_lock_ref)
937 if l is not None:
939 if l is not None:
938 l.lock()
940 l.lock()
939 return l
941 return l
940
942
941 l = self._lock(
943 l = self._lock(
942 vfs=self.vfs,
944 vfs=self.vfs,
943 lockname=b"clonebundleslock",
945 lockname=b"clonebundleslock",
944 wait=wait,
946 wait=wait,
945 releasefn=None,
947 releasefn=None,
946 acquirefn=None,
948 acquirefn=None,
947 desc=_(b'repository %s') % self.origroot,
949 desc=_(b'repository %s') % self.origroot,
948 )
950 )
949 self._cb_lock_ref = weakref.ref(l)
951 self._cb_lock_ref = weakref.ref(l)
950 return l
952 return l
951
953
952 repo._wlockfreeprefix.add(AUTO_GEN_FILE)
954 repo._wlockfreeprefix.add(AUTO_GEN_FILE)
953 repo._wlockfreeprefix.add(bundlecaches.CB_MANIFEST_FILE)
955 repo._wlockfreeprefix.add(bundlecaches.CB_MANIFEST_FILE)
954 repo.__class__ = autobundlesrepo
956 repo.__class__ = autobundlesrepo
955
957
956
958
957 @command(
959 @command(
958 b'admin::clone-bundles-refresh',
960 b'admin::clone-bundles-refresh',
959 [
961 [
960 (
962 (
961 b'',
963 b'',
962 b'background',
964 b'background',
963 False,
965 False,
964 _(b'start bundle generation in the background'),
966 _(b'start bundle generation in the background'),
965 ),
967 ),
966 ],
968 ],
967 b'',
969 b'',
968 )
970 )
969 def cmd_admin_clone_bundles_refresh(
971 def cmd_admin_clone_bundles_refresh(
970 ui,
972 ui,
971 repo: localrepo.localrepository,
973 repo: localrepo.localrepository,
972 background=False,
974 background=False,
973 ):
975 ):
974 """generate clone bundles according to the configuration
976 """generate clone bundles according to the configuration
975
977
976 This runs the logic for automatic generation, removing outdated bundles and
978 This runs the logic for automatic generation, removing outdated bundles and
977 generating new ones if necessary. See :hg:`help -e clone-bundles` for
979 generating new ones if necessary. See :hg:`help -e clone-bundles` for
978 details about how to configure this feature.
980 details about how to configure this feature.
979 """
981 """
980 debug = repo.ui.configbool(b'devel', b'debug.clonebundles')
982 debug = repo.ui.configbool(b'devel', b'debug.clonebundles')
981 bundles = read_auto_gen(repo)
983 bundles = read_auto_gen(repo)
982 op_id = b"%d_acbr" % os.getpid()
984 op_id = b"%d_acbr" % os.getpid()
983 create, delete = auto_bundle_needed_actions(repo, bundles, op_id)
985 create, delete = auto_bundle_needed_actions(repo, bundles, op_id)
984
986
985 # if some bundles are scheduled for creation in the background, they will
987 # if some bundles are scheduled for creation in the background, they will
986 # deal with garbage collection too, so no need to synchroniously do it.
988 # deal with garbage collection too, so no need to synchroniously do it.
987 #
989 #
988 # However if no bundles are scheduled for creation, we need to explicitly do
990 # However if no bundles are scheduled for creation, we need to explicitly do
989 # it here.
991 # it here.
990 if not (background and create):
992 if not (background and create):
991 # we clean up outdated bundles before generating new ones to keep the
993 # we clean up outdated bundles before generating new ones to keep the
992 # last two versions of the bundle around for a while and avoid having to
994 # last two versions of the bundle around for a while and avoid having to
993 # deal with clients that just got served a manifest.
995 # deal with clients that just got served a manifest.
994 for o in delete:
996 for o in delete:
995 delete_bundle(repo, o)
997 delete_bundle(repo, o)
996 update_bundle_list(repo, del_bundles=delete)
998 update_bundle_list(repo, del_bundles=delete)
997
999
998 if create:
1000 if create:
999 fpath = repo.vfs.makedirs(b'tmp-bundles')
1001 fpath = repo.vfs.makedirs(b'tmp-bundles')
1000
1002
1001 if background:
1003 if background:
1002 for requested_bundle in create:
1004 for requested_bundle in create:
1003 start_one_bundle(repo, requested_bundle)
1005 start_one_bundle(repo, requested_bundle)
1004 else:
1006 else:
1005 for requested_bundle in create:
1007 for requested_bundle in create:
1006 if debug:
1008 if debug:
1007 msg = b'clone-bundles: starting bundle generation: %s\n'
1009 msg = b'clone-bundles: starting bundle generation: %s\n'
1008 repo.ui.write(msg % requested_bundle.bundle_type)
1010 repo.ui.write(msg % requested_bundle.bundle_type)
1009 fname = requested_bundle.suggested_filename
1011 fname = requested_bundle.suggested_filename
1010 fpath = repo.vfs.join(b'tmp-bundles', fname)
1012 fpath = repo.vfs.join(b'tmp-bundles', fname)
1011 generating_bundle = requested_bundle.generating(fpath)
1013 generating_bundle = requested_bundle.generating(fpath)
1012 update_bundle_list(repo, new_bundles=[generating_bundle])
1014 update_bundle_list(repo, new_bundles=[generating_bundle])
1013 requested_bundle.generate_bundle(repo, fpath)
1015 requested_bundle.generate_bundle(repo, fpath)
1014 result = upload_bundle(repo, generating_bundle)
1016 result = upload_bundle(repo, generating_bundle)
1015 update_bundle_list(repo, new_bundles=[result])
1017 update_bundle_list(repo, new_bundles=[result])
1016 update_ondisk_manifest(repo)
1018 update_ondisk_manifest(repo)
1017 cleanup_tmp_bundle(repo, generating_bundle)
1019 cleanup_tmp_bundle(repo, generating_bundle)
1018
1020
1019
1021
1020 @command(b'admin::clone-bundles-clear', [], b'')
1022 @command(b'admin::clone-bundles-clear', [], b'')
1021 def cmd_admin_clone_bundles_clear(ui, repo: localrepo.localrepository):
1023 def cmd_admin_clone_bundles_clear(ui, repo: localrepo.localrepository):
1022 """remove existing clone bundle caches
1024 """remove existing clone bundle caches
1023
1025
1024 See `hg help admin::clone-bundles-refresh` for details on how to regenerate
1026 See `hg help admin::clone-bundles-refresh` for details on how to regenerate
1025 them.
1027 them.
1026
1028
1027 This command will only affect bundles currently available, it will not
1029 This command will only affect bundles currently available, it will not
1028 affect bundles being asynchronously generated.
1030 affect bundles being asynchronously generated.
1029 """
1031 """
1030 bundles = read_auto_gen(repo)
1032 bundles = read_auto_gen(repo)
1031 delete = [b for b in bundles if b.ready]
1033 delete = [b for b in bundles if b.ready]
1032 for o in delete:
1034 for o in delete:
1033 delete_bundle(repo, o)
1035 delete_bundle(repo, o)
1034 update_bundle_list(repo, del_bundles=delete)
1036 update_bundle_list(repo, del_bundles=delete)
@@ -1,540 +1,556 b''
1 # bundlecaches.py - utility to deal with pre-computed bundle for servers
1 # bundlecaches.py - utility to deal with pre-computed bundle for servers
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 import collections
6 import collections
7
7
8 from typing import (
8 from typing import (
9 cast,
9 cast,
10 )
10 )
11
11
12 from .i18n import _
12 from .i18n import _
13
13
14 from .thirdparty import attr
14 from .thirdparty import attr
15
15
16 from . import (
16 from . import (
17 error,
17 error,
18 requirements as requirementsmod,
18 requirements as requirementsmod,
19 sslutil,
19 sslutil,
20 util,
20 util,
21 )
21 )
22 from .utils import stringutil
22 from .utils import stringutil
23
23
24 urlreq = util.urlreq
24 urlreq = util.urlreq
25
25
26 BUNDLE_CACHE_DIR = b'bundle-cache'
26 BUNDLE_CACHE_DIR = b'bundle-cache'
27 CB_MANIFEST_FILE = b'clonebundles.manifest'
27 CB_MANIFEST_FILE = b'clonebundles.manifest'
28 CLONEBUNDLESCHEME = b"peer-bundle-cache://"
28 CLONEBUNDLESCHEME = b"peer-bundle-cache://"
29
29
30
30
31 def get_manifest(repo):
31 def get_manifest(repo):
32 """get the bundle manifest to be served to a client from a server"""
32 """get the bundle manifest to be served to a client from a server"""
33 raw_text = repo.vfs.tryread(CB_MANIFEST_FILE)
33 raw_text = repo.vfs.tryread(CB_MANIFEST_FILE)
34 entries = [e.split(b' ', 1) for e in raw_text.splitlines()]
34 entries = [e.split(b' ', 1) for e in raw_text.splitlines()]
35
35
36 new_lines = []
36 new_lines = []
37 for e in entries:
37 for e in entries:
38 url = alter_bundle_url(repo, e[0])
38 url = alter_bundle_url(repo, e[0])
39 if len(e) == 1:
39 if len(e) == 1:
40 line = url + b'\n'
40 line = url + b'\n'
41 else:
41 else:
42 line = b"%s %s\n" % (url, e[1])
42 line = b"%s %s\n" % (url, e[1])
43 new_lines.append(line)
43 new_lines.append(line)
44 return b''.join(new_lines)
44 return b''.join(new_lines)
45
45
46
46
47 def alter_bundle_url(repo, url):
47 def alter_bundle_url(repo, url):
48 """a function that exist to help extension and hosting to alter the url
48 """a function that exist to help extension and hosting to alter the url
49
49
50 This will typically be used to inject authentication information in the url
50 This will typically be used to inject authentication information in the url
51 of cached bundles."""
51 of cached bundles."""
52 return url
52 return url
53
53
54
54
55 SUPPORTED_CLONEBUNDLE_SCHEMES = [
56 b"http://",
57 b"https://",
58 b"largefile://",
59 CLONEBUNDLESCHEME,
60 ]
61
62
55 @attr.s
63 @attr.s
56 class bundlespec:
64 class bundlespec:
57 compression = attr.ib()
65 compression = attr.ib()
58 wirecompression = attr.ib()
66 wirecompression = attr.ib()
59 version = attr.ib()
67 version = attr.ib()
60 wireversion = attr.ib()
68 wireversion = attr.ib()
61 # parameters explicitly overwritten by the config or the specification
69 # parameters explicitly overwritten by the config or the specification
62 _explicit_params = attr.ib()
70 _explicit_params = attr.ib()
63 # default parameter for the version
71 # default parameter for the version
64 #
72 #
65 # Keeping it separated is useful to check what was actually overwritten.
73 # Keeping it separated is useful to check what was actually overwritten.
66 _default_opts = attr.ib()
74 _default_opts = attr.ib()
67
75
68 @property
76 @property
69 def params(self):
77 def params(self):
70 return collections.ChainMap(self._explicit_params, self._default_opts)
78 return collections.ChainMap(self._explicit_params, self._default_opts)
71
79
72 @property
80 @property
73 def contentopts(self):
81 def contentopts(self):
74 # kept for Backward Compatibility concerns.
82 # kept for Backward Compatibility concerns.
75 return self.params
83 return self.params
76
84
77 def set_param(self, key, value, overwrite=True):
85 def set_param(self, key, value, overwrite=True):
78 """Set a bundle parameter value.
86 """Set a bundle parameter value.
79
87
80 Will only overwrite if overwrite is true"""
88 Will only overwrite if overwrite is true"""
81 if overwrite or key not in self._explicit_params:
89 if overwrite or key not in self._explicit_params:
82 self._explicit_params[key] = value
90 self._explicit_params[key] = value
83
91
84
92
85 # Maps bundle version human names to changegroup versions.
93 # Maps bundle version human names to changegroup versions.
86 _bundlespeccgversions = {
94 _bundlespeccgversions = {
87 b'v1': b'01',
95 b'v1': b'01',
88 b'v2': b'02',
96 b'v2': b'02',
89 b'v3': b'03',
97 b'v3': b'03',
90 b'packed1': b's1',
98 b'packed1': b's1',
91 b'bundle2': b'02', # legacy
99 b'bundle2': b'02', # legacy
92 }
100 }
93
101
94 # Maps bundle version with content opts to choose which part to bundle
102 # Maps bundle version with content opts to choose which part to bundle
95 _bundlespeccontentopts = {
103 _bundlespeccontentopts = {
96 b'v1': {
104 b'v1': {
97 b'changegroup': True,
105 b'changegroup': True,
98 b'cg.version': b'01',
106 b'cg.version': b'01',
99 b'obsolescence': False,
107 b'obsolescence': False,
100 b'phases': False,
108 b'phases': False,
101 b'tagsfnodescache': False,
109 b'tagsfnodescache': False,
102 b'revbranchcache': False,
110 b'revbranchcache': False,
103 },
111 },
104 b'v2': {
112 b'v2': {
105 b'changegroup': True,
113 b'changegroup': True,
106 b'cg.version': b'02',
114 b'cg.version': b'02',
107 b'obsolescence': False,
115 b'obsolescence': False,
108 b'phases': False,
116 b'phases': False,
109 b'tagsfnodescache': True,
117 b'tagsfnodescache': True,
110 b'revbranchcache': True,
118 b'revbranchcache': True,
111 },
119 },
112 b'v3': {
120 b'v3': {
113 b'changegroup': True,
121 b'changegroup': True,
114 b'cg.version': b'03',
122 b'cg.version': b'03',
115 b'obsolescence': False,
123 b'obsolescence': False,
116 b'phases': True,
124 b'phases': True,
117 b'tagsfnodescache': True,
125 b'tagsfnodescache': True,
118 b'revbranchcache': True,
126 b'revbranchcache': True,
119 },
127 },
120 b'streamv2': {
128 b'streamv2': {
121 b'changegroup': False,
129 b'changegroup': False,
122 b'cg.version': b'02',
130 b'cg.version': b'02',
123 b'obsolescence': False,
131 b'obsolescence': False,
124 b'phases': False,
132 b'phases': False,
125 b"streamv2": True,
133 b"streamv2": True,
126 b'tagsfnodescache': False,
134 b'tagsfnodescache': False,
127 b'revbranchcache': False,
135 b'revbranchcache': False,
128 },
136 },
129 b'streamv3-exp': {
137 b'streamv3-exp': {
130 b'changegroup': False,
138 b'changegroup': False,
131 b'cg.version': b'03',
139 b'cg.version': b'03',
132 b'obsolescence': False,
140 b'obsolescence': False,
133 b'phases': False,
141 b'phases': False,
134 b"streamv3-exp": True,
142 b"streamv3-exp": True,
135 b'tagsfnodescache': False,
143 b'tagsfnodescache': False,
136 b'revbranchcache': False,
144 b'revbranchcache': False,
137 },
145 },
138 b'packed1': {
146 b'packed1': {
139 b'cg.version': b's1',
147 b'cg.version': b's1',
140 },
148 },
141 b'bundle2': { # legacy
149 b'bundle2': { # legacy
142 b'cg.version': b'02',
150 b'cg.version': b'02',
143 },
151 },
144 }
152 }
145 _bundlespeccontentopts[b'bundle2'] = _bundlespeccontentopts[b'v2']
153 _bundlespeccontentopts[b'bundle2'] = _bundlespeccontentopts[b'v2']
146
154
147 _bundlespecvariants = {b"streamv2": {}}
155 _bundlespecvariants = {b"streamv2": {}}
148
156
149 # Compression engines allowed in version 1. THIS SHOULD NEVER CHANGE.
157 # Compression engines allowed in version 1. THIS SHOULD NEVER CHANGE.
150 _bundlespecv1compengines = {b'gzip', b'bzip2', b'none'}
158 _bundlespecv1compengines = {b'gzip', b'bzip2', b'none'}
151
159
152
160
153 def param_bool(key, value):
161 def param_bool(key, value):
154 """make a boolean out of a parameter value"""
162 """make a boolean out of a parameter value"""
155 b = stringutil.parsebool(value)
163 b = stringutil.parsebool(value)
156 if b is None:
164 if b is None:
157 msg = _(b"parameter %s should be a boolean ('%s')")
165 msg = _(b"parameter %s should be a boolean ('%s')")
158 msg %= (key, value)
166 msg %= (key, value)
159 raise error.InvalidBundleSpecification(msg)
167 raise error.InvalidBundleSpecification(msg)
160 return b
168 return b
161
169
162
170
163 # mapping of known parameter name need their value processed
171 # mapping of known parameter name need their value processed
164 bundle_spec_param_processing = {
172 bundle_spec_param_processing = {
165 b"obsolescence": param_bool,
173 b"obsolescence": param_bool,
166 b"obsolescence-mandatory": param_bool,
174 b"obsolescence-mandatory": param_bool,
167 b"phases": param_bool,
175 b"phases": param_bool,
168 }
176 }
169
177
170
178
171 def _parseparams(s):
179 def _parseparams(s):
172 """parse bundlespec parameter section
180 """parse bundlespec parameter section
173
181
174 input: "comp-version;params" string
182 input: "comp-version;params" string
175
183
176 return: (spec; {param_key: param_value})
184 return: (spec; {param_key: param_value})
177 """
185 """
178 if b';' not in s:
186 if b';' not in s:
179 return s, {}
187 return s, {}
180
188
181 params = {}
189 params = {}
182 version, paramstr = s.split(b';', 1)
190 version, paramstr = s.split(b';', 1)
183
191
184 err = _(b'invalid bundle specification: missing "=" in parameter: %s')
192 err = _(b'invalid bundle specification: missing "=" in parameter: %s')
185 for p in paramstr.split(b';'):
193 for p in paramstr.split(b';'):
186 if b'=' not in p:
194 if b'=' not in p:
187 msg = err % p
195 msg = err % p
188 raise error.InvalidBundleSpecification(msg)
196 raise error.InvalidBundleSpecification(msg)
189
197
190 key, value = p.split(b'=', 1)
198 key, value = p.split(b'=', 1)
191 key = urlreq.unquote(key)
199 key = urlreq.unquote(key)
192 value = urlreq.unquote(value)
200 value = urlreq.unquote(value)
193 process = bundle_spec_param_processing.get(key)
201 process = bundle_spec_param_processing.get(key)
194 if process is not None:
202 if process is not None:
195 value = process(key, value)
203 value = process(key, value)
196 params[key] = value
204 params[key] = value
197
205
198 return version, params
206 return version, params
199
207
200
208
201 def parsebundlespec(repo, spec, strict=True):
209 def parsebundlespec(repo, spec, strict=True):
202 """Parse a bundle string specification into parts.
210 """Parse a bundle string specification into parts.
203
211
204 Bundle specifications denote a well-defined bundle/exchange format.
212 Bundle specifications denote a well-defined bundle/exchange format.
205 The content of a given specification should not change over time in
213 The content of a given specification should not change over time in
206 order to ensure that bundles produced by a newer version of Mercurial are
214 order to ensure that bundles produced by a newer version of Mercurial are
207 readable from an older version.
215 readable from an older version.
208
216
209 The string currently has the form:
217 The string currently has the form:
210
218
211 <compression>-<type>[;<parameter0>[;<parameter1>]]
219 <compression>-<type>[;<parameter0>[;<parameter1>]]
212
220
213 Where <compression> is one of the supported compression formats
221 Where <compression> is one of the supported compression formats
214 and <type> is (currently) a version string. A ";" can follow the type and
222 and <type> is (currently) a version string. A ";" can follow the type and
215 all text afterwards is interpreted as URI encoded, ";" delimited key=value
223 all text afterwards is interpreted as URI encoded, ";" delimited key=value
216 pairs.
224 pairs.
217
225
218 If ``strict`` is True (the default) <compression> is required. Otherwise,
226 If ``strict`` is True (the default) <compression> is required. Otherwise,
219 it is optional.
227 it is optional.
220
228
221 Returns a bundlespec object of (compression, version, parameters).
229 Returns a bundlespec object of (compression, version, parameters).
222 Compression will be ``None`` if not in strict mode and a compression isn't
230 Compression will be ``None`` if not in strict mode and a compression isn't
223 defined.
231 defined.
224
232
225 An ``InvalidBundleSpecification`` is raised when the specification is
233 An ``InvalidBundleSpecification`` is raised when the specification is
226 not syntactically well formed.
234 not syntactically well formed.
227
235
228 An ``UnsupportedBundleSpecification`` is raised when the compression or
236 An ``UnsupportedBundleSpecification`` is raised when the compression or
229 bundle type/version is not recognized.
237 bundle type/version is not recognized.
230
238
231 Note: this function will likely eventually return a more complex data
239 Note: this function will likely eventually return a more complex data
232 structure, including bundle2 part information.
240 structure, including bundle2 part information.
233 """
241 """
234 if strict and b'-' not in spec:
242 if strict and b'-' not in spec:
235 raise error.InvalidBundleSpecification(
243 raise error.InvalidBundleSpecification(
236 _(
244 _(
237 b'invalid bundle specification; '
245 b'invalid bundle specification; '
238 b'must be prefixed with compression: %s'
246 b'must be prefixed with compression: %s'
239 )
247 )
240 % spec
248 % spec
241 )
249 )
242
250
243 pre_args = spec.split(b';', 1)[0]
251 pre_args = spec.split(b';', 1)[0]
244 if b'-' in pre_args:
252 if b'-' in pre_args:
245 compression, version = spec.split(b'-', 1)
253 compression, version = spec.split(b'-', 1)
246
254
247 if compression not in util.compengines.supportedbundlenames:
255 if compression not in util.compengines.supportedbundlenames:
248 raise error.UnsupportedBundleSpecification(
256 raise error.UnsupportedBundleSpecification(
249 _(b'%s compression is not supported') % compression
257 _(b'%s compression is not supported') % compression
250 )
258 )
251
259
252 version, params = _parseparams(version)
260 version, params = _parseparams(version)
253
261
254 if version not in _bundlespeccontentopts:
262 if version not in _bundlespeccontentopts:
255 raise error.UnsupportedBundleSpecification(
263 raise error.UnsupportedBundleSpecification(
256 _(b'%s is not a recognized bundle version') % version
264 _(b'%s is not a recognized bundle version') % version
257 )
265 )
258 else:
266 else:
259 # Value could be just the compression or just the version, in which
267 # Value could be just the compression or just the version, in which
260 # case some defaults are assumed (but only when not in strict mode).
268 # case some defaults are assumed (but only when not in strict mode).
261 assert not strict
269 assert not strict
262
270
263 spec, params = _parseparams(spec)
271 spec, params = _parseparams(spec)
264
272
265 if spec in util.compengines.supportedbundlenames:
273 if spec in util.compengines.supportedbundlenames:
266 compression = spec
274 compression = spec
267 version = b'v1'
275 version = b'v1'
268 # Generaldelta repos require v2.
276 # Generaldelta repos require v2.
269 if requirementsmod.GENERALDELTA_REQUIREMENT in repo.requirements:
277 if requirementsmod.GENERALDELTA_REQUIREMENT in repo.requirements:
270 version = b'v2'
278 version = b'v2'
271 elif requirementsmod.REVLOGV2_REQUIREMENT in repo.requirements:
279 elif requirementsmod.REVLOGV2_REQUIREMENT in repo.requirements:
272 version = b'v2'
280 version = b'v2'
273 # Modern compression engines require v2.
281 # Modern compression engines require v2.
274 if compression not in _bundlespecv1compengines:
282 if compression not in _bundlespecv1compengines:
275 version = b'v2'
283 version = b'v2'
276 elif spec in _bundlespeccontentopts:
284 elif spec in _bundlespeccontentopts:
277 if spec == b'packed1':
285 if spec == b'packed1':
278 compression = b'none'
286 compression = b'none'
279 else:
287 else:
280 compression = b'bzip2'
288 compression = b'bzip2'
281 version = spec
289 version = spec
282 else:
290 else:
283 raise error.UnsupportedBundleSpecification(
291 raise error.UnsupportedBundleSpecification(
284 _(b'%s is not a recognized bundle specification') % spec
292 _(b'%s is not a recognized bundle specification') % spec
285 )
293 )
286
294
287 # Bundle version 1 only supports a known set of compression engines.
295 # Bundle version 1 only supports a known set of compression engines.
288 if version == b'v1' and compression not in _bundlespecv1compengines:
296 if version == b'v1' and compression not in _bundlespecv1compengines:
289 raise error.UnsupportedBundleSpecification(
297 raise error.UnsupportedBundleSpecification(
290 _(b'compression engine %s is not supported on v1 bundles')
298 _(b'compression engine %s is not supported on v1 bundles')
291 % compression
299 % compression
292 )
300 )
293
301
294 # The specification for packed1 can optionally declare the data formats
302 # The specification for packed1 can optionally declare the data formats
295 # required to apply it. If we see this metadata, compare against what the
303 # required to apply it. If we see this metadata, compare against what the
296 # repo supports and error if the bundle isn't compatible.
304 # repo supports and error if the bundle isn't compatible.
297 if version == b'packed1' and b'requirements' in params:
305 if version == b'packed1' and b'requirements' in params:
298 requirements = set(cast(bytes, params[b'requirements']).split(b','))
306 requirements = set(cast(bytes, params[b'requirements']).split(b','))
299 missingreqs = requirements - requirementsmod.STREAM_FIXED_REQUIREMENTS
307 missingreqs = requirements - requirementsmod.STREAM_FIXED_REQUIREMENTS
300 if missingreqs:
308 if missingreqs:
301 raise error.UnsupportedBundleSpecification(
309 raise error.UnsupportedBundleSpecification(
302 _(b'missing support for repository features: %s')
310 _(b'missing support for repository features: %s')
303 % b', '.join(sorted(missingreqs))
311 % b', '.join(sorted(missingreqs))
304 )
312 )
305
313
306 # Compute contentopts based on the version
314 # Compute contentopts based on the version
307 if b"stream" in params:
315 if b"stream" in params:
308 # This case is fishy as this mostly derails the version selection
316 # This case is fishy as this mostly derails the version selection
309 # mechanism. `stream` bundles are quite specific and used differently
317 # mechanism. `stream` bundles are quite specific and used differently
310 # as "normal" bundles.
318 # as "normal" bundles.
311 #
319 #
312 # (we should probably define a cleaner way to do this and raise a
320 # (we should probably define a cleaner way to do this and raise a
313 # warning when the old way is encountered)
321 # warning when the old way is encountered)
314 if params[b"stream"] == b"v2":
322 if params[b"stream"] == b"v2":
315 version = b"streamv2"
323 version = b"streamv2"
316 if params[b"stream"] == b"v3-exp":
324 if params[b"stream"] == b"v3-exp":
317 version = b"streamv3-exp"
325 version = b"streamv3-exp"
318 contentopts = _bundlespeccontentopts.get(version, {}).copy()
326 contentopts = _bundlespeccontentopts.get(version, {}).copy()
319 if version == b"streamv2" or version == b"streamv3-exp":
327 if version == b"streamv2" or version == b"streamv3-exp":
320 # streamv2 have been reported as "v2" for a while.
328 # streamv2 have been reported as "v2" for a while.
321 version = b"v2"
329 version = b"v2"
322
330
323 engine = util.compengines.forbundlename(compression)
331 engine = util.compengines.forbundlename(compression)
324 compression, wirecompression = engine.bundletype()
332 compression, wirecompression = engine.bundletype()
325 wireversion = _bundlespeccontentopts[version][b'cg.version']
333 wireversion = _bundlespeccontentopts[version][b'cg.version']
326
334
327 return bundlespec(
335 return bundlespec(
328 compression, wirecompression, version, wireversion, params, contentopts
336 compression, wirecompression, version, wireversion, params, contentopts
329 )
337 )
330
338
331
339
332 def parseclonebundlesmanifest(repo, s):
340 def parseclonebundlesmanifest(repo, s):
333 """Parses the raw text of a clone bundles manifest.
341 """Parses the raw text of a clone bundles manifest.
334
342
335 Returns a list of dicts. The dicts have a ``URL`` key corresponding
343 Returns a list of dicts. The dicts have a ``URL`` key corresponding
336 to the URL and other keys are the attributes for the entry.
344 to the URL and other keys are the attributes for the entry.
337 """
345 """
338 m = []
346 m = []
339 for line in s.splitlines():
347 for line in s.splitlines():
340 fields = line.split()
348 fields = line.split()
341 if not fields:
349 if not fields:
342 continue
350 continue
343 attrs = {b'URL': fields[0]}
351 attrs = {b'URL': fields[0]}
344 for rawattr in fields[1:]:
352 for rawattr in fields[1:]:
345 key, value = rawattr.split(b'=', 1)
353 key, value = rawattr.split(b'=', 1)
346 key = util.urlreq.unquote(key)
354 key = util.urlreq.unquote(key)
347 value = util.urlreq.unquote(value)
355 value = util.urlreq.unquote(value)
348 attrs[key] = value
356 attrs[key] = value
349
357
350 # Parse BUNDLESPEC into components. This makes client-side
358 # Parse BUNDLESPEC into components. This makes client-side
351 # preferences easier to specify since you can prefer a single
359 # preferences easier to specify since you can prefer a single
352 # component of the BUNDLESPEC.
360 # component of the BUNDLESPEC.
353 if key == b'BUNDLESPEC':
361 if key == b'BUNDLESPEC':
354 try:
362 try:
355 bundlespec = parsebundlespec(repo, value)
363 bundlespec = parsebundlespec(repo, value)
356 attrs[b'COMPRESSION'] = bundlespec.compression
364 attrs[b'COMPRESSION'] = bundlespec.compression
357 attrs[b'VERSION'] = bundlespec.version
365 attrs[b'VERSION'] = bundlespec.version
358 except error.InvalidBundleSpecification:
366 except error.InvalidBundleSpecification:
359 pass
367 pass
360 except error.UnsupportedBundleSpecification:
368 except error.UnsupportedBundleSpecification:
361 pass
369 pass
362
370
363 m.append(attrs)
371 m.append(attrs)
364
372
365 return m
373 return m
366
374
367
375
368 def isstreamclonespec(bundlespec):
376 def isstreamclonespec(bundlespec):
369 # Stream clone v1
377 # Stream clone v1
370 if bundlespec.wirecompression == b'UN' and bundlespec.wireversion == b's1':
378 if bundlespec.wirecompression == b'UN' and bundlespec.wireversion == b's1':
371 return True
379 return True
372
380
373 # Stream clone v2
381 # Stream clone v2
374 if (
382 if (
375 bundlespec.wirecompression == b'UN'
383 bundlespec.wirecompression == b'UN'
376 and bundlespec.wireversion == b'02'
384 and bundlespec.wireversion == b'02'
377 and (
385 and (
378 bundlespec.contentopts.get(b'streamv2')
386 bundlespec.contentopts.get(b'streamv2')
379 or bundlespec.contentopts.get(b'streamv3-exp')
387 or bundlespec.contentopts.get(b'streamv3-exp')
380 )
388 )
381 ):
389 ):
382 return True
390 return True
383
391
384 return False
392 return False
385
393
386
394
387 def filterclonebundleentries(repo, entries, streamclonerequested=False):
395 def filterclonebundleentries(
396 repo, entries, streamclonerequested=False, pullbundles=False
397 ):
388 """Remove incompatible clone bundle manifest entries.
398 """Remove incompatible clone bundle manifest entries.
389
399
390 Accepts a list of entries parsed with ``parseclonebundlesmanifest``
400 Accepts a list of entries parsed with ``parseclonebundlesmanifest``
391 and returns a new list consisting of only the entries that this client
401 and returns a new list consisting of only the entries that this client
392 should be able to apply.
402 should be able to apply.
393
403
394 There is no guarantee we'll be able to apply all returned entries because
404 There is no guarantee we'll be able to apply all returned entries because
395 the metadata we use to filter on may be missing or wrong.
405 the metadata we use to filter on may be missing or wrong.
396 """
406 """
397 newentries = []
407 newentries = []
398 for entry in entries:
408 for entry in entries:
409 url = entry.get(b'URL')
410 if not pullbundles and not any(
411 [url.startswith(scheme) for scheme in SUPPORTED_CLONEBUNDLE_SCHEMES]
412 ):
413 repo.ui.debug(
414 b'filtering %s because not a supported clonebundle scheme\n'
415 % url
416 )
417 continue
418
399 spec = entry.get(b'BUNDLESPEC')
419 spec = entry.get(b'BUNDLESPEC')
400 if spec:
420 if spec:
401 try:
421 try:
402 bundlespec = parsebundlespec(repo, spec, strict=True)
422 bundlespec = parsebundlespec(repo, spec, strict=True)
403
423
404 # If a stream clone was requested, filter out non-streamclone
424 # If a stream clone was requested, filter out non-streamclone
405 # entries.
425 # entries.
406 if streamclonerequested and not isstreamclonespec(bundlespec):
426 if streamclonerequested and not isstreamclonespec(bundlespec):
407 repo.ui.debug(
427 repo.ui.debug(
408 b'filtering %s because not a stream clone\n'
428 b'filtering %s because not a stream clone\n' % url
409 % entry[b'URL']
410 )
429 )
411 continue
430 continue
412
431
413 except error.InvalidBundleSpecification as e:
432 except error.InvalidBundleSpecification as e:
414 repo.ui.debug(stringutil.forcebytestr(e) + b'\n')
433 repo.ui.debug(stringutil.forcebytestr(e) + b'\n')
415 continue
434 continue
416 except error.UnsupportedBundleSpecification as e:
435 except error.UnsupportedBundleSpecification as e:
417 repo.ui.debug(
436 repo.ui.debug(
418 b'filtering %s because unsupported bundle '
437 b'filtering %s because unsupported bundle '
419 b'spec: %s\n' % (entry[b'URL'], stringutil.forcebytestr(e))
438 b'spec: %s\n' % (url, stringutil.forcebytestr(e))
420 )
439 )
421 continue
440 continue
422 # If we don't have a spec and requested a stream clone, we don't know
441 # If we don't have a spec and requested a stream clone, we don't know
423 # what the entry is so don't attempt to apply it.
442 # what the entry is so don't attempt to apply it.
424 elif streamclonerequested:
443 elif streamclonerequested:
425 repo.ui.debug(
444 repo.ui.debug(
426 b'filtering %s because cannot determine if a stream '
445 b'filtering %s because cannot determine if a stream '
427 b'clone bundle\n' % entry[b'URL']
446 b'clone bundle\n' % url
428 )
447 )
429 continue
448 continue
430
449
431 if b'REQUIRESNI' in entry and not sslutil.hassni:
450 if b'REQUIRESNI' in entry and not sslutil.hassni:
432 repo.ui.debug(
451 repo.ui.debug(b'filtering %s because SNI not supported\n' % url)
433 b'filtering %s because SNI not supported\n' % entry[b'URL']
434 )
435 continue
452 continue
436
453
437 if b'REQUIREDRAM' in entry:
454 if b'REQUIREDRAM' in entry:
438 try:
455 try:
439 requiredram = util.sizetoint(entry[b'REQUIREDRAM'])
456 requiredram = util.sizetoint(entry[b'REQUIREDRAM'])
440 except error.ParseError:
457 except error.ParseError:
441 repo.ui.debug(
458 repo.ui.debug(
442 b'filtering %s due to a bad REQUIREDRAM attribute\n'
459 b'filtering %s due to a bad REQUIREDRAM attribute\n' % url
443 % entry[b'URL']
444 )
460 )
445 continue
461 continue
446 actualram = repo.ui.estimatememory()
462 actualram = repo.ui.estimatememory()
447 if actualram is not None and actualram * 0.66 < requiredram:
463 if actualram is not None and actualram * 0.66 < requiredram:
448 repo.ui.debug(
464 repo.ui.debug(
449 b'filtering %s as it needs more than 2/3 of system memory\n'
465 b'filtering %s as it needs more than 2/3 of system memory\n'
450 % entry[b'URL']
466 % url
451 )
467 )
452 continue
468 continue
453
469
454 newentries.append(entry)
470 newentries.append(entry)
455
471
456 return newentries
472 return newentries
457
473
458
474
459 class clonebundleentry:
475 class clonebundleentry:
460 """Represents an item in a clone bundles manifest.
476 """Represents an item in a clone bundles manifest.
461
477
462 This rich class is needed to support sorting since sorted() in Python 3
478 This rich class is needed to support sorting since sorted() in Python 3
463 doesn't support ``cmp`` and our comparison is complex enough that ``key=``
479 doesn't support ``cmp`` and our comparison is complex enough that ``key=``
464 won't work.
480 won't work.
465 """
481 """
466
482
467 def __init__(self, value, prefers):
483 def __init__(self, value, prefers):
468 self.value = value
484 self.value = value
469 self.prefers = prefers
485 self.prefers = prefers
470
486
471 def _cmp(self, other):
487 def _cmp(self, other):
472 for prefkey, prefvalue in self.prefers:
488 for prefkey, prefvalue in self.prefers:
473 avalue = self.value.get(prefkey)
489 avalue = self.value.get(prefkey)
474 bvalue = other.value.get(prefkey)
490 bvalue = other.value.get(prefkey)
475
491
476 # Special case for b missing attribute and a matches exactly.
492 # Special case for b missing attribute and a matches exactly.
477 if avalue is not None and bvalue is None and avalue == prefvalue:
493 if avalue is not None and bvalue is None and avalue == prefvalue:
478 return -1
494 return -1
479
495
480 # Special case for a missing attribute and b matches exactly.
496 # Special case for a missing attribute and b matches exactly.
481 if bvalue is not None and avalue is None and bvalue == prefvalue:
497 if bvalue is not None and avalue is None and bvalue == prefvalue:
482 return 1
498 return 1
483
499
484 # We can't compare unless attribute present on both.
500 # We can't compare unless attribute present on both.
485 if avalue is None or bvalue is None:
501 if avalue is None or bvalue is None:
486 continue
502 continue
487
503
488 # Same values should fall back to next attribute.
504 # Same values should fall back to next attribute.
489 if avalue == bvalue:
505 if avalue == bvalue:
490 continue
506 continue
491
507
492 # Exact matches come first.
508 # Exact matches come first.
493 if avalue == prefvalue:
509 if avalue == prefvalue:
494 return -1
510 return -1
495 if bvalue == prefvalue:
511 if bvalue == prefvalue:
496 return 1
512 return 1
497
513
498 # Fall back to next attribute.
514 # Fall back to next attribute.
499 continue
515 continue
500
516
501 # If we got here we couldn't sort by attributes and prefers. Fall
517 # If we got here we couldn't sort by attributes and prefers. Fall
502 # back to index order.
518 # back to index order.
503 return 0
519 return 0
504
520
505 def __lt__(self, other):
521 def __lt__(self, other):
506 return self._cmp(other) < 0
522 return self._cmp(other) < 0
507
523
508 def __gt__(self, other):
524 def __gt__(self, other):
509 return self._cmp(other) > 0
525 return self._cmp(other) > 0
510
526
511 def __eq__(self, other):
527 def __eq__(self, other):
512 return self._cmp(other) == 0
528 return self._cmp(other) == 0
513
529
514 def __le__(self, other):
530 def __le__(self, other):
515 return self._cmp(other) <= 0
531 return self._cmp(other) <= 0
516
532
517 def __ge__(self, other):
533 def __ge__(self, other):
518 return self._cmp(other) >= 0
534 return self._cmp(other) >= 0
519
535
520 def __ne__(self, other):
536 def __ne__(self, other):
521 return self._cmp(other) != 0
537 return self._cmp(other) != 0
522
538
523
539
524 def sortclonebundleentries(ui, entries):
540 def sortclonebundleentries(ui, entries):
525 prefers = ui.configlist(b'ui', b'clonebundleprefers')
541 prefers = ui.configlist(b'ui', b'clonebundleprefers')
526 if not prefers:
542 if not prefers:
527 return list(entries)
543 return list(entries)
528
544
529 def _split(p):
545 def _split(p):
530 if b'=' not in p:
546 if b'=' not in p:
531 hint = _(b"each comma separated item should be key=value pairs")
547 hint = _(b"each comma separated item should be key=value pairs")
532 raise error.Abort(
548 raise error.Abort(
533 _(b"invalid ui.clonebundleprefers item: %s") % p, hint=hint
549 _(b"invalid ui.clonebundleprefers item: %s") % p, hint=hint
534 )
550 )
535 return p.split(b'=', 1)
551 return p.split(b'=', 1)
536
552
537 prefers = [_split(p) for p in prefers]
553 prefers = [_split(p) for p in prefers]
538
554
539 items = sorted(clonebundleentry(v, prefers) for v in entries)
555 items = sorted(clonebundleentry(v, prefers) for v in entries)
540 return [i.value for i in items]
556 return [i.value for i in items]
@@ -1,786 +1,852 b''
1 # dirstatemap.py
1 # dirstatemap.py
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6
6
7 import struct
7 from .i18n import _
8 from .i18n import _
8
9
9 from . import (
10 from . import (
10 error,
11 error,
11 pathutil,
12 pathutil,
12 policy,
13 policy,
13 testing,
14 testing,
14 txnutil,
15 txnutil,
15 util,
16 util,
16 )
17 )
17
18
18 from .dirstateutils import (
19 from .dirstateutils import (
19 docket as docketmod,
20 docket as docketmod,
20 v2,
21 v2,
21 )
22 )
22
23
23 parsers = policy.importmod('parsers')
24 parsers = policy.importmod('parsers')
24 rustmod = policy.importrust('dirstate')
25 rustmod = policy.importrust('dirstate')
25
26
26 propertycache = util.propertycache
27 propertycache = util.propertycache
27
28
28 if rustmod is None:
29 if rustmod is None:
29 DirstateItem = parsers.DirstateItem
30 DirstateItem = parsers.DirstateItem
30 else:
31 else:
31 DirstateItem = rustmod.DirstateItem
32 DirstateItem = rustmod.DirstateItem
32
33
33 rangemask = 0x7FFFFFFF
34 rangemask = 0x7FFFFFFF
34
35
35 WRITE_MODE_AUTO = 0
36 WRITE_MODE_AUTO = 0
36 WRITE_MODE_FORCE_NEW = 1
37 WRITE_MODE_FORCE_NEW = 1
37 WRITE_MODE_FORCE_APPEND = 2
38 WRITE_MODE_FORCE_APPEND = 2
38
39
39
40
40 V2_MAX_READ_ATTEMPTS = 5
41 V2_MAX_READ_ATTEMPTS = 5
41
42
42
43
43 class _dirstatemapcommon:
44 class _dirstatemapcommon:
44 """
45 """
45 Methods that are identical for both implementations of the dirstatemap
46 Methods that are identical for both implementations of the dirstatemap
46 class, with and without Rust extensions enabled.
47 class, with and without Rust extensions enabled.
47 """
48 """
48
49
49 # please pytype
50 # please pytype
50
51
51 _map = None
52 _map = None
52 copymap = None
53 copymap = None
53
54
54 def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2):
55 def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2):
55 self._use_dirstate_v2 = use_dirstate_v2
56 self._use_dirstate_v2 = use_dirstate_v2
56 self._nodeconstants = nodeconstants
57 self._nodeconstants = nodeconstants
57 self._ui = ui
58 self._ui = ui
58 self._opener = opener
59 self._opener = opener
59 self._root = root
60 self._root = root
60 self._filename = b'dirstate'
61 self._filename = b'dirstate'
61 self._nodelen = 20 # Also update Rust code when changing this!
62 self._nodelen = 20 # Also update Rust code when changing this!
62 self._parents = None
63 self._parents = None
63 self._dirtyparents = False
64 self._dirtyparents = False
64 self._docket = None
65 self._docket = None
65 write_mode = ui.config(b"devel", b"dirstate.v2.data_update_mode")
66 write_mode = ui.config(b"devel", b"dirstate.v2.data_update_mode")
66 if write_mode == b"auto":
67 if write_mode == b"auto":
67 self._write_mode = WRITE_MODE_AUTO
68 self._write_mode = WRITE_MODE_AUTO
68 elif write_mode == b"force-append":
69 elif write_mode == b"force-append":
69 self._write_mode = WRITE_MODE_FORCE_APPEND
70 self._write_mode = WRITE_MODE_FORCE_APPEND
70 elif write_mode == b"force-new":
71 elif write_mode == b"force-new":
71 self._write_mode = WRITE_MODE_FORCE_NEW
72 self._write_mode = WRITE_MODE_FORCE_NEW
72 else:
73 else:
73 # unknown value, fallback to default
74 # unknown value, fallback to default
74 self._write_mode = WRITE_MODE_AUTO
75 self._write_mode = WRITE_MODE_AUTO
75
76
76 # for consistent view between _pl() and _read() invocations
77 # for consistent view between _pl() and _read() invocations
77 self._pendingmode = None
78 self._pendingmode = None
78
79
79 def _set_identity(self):
80 def _set_identity(self):
80 self.identity = self._get_current_identity()
81 self.identity = self._get_current_identity()
81
82
82 def _get_current_identity(self):
83 def _get_current_identity(self):
83 try:
84 try:
84 return util.cachestat(self._opener.join(self._filename))
85 return util.cachestat(self._opener.join(self._filename))
85 except FileNotFoundError:
86 except FileNotFoundError:
86 return None
87 return None
87
88
88 def may_need_refresh(self):
89 def may_need_refresh(self):
89 if 'identity' not in vars(self):
90 if 'identity' not in vars(self):
90 # no existing identity, we need a refresh
91 # no existing identity, we need a refresh
91 return True
92 return True
92 if self.identity is None:
93 if self.identity is None:
93 return True
94 return True
94 if not self.identity.cacheable():
95 if not self.identity.cacheable():
95 # We cannot trust the entry
96 # We cannot trust the entry
96 # XXX this is a problem on windows, NFS, or other inode less system
97 # XXX this is a problem on windows, NFS, or other inode less system
97 return True
98 return True
98 current_identity = self._get_current_identity()
99 current_identity = self._get_current_identity()
99 if current_identity is None:
100 if current_identity is None:
100 return True
101 return True
101 if not current_identity.cacheable():
102 if not current_identity.cacheable():
102 # We cannot trust the entry
103 # We cannot trust the entry
103 # XXX this is a problem on windows, NFS, or other inode less system
104 # XXX this is a problem on windows, NFS, or other inode less system
104 return True
105 return True
105 return current_identity != self.identity
106 return current_identity != self.identity
106
107
107 def preload(self):
108 def preload(self):
108 """Loads the underlying data, if it's not already loaded"""
109 """Loads the underlying data, if it's not already loaded"""
109 self._map
110 self._map
110
111
111 def get(self, key, default=None):
112 def get(self, key, default=None):
112 return self._map.get(key, default)
113 return self._map.get(key, default)
113
114
114 def __len__(self):
115 def __len__(self):
115 return len(self._map)
116 return len(self._map)
116
117
117 def __iter__(self):
118 def __iter__(self):
118 return iter(self._map)
119 return iter(self._map)
119
120
120 def __contains__(self, key):
121 def __contains__(self, key):
121 return key in self._map
122 return key in self._map
122
123
123 def __getitem__(self, item):
124 def __getitem__(self, item):
124 return self._map[item]
125 return self._map[item]
125
126
126 ### disk interaction
127 ### disk interaction
127
128
128 def _opendirstatefile(self):
129 def _opendirstatefile(self):
129 fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
130 fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
130 if self._pendingmode is not None and self._pendingmode != mode:
131 if self._pendingmode is not None and self._pendingmode != mode:
131 fp.close()
132 fp.close()
132 raise error.Abort(
133 raise error.Abort(
133 _(b'working directory state may be changed parallelly')
134 _(b'working directory state may be changed parallelly')
134 )
135 )
135 self._pendingmode = mode
136 self._pendingmode = mode
136 return fp
137 return fp
137
138
138 def _readdirstatefile(self, size=-1):
139 def _readdirstatefile(self, size=-1):
139 try:
140 try:
140 with self._opendirstatefile() as fp:
141 with self._opendirstatefile() as fp:
141 return fp.read(size)
142 return fp.read(size)
142 except FileNotFoundError:
143 except FileNotFoundError:
143 # File doesn't exist, so the current state is empty
144 # File doesn't exist, so the current state is empty
144 return b''
145 return b''
145
146
146 @property
147 @property
147 def docket(self):
148 def docket(self):
148 if not self._docket:
149 if not self._docket:
149 if not self._use_dirstate_v2:
150 if not self._use_dirstate_v2:
150 raise error.ProgrammingError(
151 raise error.ProgrammingError(
151 b'dirstate only has a docket in v2 format'
152 b'dirstate only has a docket in v2 format'
152 )
153 )
153 self._set_identity()
154 self._set_identity()
154 self._docket = docketmod.DirstateDocket.parse(
155 try:
155 self._readdirstatefile(), self._nodeconstants
156 self._docket = docketmod.DirstateDocket.parse(
156 )
157 self._readdirstatefile(), self._nodeconstants
158 )
159 except struct.error:
160 self._ui.debug(b"failed to read dirstate-v2 data")
161 raise error.CorruptedDirstate(
162 b"failed to read dirstate-v2 data"
163 )
157 return self._docket
164 return self._docket
158
165
159 def _read_v2_data(self):
166 def _read_v2_data(self):
160 data = None
167 data = None
161 attempts = 0
168 attempts = 0
162 while attempts < V2_MAX_READ_ATTEMPTS:
169 while attempts < V2_MAX_READ_ATTEMPTS:
163 attempts += 1
170 attempts += 1
164 try:
171 try:
165 # TODO: use mmap when possible
172 # TODO: use mmap when possible
166 data = self._opener.read(self.docket.data_filename())
173 data = self._opener.read(self.docket.data_filename())
167 except FileNotFoundError:
174 except FileNotFoundError:
168 # read race detected between docket and data file
175 # read race detected between docket and data file
169 # reload the docket and retry
176 # reload the docket and retry
170 self._docket = None
177 self._docket = None
171 if data is None:
178 if data is None:
172 assert attempts >= V2_MAX_READ_ATTEMPTS
179 assert attempts >= V2_MAX_READ_ATTEMPTS
173 msg = b"dirstate read race happened %d times in a row"
180 msg = b"dirstate read race happened %d times in a row"
174 msg %= attempts
181 msg %= attempts
175 raise error.Abort(msg)
182 raise error.Abort(msg)
176 return self._opener.read(self.docket.data_filename())
183 return self._opener.read(self.docket.data_filename())
177
184
178 def write_v2_no_append(self, tr, st, meta, packed):
185 def write_v2_no_append(self, tr, st, meta, packed):
179 old_docket = self.docket
186 try:
187 old_docket = self.docket
188 except error.CorruptedDirstate:
189 # This means we've identified a dirstate-v1 file on-disk when we
190 # were expecting a dirstate-v2 docket. We've managed to recover
191 # from that unexpected situation, and now we want to write back a
192 # dirstate-v2 file to make the on-disk situation right again.
193 #
194 # This shouldn't be triggered since `self.docket` is cached and
195 # we would have called parents() or read() first, but it's here
196 # just in case.
197 old_docket = None
198
180 new_docket = docketmod.DirstateDocket.with_new_uuid(
199 new_docket = docketmod.DirstateDocket.with_new_uuid(
181 self.parents(), len(packed), meta
200 self.parents(), len(packed), meta
182 )
201 )
183 if old_docket.uuid == new_docket.uuid:
202 if old_docket is not None and old_docket.uuid == new_docket.uuid:
184 raise error.ProgrammingError(b'dirstate docket name collision')
203 raise error.ProgrammingError(b'dirstate docket name collision')
185 data_filename = new_docket.data_filename()
204 data_filename = new_docket.data_filename()
186 self._opener.write(data_filename, packed)
205 self._opener.write(data_filename, packed)
187 # tell the transaction that we are adding a new file
206 # tell the transaction that we are adding a new file
188 if tr is not None:
207 if tr is not None:
189 tr.addbackup(data_filename, location=b'plain')
208 tr.addbackup(data_filename, location=b'plain')
190 # Write the new docket after the new data file has been
209 # Write the new docket after the new data file has been
191 # written. Because `st` was opened with `atomictemp=True`,
210 # written. Because `st` was opened with `atomictemp=True`,
192 # the actual `.hg/dirstate` file is only affected on close.
211 # the actual `.hg/dirstate` file is only affected on close.
193 st.write(new_docket.serialize())
212 st.write(new_docket.serialize())
194 st.close()
213 st.close()
195 # Remove the old data file after the new docket pointing to
214 # Remove the old data file after the new docket pointing to
196 # the new data file was written.
215 # the new data file was written.
197 if old_docket.uuid:
216 if old_docket is not None and old_docket.uuid:
198 data_filename = old_docket.data_filename()
217 data_filename = old_docket.data_filename()
199 if tr is not None:
218 if tr is not None:
200 tr.addbackup(data_filename, location=b'plain')
219 tr.addbackup(data_filename, location=b'plain')
201 unlink = lambda _tr=None: self._opener.unlink(data_filename)
220 unlink = lambda _tr=None: self._opener.unlink(data_filename)
202 if tr:
221 if tr:
203 category = b"dirstate-v2-clean-" + old_docket.uuid
222 category = b"dirstate-v2-clean-" + old_docket.uuid
204 tr.addpostclose(category, unlink)
223 tr.addpostclose(category, unlink)
205 else:
224 else:
206 unlink()
225 unlink()
207 self._docket = new_docket
226 self._docket = new_docket
208
227
209 ### reading/setting parents
228 ### reading/setting parents
210
229
211 def parents(self):
230 def parents(self):
212 if not self._parents:
231 if not self._parents:
213 if self._use_dirstate_v2:
232 if self._use_dirstate_v2:
214 self._parents = self.docket.parents
233 try:
234 self.docket
235 except error.CorruptedDirstate as e:
236 # fall back to dirstate-v1 if we fail to read v2
237 self._v1_parents(e)
238 else:
239 self._parents = self.docket.parents
215 else:
240 else:
216 read_len = self._nodelen * 2
241 self._v1_parents()
217 st = self._readdirstatefile(read_len)
218 l = len(st)
219 if l == read_len:
220 self._parents = (
221 st[: self._nodelen],
222 st[self._nodelen : 2 * self._nodelen],
223 )
224 elif l == 0:
225 self._parents = (
226 self._nodeconstants.nullid,
227 self._nodeconstants.nullid,
228 )
229 else:
230 raise error.Abort(
231 _(b'working directory state appears damaged!')
232 )
233
242
234 return self._parents
243 return self._parents
235
244
245 def _v1_parents(self, from_v2_exception=None):
246 read_len = self._nodelen * 2
247 st = self._readdirstatefile(read_len)
248 l = len(st)
249 if l == read_len:
250 self._parents = (
251 st[: self._nodelen],
252 st[self._nodelen : 2 * self._nodelen],
253 )
254 elif l == 0:
255 self._parents = (
256 self._nodeconstants.nullid,
257 self._nodeconstants.nullid,
258 )
259 else:
260 hint = None
261 if from_v2_exception is not None:
262 hint = _(b"falling back to dirstate-v1 from v2 also failed")
263 raise error.Abort(
264 _(b'working directory state appears damaged!'), hint
265 )
266
236
267
237 class dirstatemap(_dirstatemapcommon):
268 class dirstatemap(_dirstatemapcommon):
238 """Map encapsulating the dirstate's contents.
269 """Map encapsulating the dirstate's contents.
239
270
240 The dirstate contains the following state:
271 The dirstate contains the following state:
241
272
242 - `identity` is the identity of the dirstate file, which can be used to
273 - `identity` is the identity of the dirstate file, which can be used to
243 detect when changes have occurred to the dirstate file.
274 detect when changes have occurred to the dirstate file.
244
275
245 - `parents` is a pair containing the parents of the working copy. The
276 - `parents` is a pair containing the parents of the working copy. The
246 parents are updated by calling `setparents`.
277 parents are updated by calling `setparents`.
247
278
248 - the state map maps filenames to tuples of (state, mode, size, mtime),
279 - the state map maps filenames to tuples of (state, mode, size, mtime),
249 where state is a single character representing 'normal', 'added',
280 where state is a single character representing 'normal', 'added',
250 'removed', or 'merged'. It is read by treating the dirstate as a
281 'removed', or 'merged'. It is read by treating the dirstate as a
251 dict. File state is updated by calling various methods (see each
282 dict. File state is updated by calling various methods (see each
252 documentation for details):
283 documentation for details):
253
284
254 - `reset_state`,
285 - `reset_state`,
255 - `set_tracked`
286 - `set_tracked`
256 - `set_untracked`
287 - `set_untracked`
257 - `set_clean`
288 - `set_clean`
258 - `set_possibly_dirty`
289 - `set_possibly_dirty`
259
290
260 - `copymap` maps destination filenames to their source filename.
291 - `copymap` maps destination filenames to their source filename.
261
292
262 The dirstate also provides the following views onto the state:
293 The dirstate also provides the following views onto the state:
263
294
264 - `filefoldmap` is a dict mapping normalized filenames to the denormalized
295 - `filefoldmap` is a dict mapping normalized filenames to the denormalized
265 form that they appear as in the dirstate.
296 form that they appear as in the dirstate.
266
297
267 - `dirfoldmap` is a dict mapping normalized directory names to the
298 - `dirfoldmap` is a dict mapping normalized directory names to the
268 denormalized form that they appear as in the dirstate.
299 denormalized form that they appear as in the dirstate.
269 """
300 """
270
301
271 ### Core data storage and access
302 ### Core data storage and access
272
303
273 @propertycache
304 @propertycache
274 def _map(self):
305 def _map(self):
275 self._map = {}
306 self._map = {}
276 self.read()
307 self.read()
277 return self._map
308 return self._map
278
309
279 @propertycache
310 @propertycache
280 def copymap(self):
311 def copymap(self):
281 self.copymap = {}
312 self.copymap = {}
282 self._map
313 self._map
283 return self.copymap
314 return self.copymap
284
315
285 def clear(self):
316 def clear(self):
286 self._map.clear()
317 self._map.clear()
287 self.copymap.clear()
318 self.copymap.clear()
288 self.setparents(self._nodeconstants.nullid, self._nodeconstants.nullid)
319 self.setparents(self._nodeconstants.nullid, self._nodeconstants.nullid)
289 util.clearcachedproperty(self, b"_dirs")
320 util.clearcachedproperty(self, b"_dirs")
290 util.clearcachedproperty(self, b"_alldirs")
321 util.clearcachedproperty(self, b"_alldirs")
291 util.clearcachedproperty(self, b"filefoldmap")
322 util.clearcachedproperty(self, b"filefoldmap")
292 util.clearcachedproperty(self, b"dirfoldmap")
323 util.clearcachedproperty(self, b"dirfoldmap")
293
324
294 def items(self):
325 def items(self):
295 return self._map.items()
326 return self._map.items()
296
327
297 # forward for python2,3 compat
328 # forward for python2,3 compat
298 iteritems = items
329 iteritems = items
299
330
300 def debug_iter(self, all):
331 def debug_iter(self, all):
301 """
332 """
302 Return an iterator of (filename, state, mode, size, mtime) tuples
333 Return an iterator of (filename, state, mode, size, mtime) tuples
303
334
304 `all` is unused when Rust is not enabled
335 `all` is unused when Rust is not enabled
305 """
336 """
306 for (filename, item) in self.items():
337 for (filename, item) in self.items():
307 yield (filename, item.state, item.mode, item.size, item.mtime)
338 yield (filename, item.state, item.mode, item.size, item.mtime)
308
339
309 def keys(self):
340 def keys(self):
310 return self._map.keys()
341 return self._map.keys()
311
342
312 ### reading/setting parents
343 ### reading/setting parents
313
344
314 def setparents(self, p1, p2, fold_p2=False):
345 def setparents(self, p1, p2, fold_p2=False):
315 self._parents = (p1, p2)
346 self._parents = (p1, p2)
316 self._dirtyparents = True
347 self._dirtyparents = True
317 copies = {}
348 copies = {}
318 if fold_p2:
349 if fold_p2:
319 for f, s in self._map.items():
350 for f, s in self._map.items():
320 # Discard "merged" markers when moving away from a merge state
351 # Discard "merged" markers when moving away from a merge state
321 if s.p2_info:
352 if s.p2_info:
322 source = self.copymap.pop(f, None)
353 source = self.copymap.pop(f, None)
323 if source:
354 if source:
324 copies[f] = source
355 copies[f] = source
325 s.drop_merge_data()
356 s.drop_merge_data()
326 return copies
357 return copies
327
358
328 ### disk interaction
359 ### disk interaction
329
360
330 def read(self):
361 def read(self):
331 testing.wait_on_cfg(self._ui, b'dirstate.pre-read-file')
362 testing.wait_on_cfg(self._ui, b'dirstate.pre-read-file')
332 if self._use_dirstate_v2:
363 if self._use_dirstate_v2:
333
364 try:
334 if not self.docket.uuid:
365 self.docket
335 return
366 except error.CorruptedDirstate:
336 testing.wait_on_cfg(self._ui, b'dirstate.post-docket-read-file')
367 # fall back to dirstate-v1 if we fail to read v2
337 st = self._read_v2_data()
368 self._set_identity()
369 st = self._readdirstatefile()
370 else:
371 if not self.docket.uuid:
372 return
373 testing.wait_on_cfg(self._ui, b'dirstate.post-docket-read-file')
374 st = self._read_v2_data()
338 else:
375 else:
339 self._set_identity()
376 self._set_identity()
340 st = self._readdirstatefile()
377 st = self._readdirstatefile()
341
378
342 if not st:
379 if not st:
343 return
380 return
344
381
345 # TODO: adjust this estimate for dirstate-v2
382 # TODO: adjust this estimate for dirstate-v2
346 if util.safehasattr(parsers, 'dict_new_presized'):
383 if util.safehasattr(parsers, 'dict_new_presized'):
347 # Make an estimate of the number of files in the dirstate based on
384 # Make an estimate of the number of files in the dirstate based on
348 # its size. This trades wasting some memory for avoiding costly
385 # its size. This trades wasting some memory for avoiding costly
349 # resizes. Each entry have a prefix of 17 bytes followed by one or
386 # resizes. Each entry have a prefix of 17 bytes followed by one or
350 # two path names. Studies on various large-scale real-world repositories
387 # two path names. Studies on various large-scale real-world repositories
351 # found 54 bytes a reasonable upper limit for the average path names.
388 # found 54 bytes a reasonable upper limit for the average path names.
352 # Copy entries are ignored for the sake of this estimate.
389 # Copy entries are ignored for the sake of this estimate.
353 self._map = parsers.dict_new_presized(len(st) // 71)
390 self._map = parsers.dict_new_presized(len(st) // 71)
354
391
355 # Python's garbage collector triggers a GC each time a certain number
392 # Python's garbage collector triggers a GC each time a certain number
356 # of container objects (the number being defined by
393 # of container objects (the number being defined by
357 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
394 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
358 # for each file in the dirstate. The C version then immediately marks
395 # for each file in the dirstate. The C version then immediately marks
359 # them as not to be tracked by the collector. However, this has no
396 # them as not to be tracked by the collector. However, this has no
360 # effect on when GCs are triggered, only on what objects the GC looks
397 # effect on when GCs are triggered, only on what objects the GC looks
361 # into. This means that O(number of files) GCs are unavoidable.
398 # into. This means that O(number of files) GCs are unavoidable.
362 # Depending on when in the process's lifetime the dirstate is parsed,
399 # Depending on when in the process's lifetime the dirstate is parsed,
363 # this can get very expensive. As a workaround, disable GC while
400 # this can get very expensive. As a workaround, disable GC while
364 # parsing the dirstate.
401 # parsing the dirstate.
365 #
402 #
366 # (we cannot decorate the function directly since it is in a C module)
403 # (we cannot decorate the function directly since it is in a C module)
367 if self._use_dirstate_v2:
404 if self._use_dirstate_v2:
368 p = self.docket.parents
405 try:
369 meta = self.docket.tree_metadata
406 self.docket
370 parse_dirstate = util.nogc(v2.parse_dirstate)
407 except error.CorruptedDirstate:
371 parse_dirstate(self._map, self.copymap, st, meta)
408 # fall back to dirstate-v1 if we fail to parse v2
409 parse_dirstate = util.nogc(parsers.parse_dirstate)
410 p = parse_dirstate(self._map, self.copymap, st)
411 else:
412 p = self.docket.parents
413 meta = self.docket.tree_metadata
414 parse_dirstate = util.nogc(v2.parse_dirstate)
415 parse_dirstate(self._map, self.copymap, st, meta)
372 else:
416 else:
373 parse_dirstate = util.nogc(parsers.parse_dirstate)
417 parse_dirstate = util.nogc(parsers.parse_dirstate)
374 p = parse_dirstate(self._map, self.copymap, st)
418 p = parse_dirstate(self._map, self.copymap, st)
375 if not self._dirtyparents:
419 if not self._dirtyparents:
376 self.setparents(*p)
420 self.setparents(*p)
377
421
378 # Avoid excess attribute lookups by fast pathing certain checks
422 # Avoid excess attribute lookups by fast pathing certain checks
379 self.__contains__ = self._map.__contains__
423 self.__contains__ = self._map.__contains__
380 self.__getitem__ = self._map.__getitem__
424 self.__getitem__ = self._map.__getitem__
381 self.get = self._map.get
425 self.get = self._map.get
382
426
383 def write(self, tr, st):
427 def write(self, tr, st):
384 if self._use_dirstate_v2:
428 if self._use_dirstate_v2:
385 packed, meta = v2.pack_dirstate(self._map, self.copymap)
429 packed, meta = v2.pack_dirstate(self._map, self.copymap)
386 self.write_v2_no_append(tr, st, meta, packed)
430 self.write_v2_no_append(tr, st, meta, packed)
387 else:
431 else:
388 packed = parsers.pack_dirstate(
432 packed = parsers.pack_dirstate(
389 self._map, self.copymap, self.parents()
433 self._map, self.copymap, self.parents()
390 )
434 )
391 st.write(packed)
435 st.write(packed)
392 st.close()
436 st.close()
393 self._dirtyparents = False
437 self._dirtyparents = False
394
438
395 @propertycache
439 @propertycache
396 def identity(self):
440 def identity(self):
397 self._map
441 self._map
398 return self.identity
442 return self.identity
399
443
400 ### code related to maintaining and accessing "extra" property
444 ### code related to maintaining and accessing "extra" property
401 # (e.g. "has_dir")
445 # (e.g. "has_dir")
402
446
403 def _dirs_incr(self, filename, old_entry=None):
447 def _dirs_incr(self, filename, old_entry=None):
404 """increment the dirstate counter if applicable"""
448 """increment the dirstate counter if applicable"""
405 if (
449 if (
406 old_entry is None or old_entry.removed
450 old_entry is None or old_entry.removed
407 ) and "_dirs" in self.__dict__:
451 ) and "_dirs" in self.__dict__:
408 self._dirs.addpath(filename)
452 self._dirs.addpath(filename)
409 if old_entry is None and "_alldirs" in self.__dict__:
453 if old_entry is None and "_alldirs" in self.__dict__:
410 self._alldirs.addpath(filename)
454 self._alldirs.addpath(filename)
411
455
412 def _dirs_decr(self, filename, old_entry=None, remove_variant=False):
456 def _dirs_decr(self, filename, old_entry=None, remove_variant=False):
413 """decrement the dirstate counter if applicable"""
457 """decrement the dirstate counter if applicable"""
414 if old_entry is not None:
458 if old_entry is not None:
415 if "_dirs" in self.__dict__ and not old_entry.removed:
459 if "_dirs" in self.__dict__ and not old_entry.removed:
416 self._dirs.delpath(filename)
460 self._dirs.delpath(filename)
417 if "_alldirs" in self.__dict__ and not remove_variant:
461 if "_alldirs" in self.__dict__ and not remove_variant:
418 self._alldirs.delpath(filename)
462 self._alldirs.delpath(filename)
419 elif remove_variant and "_alldirs" in self.__dict__:
463 elif remove_variant and "_alldirs" in self.__dict__:
420 self._alldirs.addpath(filename)
464 self._alldirs.addpath(filename)
421 if "filefoldmap" in self.__dict__:
465 if "filefoldmap" in self.__dict__:
422 normed = util.normcase(filename)
466 normed = util.normcase(filename)
423 self.filefoldmap.pop(normed, None)
467 self.filefoldmap.pop(normed, None)
424
468
425 @propertycache
469 @propertycache
426 def filefoldmap(self):
470 def filefoldmap(self):
427 """Returns a dictionary mapping normalized case paths to their
471 """Returns a dictionary mapping normalized case paths to their
428 non-normalized versions.
472 non-normalized versions.
429 """
473 """
430 try:
474 try:
431 makefilefoldmap = parsers.make_file_foldmap
475 makefilefoldmap = parsers.make_file_foldmap
432 except AttributeError:
476 except AttributeError:
433 pass
477 pass
434 else:
478 else:
435 return makefilefoldmap(
479 return makefilefoldmap(
436 self._map, util.normcasespec, util.normcasefallback
480 self._map, util.normcasespec, util.normcasefallback
437 )
481 )
438
482
439 f = {}
483 f = {}
440 normcase = util.normcase
484 normcase = util.normcase
441 for name, s in self._map.items():
485 for name, s in self._map.items():
442 if not s.removed:
486 if not s.removed:
443 f[normcase(name)] = name
487 f[normcase(name)] = name
444 f[b'.'] = b'.' # prevents useless util.fspath() invocation
488 f[b'.'] = b'.' # prevents useless util.fspath() invocation
445 return f
489 return f
446
490
447 @propertycache
491 @propertycache
448 def dirfoldmap(self):
492 def dirfoldmap(self):
449 f = {}
493 f = {}
450 normcase = util.normcase
494 normcase = util.normcase
451 for name in self._dirs:
495 for name in self._dirs:
452 f[normcase(name)] = name
496 f[normcase(name)] = name
453 return f
497 return f
454
498
455 def hastrackeddir(self, d):
499 def hastrackeddir(self, d):
456 """
500 """
457 Returns True if the dirstate contains a tracked (not removed) file
501 Returns True if the dirstate contains a tracked (not removed) file
458 in this directory.
502 in this directory.
459 """
503 """
460 return d in self._dirs
504 return d in self._dirs
461
505
462 def hasdir(self, d):
506 def hasdir(self, d):
463 """
507 """
464 Returns True if the dirstate contains a file (tracked or removed)
508 Returns True if the dirstate contains a file (tracked or removed)
465 in this directory.
509 in this directory.
466 """
510 """
467 return d in self._alldirs
511 return d in self._alldirs
468
512
469 @propertycache
513 @propertycache
470 def _dirs(self):
514 def _dirs(self):
471 return pathutil.dirs(self._map, only_tracked=True)
515 return pathutil.dirs(self._map, only_tracked=True)
472
516
473 @propertycache
517 @propertycache
474 def _alldirs(self):
518 def _alldirs(self):
475 return pathutil.dirs(self._map)
519 return pathutil.dirs(self._map)
476
520
477 ### code related to manipulation of entries and copy-sources
521 ### code related to manipulation of entries and copy-sources
478
522
479 def reset_state(
523 def reset_state(
480 self,
524 self,
481 filename,
525 filename,
482 wc_tracked=False,
526 wc_tracked=False,
483 p1_tracked=False,
527 p1_tracked=False,
484 p2_info=False,
528 p2_info=False,
485 has_meaningful_mtime=True,
529 has_meaningful_mtime=True,
486 parentfiledata=None,
530 parentfiledata=None,
487 ):
531 ):
488 """Set a entry to a given state, diregarding all previous state
532 """Set a entry to a given state, diregarding all previous state
489
533
490 This is to be used by the part of the dirstate API dedicated to
534 This is to be used by the part of the dirstate API dedicated to
491 adjusting the dirstate after a update/merge.
535 adjusting the dirstate after a update/merge.
492
536
493 note: calling this might result to no entry existing at all if the
537 note: calling this might result to no entry existing at all if the
494 dirstate map does not see any point at having one for this file
538 dirstate map does not see any point at having one for this file
495 anymore.
539 anymore.
496 """
540 """
497 # copy information are now outdated
541 # copy information are now outdated
498 # (maybe new information should be in directly passed to this function)
542 # (maybe new information should be in directly passed to this function)
499 self.copymap.pop(filename, None)
543 self.copymap.pop(filename, None)
500
544
501 if not (p1_tracked or p2_info or wc_tracked):
545 if not (p1_tracked or p2_info or wc_tracked):
502 old_entry = self._map.get(filename)
546 old_entry = self._map.get(filename)
503 self._drop_entry(filename)
547 self._drop_entry(filename)
504 self._dirs_decr(filename, old_entry=old_entry)
548 self._dirs_decr(filename, old_entry=old_entry)
505 return
549 return
506
550
507 old_entry = self._map.get(filename)
551 old_entry = self._map.get(filename)
508 self._dirs_incr(filename, old_entry)
552 self._dirs_incr(filename, old_entry)
509 entry = DirstateItem(
553 entry = DirstateItem(
510 wc_tracked=wc_tracked,
554 wc_tracked=wc_tracked,
511 p1_tracked=p1_tracked,
555 p1_tracked=p1_tracked,
512 p2_info=p2_info,
556 p2_info=p2_info,
513 has_meaningful_mtime=has_meaningful_mtime,
557 has_meaningful_mtime=has_meaningful_mtime,
514 parentfiledata=parentfiledata,
558 parentfiledata=parentfiledata,
515 )
559 )
516 self._map[filename] = entry
560 self._map[filename] = entry
517
561
518 def set_tracked(self, filename):
562 def set_tracked(self, filename):
519 new = False
563 new = False
520 entry = self.get(filename)
564 entry = self.get(filename)
521 if entry is None:
565 if entry is None:
522 self._dirs_incr(filename)
566 self._dirs_incr(filename)
523 entry = DirstateItem(
567 entry = DirstateItem(
524 wc_tracked=True,
568 wc_tracked=True,
525 )
569 )
526
570
527 self._map[filename] = entry
571 self._map[filename] = entry
528 new = True
572 new = True
529 elif not entry.tracked:
573 elif not entry.tracked:
530 self._dirs_incr(filename, entry)
574 self._dirs_incr(filename, entry)
531 entry.set_tracked()
575 entry.set_tracked()
532 self._refresh_entry(filename, entry)
576 self._refresh_entry(filename, entry)
533 new = True
577 new = True
534 else:
578 else:
535 # XXX This is probably overkill for more case, but we need this to
579 # XXX This is probably overkill for more case, but we need this to
536 # fully replace the `normallookup` call with `set_tracked` one.
580 # fully replace the `normallookup` call with `set_tracked` one.
537 # Consider smoothing this in the future.
581 # Consider smoothing this in the future.
538 entry.set_possibly_dirty()
582 entry.set_possibly_dirty()
539 self._refresh_entry(filename, entry)
583 self._refresh_entry(filename, entry)
540 return new
584 return new
541
585
542 def set_untracked(self, f):
586 def set_untracked(self, f):
543 """Mark a file as no longer tracked in the dirstate map"""
587 """Mark a file as no longer tracked in the dirstate map"""
544 entry = self.get(f)
588 entry = self.get(f)
545 if entry is None:
589 if entry is None:
546 return False
590 return False
547 else:
591 else:
548 self._dirs_decr(f, old_entry=entry, remove_variant=not entry.added)
592 self._dirs_decr(f, old_entry=entry, remove_variant=not entry.added)
549 if not entry.p2_info:
593 if not entry.p2_info:
550 self.copymap.pop(f, None)
594 self.copymap.pop(f, None)
551 entry.set_untracked()
595 entry.set_untracked()
552 self._refresh_entry(f, entry)
596 self._refresh_entry(f, entry)
553 return True
597 return True
554
598
555 def set_clean(self, filename, mode, size, mtime):
599 def set_clean(self, filename, mode, size, mtime):
556 """mark a file as back to a clean state"""
600 """mark a file as back to a clean state"""
557 entry = self[filename]
601 entry = self[filename]
558 size = size & rangemask
602 size = size & rangemask
559 entry.set_clean(mode, size, mtime)
603 entry.set_clean(mode, size, mtime)
560 self._refresh_entry(filename, entry)
604 self._refresh_entry(filename, entry)
561 self.copymap.pop(filename, None)
605 self.copymap.pop(filename, None)
562
606
563 def set_possibly_dirty(self, filename):
607 def set_possibly_dirty(self, filename):
564 """record that the current state of the file on disk is unknown"""
608 """record that the current state of the file on disk is unknown"""
565 entry = self[filename]
609 entry = self[filename]
566 entry.set_possibly_dirty()
610 entry.set_possibly_dirty()
567 self._refresh_entry(filename, entry)
611 self._refresh_entry(filename, entry)
568
612
569 def _refresh_entry(self, f, entry):
613 def _refresh_entry(self, f, entry):
570 """record updated state of an entry"""
614 """record updated state of an entry"""
571 if not entry.any_tracked:
615 if not entry.any_tracked:
572 self._map.pop(f, None)
616 self._map.pop(f, None)
573
617
574 def _drop_entry(self, f):
618 def _drop_entry(self, f):
575 """remove any entry for file f
619 """remove any entry for file f
576
620
577 This should also drop associated copy information
621 This should also drop associated copy information
578
622
579 The fact we actually need to drop it is the responsability of the caller"""
623 The fact we actually need to drop it is the responsability of the caller"""
580 self._map.pop(f, None)
624 self._map.pop(f, None)
581 self.copymap.pop(f, None)
625 self.copymap.pop(f, None)
582
626
583
627
584 if rustmod is not None:
628 if rustmod is not None:
585
629
586 class dirstatemap(_dirstatemapcommon):
630 class dirstatemap(_dirstatemapcommon):
587
631
588 ### Core data storage and access
632 ### Core data storage and access
589
633
590 @propertycache
634 @propertycache
591 def _map(self):
635 def _map(self):
592 """
636 """
593 Fills the Dirstatemap when called.
637 Fills the Dirstatemap when called.
594 """
638 """
595 # ignore HG_PENDING because identity is used only for writing
639 # ignore HG_PENDING because identity is used only for writing
596 self._set_identity()
640 self._set_identity()
597
641
598 testing.wait_on_cfg(self._ui, b'dirstate.pre-read-file')
642 testing.wait_on_cfg(self._ui, b'dirstate.pre-read-file')
599 if self._use_dirstate_v2:
643 if self._use_dirstate_v2:
600 self.docket # load the data if needed
644 try:
601 inode = (
645 self.docket
602 self.identity.stat.st_ino
646 except error.CorruptedDirstate as e:
603 if self.identity is not None
647 # fall back to dirstate-v1 if we fail to read v2
604 and self.identity.stat is not None
648 parents = self._v1_map(e)
605 else None
606 )
607 testing.wait_on_cfg(self._ui, b'dirstate.post-docket-read-file')
608 if not self.docket.uuid:
609 data = b''
610 self._map = rustmod.DirstateMap.new_empty()
611 else:
649 else:
612 data = self._read_v2_data()
650 parents = self.docket.parents
613 self._map = rustmod.DirstateMap.new_v2(
651 inode = (
614 data,
652 self.identity.stat.st_ino
615 self.docket.data_size,
653 if self.identity is not None
616 self.docket.tree_metadata,
654 and self.identity.stat is not None
617 self.docket.uuid,
655 else None
618 inode,
656 )
657 testing.wait_on_cfg(
658 self._ui, b'dirstate.post-docket-read-file'
619 )
659 )
620 parents = self.docket.parents
660 if not self.docket.uuid:
661 data = b''
662 self._map = rustmod.DirstateMap.new_empty()
663 else:
664 data = self._read_v2_data()
665 self._map = rustmod.DirstateMap.new_v2(
666 data,
667 self.docket.data_size,
668 self.docket.tree_metadata,
669 self.docket.uuid,
670 inode,
671 )
672 parents = self.docket.parents
621 else:
673 else:
622 self._set_identity()
674 parents = self._v1_map()
623 inode = (
624 self.identity.stat.st_ino
625 if self.identity is not None
626 and self.identity.stat is not None
627 else None
628 )
629 self._map, parents = rustmod.DirstateMap.new_v1(
630 self._readdirstatefile(), inode
631 )
632
675
633 if parents and not self._dirtyparents:
676 if parents and not self._dirtyparents:
634 self.setparents(*parents)
677 self.setparents(*parents)
635
678
636 self.__contains__ = self._map.__contains__
679 self.__contains__ = self._map.__contains__
637 self.__getitem__ = self._map.__getitem__
680 self.__getitem__ = self._map.__getitem__
638 self.get = self._map.get
681 self.get = self._map.get
639 return self._map
682 return self._map
640
683
684 def _v1_map(self, from_v2_exception=None):
685 self._set_identity()
686 inode = (
687 self.identity.stat.st_ino
688 if self.identity is not None and self.identity.stat is not None
689 else None
690 )
691 try:
692 self._map, parents = rustmod.DirstateMap.new_v1(
693 self._readdirstatefile(), inode
694 )
695 except OSError as e:
696 if from_v2_exception is not None:
697 raise e from from_v2_exception
698 raise
699 return parents
700
641 @property
701 @property
642 def copymap(self):
702 def copymap(self):
643 return self._map.copymap()
703 return self._map.copymap()
644
704
645 def debug_iter(self, all):
705 def debug_iter(self, all):
646 """
706 """
647 Return an iterator of (filename, state, mode, size, mtime) tuples
707 Return an iterator of (filename, state, mode, size, mtime) tuples
648
708
649 `all`: also include with `state == b' '` dirstate tree nodes that
709 `all`: also include with `state == b' '` dirstate tree nodes that
650 don't have an associated `DirstateItem`.
710 don't have an associated `DirstateItem`.
651
711
652 """
712 """
653 return self._map.debug_iter(all)
713 return self._map.debug_iter(all)
654
714
655 def clear(self):
715 def clear(self):
656 self._map.clear()
716 self._map.clear()
657 self.setparents(
717 self.setparents(
658 self._nodeconstants.nullid, self._nodeconstants.nullid
718 self._nodeconstants.nullid, self._nodeconstants.nullid
659 )
719 )
660 util.clearcachedproperty(self, b"_dirs")
720 util.clearcachedproperty(self, b"_dirs")
661 util.clearcachedproperty(self, b"_alldirs")
721 util.clearcachedproperty(self, b"_alldirs")
662 util.clearcachedproperty(self, b"dirfoldmap")
722 util.clearcachedproperty(self, b"dirfoldmap")
663
723
664 def items(self):
724 def items(self):
665 return self._map.items()
725 return self._map.items()
666
726
667 # forward for python2,3 compat
727 # forward for python2,3 compat
668 iteritems = items
728 iteritems = items
669
729
670 def keys(self):
730 def keys(self):
671 return iter(self._map)
731 return iter(self._map)
672
732
673 ### reading/setting parents
733 ### reading/setting parents
674
734
675 def setparents(self, p1, p2, fold_p2=False):
735 def setparents(self, p1, p2, fold_p2=False):
676 self._parents = (p1, p2)
736 self._parents = (p1, p2)
677 self._dirtyparents = True
737 self._dirtyparents = True
678 copies = {}
738 copies = {}
679 if fold_p2:
739 if fold_p2:
680 copies = self._map.setparents_fixup()
740 copies = self._map.setparents_fixup()
681 return copies
741 return copies
682
742
683 ### disk interaction
743 ### disk interaction
684
744
685 @propertycache
745 @propertycache
686 def identity(self):
746 def identity(self):
687 self._map
747 self._map
688 return self.identity
748 return self.identity
689
749
690 def write(self, tr, st):
750 def write(self, tr, st):
691 if not self._use_dirstate_v2:
751 if not self._use_dirstate_v2:
692 p1, p2 = self.parents()
752 p1, p2 = self.parents()
693 packed = self._map.write_v1(p1, p2)
753 packed = self._map.write_v1(p1, p2)
694 st.write(packed)
754 st.write(packed)
695 st.close()
755 st.close()
696 self._dirtyparents = False
756 self._dirtyparents = False
697 return
757 return
698
758
759 write_mode = self._write_mode
760 try:
761 docket = self.docket
762 except error.CorruptedDirstate:
763 # fall back to dirstate-v1 if we fail to parse v2
764 docket = None
765
699 # We can only append to an existing data file if there is one
766 # We can only append to an existing data file if there is one
700 write_mode = self._write_mode
767 if docket is None or docket.uuid is None:
701 if self.docket.uuid is None:
702 write_mode = WRITE_MODE_FORCE_NEW
768 write_mode = WRITE_MODE_FORCE_NEW
703 packed, meta, append = self._map.write_v2(write_mode)
769 packed, meta, append = self._map.write_v2(write_mode)
704 if append:
770 if append:
705 docket = self.docket
771 docket = self.docket
706 data_filename = docket.data_filename()
772 data_filename = docket.data_filename()
707 # We mark it for backup to make sure a future `hg rollback` (or
773 # We mark it for backup to make sure a future `hg rollback` (or
708 # `hg recover`?) call find the data it needs to restore a
774 # `hg recover`?) call find the data it needs to restore a
709 # working repository.
775 # working repository.
710 #
776 #
711 # The backup can use a hardlink because the format is resistant
777 # The backup can use a hardlink because the format is resistant
712 # to trailing "dead" data.
778 # to trailing "dead" data.
713 if tr is not None:
779 if tr is not None:
714 tr.addbackup(data_filename, location=b'plain')
780 tr.addbackup(data_filename, location=b'plain')
715 with self._opener(data_filename, b'r+b') as fp:
781 with self._opener(data_filename, b'r+b') as fp:
716 fp.seek(docket.data_size)
782 fp.seek(docket.data_size)
717 assert fp.tell() == docket.data_size
783 assert fp.tell() == docket.data_size
718 written = fp.write(packed)
784 written = fp.write(packed)
719 if written is not None: # py2 may return None
785 if written is not None: # py2 may return None
720 assert written == len(packed), (written, len(packed))
786 assert written == len(packed), (written, len(packed))
721 docket.data_size += len(packed)
787 docket.data_size += len(packed)
722 docket.parents = self.parents()
788 docket.parents = self.parents()
723 docket.tree_metadata = meta
789 docket.tree_metadata = meta
724 st.write(docket.serialize())
790 st.write(docket.serialize())
725 st.close()
791 st.close()
726 else:
792 else:
727 self.write_v2_no_append(tr, st, meta, packed)
793 self.write_v2_no_append(tr, st, meta, packed)
728 # Reload from the newly-written file
794 # Reload from the newly-written file
729 util.clearcachedproperty(self, b"_map")
795 util.clearcachedproperty(self, b"_map")
730 self._dirtyparents = False
796 self._dirtyparents = False
731
797
732 ### code related to maintaining and accessing "extra" property
798 ### code related to maintaining and accessing "extra" property
733 # (e.g. "has_dir")
799 # (e.g. "has_dir")
734
800
735 @propertycache
801 @propertycache
736 def filefoldmap(self):
802 def filefoldmap(self):
737 """Returns a dictionary mapping normalized case paths to their
803 """Returns a dictionary mapping normalized case paths to their
738 non-normalized versions.
804 non-normalized versions.
739 """
805 """
740 return self._map.filefoldmapasdict()
806 return self._map.filefoldmapasdict()
741
807
742 def hastrackeddir(self, d):
808 def hastrackeddir(self, d):
743 return self._map.hastrackeddir(d)
809 return self._map.hastrackeddir(d)
744
810
745 def hasdir(self, d):
811 def hasdir(self, d):
746 return self._map.hasdir(d)
812 return self._map.hasdir(d)
747
813
748 @propertycache
814 @propertycache
749 def dirfoldmap(self):
815 def dirfoldmap(self):
750 f = {}
816 f = {}
751 normcase = util.normcase
817 normcase = util.normcase
752 for name in self._map.tracked_dirs():
818 for name in self._map.tracked_dirs():
753 f[normcase(name)] = name
819 f[normcase(name)] = name
754 return f
820 return f
755
821
756 ### code related to manipulation of entries and copy-sources
822 ### code related to manipulation of entries and copy-sources
757
823
758 def set_tracked(self, f):
824 def set_tracked(self, f):
759 return self._map.set_tracked(f)
825 return self._map.set_tracked(f)
760
826
761 def set_untracked(self, f):
827 def set_untracked(self, f):
762 return self._map.set_untracked(f)
828 return self._map.set_untracked(f)
763
829
764 def set_clean(self, filename, mode, size, mtime):
830 def set_clean(self, filename, mode, size, mtime):
765 self._map.set_clean(filename, mode, size, mtime)
831 self._map.set_clean(filename, mode, size, mtime)
766
832
767 def set_possibly_dirty(self, f):
833 def set_possibly_dirty(self, f):
768 self._map.set_possibly_dirty(f)
834 self._map.set_possibly_dirty(f)
769
835
770 def reset_state(
836 def reset_state(
771 self,
837 self,
772 filename,
838 filename,
773 wc_tracked=False,
839 wc_tracked=False,
774 p1_tracked=False,
840 p1_tracked=False,
775 p2_info=False,
841 p2_info=False,
776 has_meaningful_mtime=True,
842 has_meaningful_mtime=True,
777 parentfiledata=None,
843 parentfiledata=None,
778 ):
844 ):
779 return self._map.reset_state(
845 return self._map.reset_state(
780 filename,
846 filename,
781 wc_tracked,
847 wc_tracked,
782 p1_tracked,
848 p1_tracked,
783 p2_info,
849 p2_info,
784 has_meaningful_mtime,
850 has_meaningful_mtime,
785 parentfiledata,
851 parentfiledata,
786 )
852 )
@@ -1,674 +1,681 b''
1 # error.py - Mercurial exceptions
1 # error.py - Mercurial exceptions
2 #
2 #
3 # Copyright 2005-2008 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2008 Olivia Mackall <olivia@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 """Mercurial exceptions.
8 """Mercurial exceptions.
9
9
10 This allows us to catch exceptions at higher levels without forcing
10 This allows us to catch exceptions at higher levels without forcing
11 imports.
11 imports.
12 """
12 """
13
13
14
14
15 import difflib
15 import difflib
16
16
17 # Do not import anything but pycompat here, please
17 # Do not import anything but pycompat here, please
18 from . import pycompat
18 from . import pycompat
19
19
20 if pycompat.TYPE_CHECKING:
20 if pycompat.TYPE_CHECKING:
21 from typing import (
21 from typing import (
22 Any,
22 Any,
23 AnyStr,
23 AnyStr,
24 Iterable,
24 Iterable,
25 List,
25 List,
26 Optional,
26 Optional,
27 Sequence,
27 Sequence,
28 Union,
28 Union,
29 )
29 )
30
30
31
31
32 def _tobytes(exc):
32 def _tobytes(exc):
33 # type: (...) -> bytes
33 # type: (...) -> bytes
34 """Byte-stringify exception in the same way as BaseException_str()"""
34 """Byte-stringify exception in the same way as BaseException_str()"""
35 if not exc.args:
35 if not exc.args:
36 return b''
36 return b''
37 if len(exc.args) == 1:
37 if len(exc.args) == 1:
38 return pycompat.bytestr(exc.args[0])
38 return pycompat.bytestr(exc.args[0])
39 return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args)
39 return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args)
40
40
41
41
42 class Hint:
42 class Hint:
43 """Mix-in to provide a hint of an error
43 """Mix-in to provide a hint of an error
44
44
45 This should come first in the inheritance list to consume a hint and
45 This should come first in the inheritance list to consume a hint and
46 pass remaining arguments to the exception class.
46 pass remaining arguments to the exception class.
47 """
47 """
48
48
49 def __init__(self, *args, **kw):
49 def __init__(self, *args, **kw):
50 self.hint = kw.pop('hint', None) # type: Optional[bytes]
50 self.hint = kw.pop('hint', None) # type: Optional[bytes]
51 super(Hint, self).__init__(*args, **kw)
51 super(Hint, self).__init__(*args, **kw)
52
52
53
53
54 class Error(Hint, Exception):
54 class Error(Hint, Exception):
55 """Base class for Mercurial errors."""
55 """Base class for Mercurial errors."""
56
56
57 coarse_exit_code = None
57 coarse_exit_code = None
58 detailed_exit_code = None
58 detailed_exit_code = None
59
59
60 def __init__(self, message, hint=None):
60 def __init__(self, message, hint=None):
61 # type: (bytes, Optional[bytes]) -> None
61 # type: (bytes, Optional[bytes]) -> None
62 self.message = message
62 self.message = message
63 self.hint = hint
63 self.hint = hint
64 # Pass the message into the Exception constructor to help extensions
64 # Pass the message into the Exception constructor to help extensions
65 # that look for exc.args[0].
65 # that look for exc.args[0].
66 Exception.__init__(self, message)
66 Exception.__init__(self, message)
67
67
68 def __bytes__(self):
68 def __bytes__(self):
69 return self.message
69 return self.message
70
70
71 def __str__(self):
71 def __str__(self):
72 # type: () -> str
72 # type: () -> str
73 # the output would be unreadable if the message was translated,
73 # the output would be unreadable if the message was translated,
74 # but do not replace it with encoding.strfromlocal(), which
74 # but do not replace it with encoding.strfromlocal(), which
75 # may raise another exception.
75 # may raise another exception.
76 return pycompat.sysstr(self.__bytes__())
76 return pycompat.sysstr(self.__bytes__())
77
77
78 def format(self):
78 def format(self):
79 # type: () -> bytes
79 # type: () -> bytes
80 from .i18n import _
80 from .i18n import _
81
81
82 message = _(b"abort: %s\n") % self.message
82 message = _(b"abort: %s\n") % self.message
83 if self.hint:
83 if self.hint:
84 message += _(b"(%s)\n") % self.hint
84 message += _(b"(%s)\n") % self.hint
85 return message
85 return message
86
86
87
87
88 class Abort(Error):
88 class Abort(Error):
89 """Raised if a command needs to print an error and exit."""
89 """Raised if a command needs to print an error and exit."""
90
90
91
91
92 class StorageError(Error):
92 class StorageError(Error):
93 """Raised when an error occurs in a storage layer.
93 """Raised when an error occurs in a storage layer.
94
94
95 Usually subclassed by a storage-specific exception.
95 Usually subclassed by a storage-specific exception.
96 """
96 """
97
97
98 detailed_exit_code = 50
98 detailed_exit_code = 50
99
99
100
100
101 class RevlogError(StorageError):
101 class RevlogError(StorageError):
102 pass
102 pass
103
103
104
104
105 class SidedataHashError(RevlogError):
105 class SidedataHashError(RevlogError):
106 def __init__(self, key, expected, got):
106 def __init__(self, key, expected, got):
107 # type: (int, bytes, bytes) -> None
107 # type: (int, bytes, bytes) -> None
108 self.hint = None
108 self.hint = None
109 self.sidedatakey = key
109 self.sidedatakey = key
110 self.expecteddigest = expected
110 self.expecteddigest = expected
111 self.actualdigest = got
111 self.actualdigest = got
112
112
113
113
114 class FilteredIndexError(IndexError):
114 class FilteredIndexError(IndexError):
115 __bytes__ = _tobytes
115 __bytes__ = _tobytes
116
116
117
117
118 class LookupError(RevlogError, KeyError):
118 class LookupError(RevlogError, KeyError):
119 def __init__(self, name, index, message):
119 def __init__(self, name, index, message):
120 # type: (bytes, bytes, bytes) -> None
120 # type: (bytes, bytes, bytes) -> None
121 self.name = name
121 self.name = name
122 self.index = index
122 self.index = index
123 # this can't be called 'message' because at least some installs of
123 # this can't be called 'message' because at least some installs of
124 # Python 2.6+ complain about the 'message' property being deprecated
124 # Python 2.6+ complain about the 'message' property being deprecated
125 self.lookupmessage = message
125 self.lookupmessage = message
126 if isinstance(name, bytes) and len(name) == 20:
126 if isinstance(name, bytes) and len(name) == 20:
127 from .node import hex
127 from .node import hex
128
128
129 name = hex(name)
129 name = hex(name)
130 # if name is a binary node, it can be None
130 # if name is a binary node, it can be None
131 RevlogError.__init__(
131 RevlogError.__init__(
132 self, b'%s@%s: %s' % (index, pycompat.bytestr(name), message)
132 self, b'%s@%s: %s' % (index, pycompat.bytestr(name), message)
133 )
133 )
134
134
135 def __bytes__(self):
135 def __bytes__(self):
136 return RevlogError.__bytes__(self)
136 return RevlogError.__bytes__(self)
137
137
138 def __str__(self):
138 def __str__(self):
139 return RevlogError.__str__(self)
139 return RevlogError.__str__(self)
140
140
141
141
142 class AmbiguousPrefixLookupError(LookupError):
142 class AmbiguousPrefixLookupError(LookupError):
143 pass
143 pass
144
144
145
145
146 class FilteredLookupError(LookupError):
146 class FilteredLookupError(LookupError):
147 pass
147 pass
148
148
149
149
150 class ManifestLookupError(LookupError):
150 class ManifestLookupError(LookupError):
151 pass
151 pass
152
152
153
153
154 class CommandError(Exception):
154 class CommandError(Exception):
155 """Exception raised on errors in parsing the command line."""
155 """Exception raised on errors in parsing the command line."""
156
156
157 def __init__(self, command, message):
157 def __init__(self, command, message):
158 # type: (Optional[bytes], bytes) -> None
158 # type: (Optional[bytes], bytes) -> None
159 self.command = command
159 self.command = command
160 self.message = message
160 self.message = message
161 super(CommandError, self).__init__()
161 super(CommandError, self).__init__()
162
162
163 __bytes__ = _tobytes
163 __bytes__ = _tobytes
164
164
165
165
166 class UnknownCommand(Exception):
166 class UnknownCommand(Exception):
167 """Exception raised if command is not in the command table."""
167 """Exception raised if command is not in the command table."""
168
168
169 def __init__(self, command, all_commands=None):
169 def __init__(self, command, all_commands=None):
170 # type: (bytes, Optional[List[bytes]]) -> None
170 # type: (bytes, Optional[List[bytes]]) -> None
171 self.command = command
171 self.command = command
172 self.all_commands = all_commands
172 self.all_commands = all_commands
173 super(UnknownCommand, self).__init__()
173 super(UnknownCommand, self).__init__()
174
174
175 __bytes__ = _tobytes
175 __bytes__ = _tobytes
176
176
177
177
178 class AmbiguousCommand(Exception):
178 class AmbiguousCommand(Exception):
179 """Exception raised if command shortcut matches more than one command."""
179 """Exception raised if command shortcut matches more than one command."""
180
180
181 def __init__(self, prefix, matches):
181 def __init__(self, prefix, matches):
182 # type: (bytes, List[bytes]) -> None
182 # type: (bytes, List[bytes]) -> None
183 self.prefix = prefix
183 self.prefix = prefix
184 self.matches = matches
184 self.matches = matches
185 super(AmbiguousCommand, self).__init__()
185 super(AmbiguousCommand, self).__init__()
186
186
187 __bytes__ = _tobytes
187 __bytes__ = _tobytes
188
188
189
189
190 class WorkerError(Exception):
190 class WorkerError(Exception):
191 """Exception raised when a worker process dies."""
191 """Exception raised when a worker process dies."""
192
192
193 def __init__(self, status_code):
193 def __init__(self, status_code):
194 # type: (int) -> None
194 # type: (int) -> None
195 self.status_code = status_code
195 self.status_code = status_code
196 # Pass status code to superclass just so it becomes part of __bytes__
196 # Pass status code to superclass just so it becomes part of __bytes__
197 super(WorkerError, self).__init__(status_code)
197 super(WorkerError, self).__init__(status_code)
198
198
199 __bytes__ = _tobytes
199 __bytes__ = _tobytes
200
200
201
201
202 class InterventionRequired(Abort):
202 class InterventionRequired(Abort):
203 """Exception raised when a command requires human intervention."""
203 """Exception raised when a command requires human intervention."""
204
204
205 coarse_exit_code = 1
205 coarse_exit_code = 1
206 detailed_exit_code = 240
206 detailed_exit_code = 240
207
207
208 def format(self):
208 def format(self):
209 # type: () -> bytes
209 # type: () -> bytes
210 from .i18n import _
210 from .i18n import _
211
211
212 message = _(b"%s\n") % self.message
212 message = _(b"%s\n") % self.message
213 if self.hint:
213 if self.hint:
214 message += _(b"(%s)\n") % self.hint
214 message += _(b"(%s)\n") % self.hint
215 return message
215 return message
216
216
217
217
218 class ConflictResolutionRequired(InterventionRequired):
218 class ConflictResolutionRequired(InterventionRequired):
219 """Exception raised when a continuable command required merge conflict resolution."""
219 """Exception raised when a continuable command required merge conflict resolution."""
220
220
221 def __init__(self, opname):
221 def __init__(self, opname):
222 # type: (bytes) -> None
222 # type: (bytes) -> None
223 from .i18n import _
223 from .i18n import _
224
224
225 self.opname = opname
225 self.opname = opname
226 InterventionRequired.__init__(
226 InterventionRequired.__init__(
227 self,
227 self,
228 _(
228 _(
229 b"unresolved conflicts (see 'hg resolve', then 'hg %s --continue')"
229 b"unresolved conflicts (see 'hg resolve', then 'hg %s --continue')"
230 )
230 )
231 % opname,
231 % opname,
232 )
232 )
233
233
234
234
235 class InputError(Abort):
235 class InputError(Abort):
236 """Indicates that the user made an error in their input.
236 """Indicates that the user made an error in their input.
237
237
238 Examples: Invalid command, invalid flags, invalid revision.
238 Examples: Invalid command, invalid flags, invalid revision.
239 """
239 """
240
240
241 detailed_exit_code = 10
241 detailed_exit_code = 10
242
242
243
243
244 class StateError(Abort):
244 class StateError(Abort):
245 """Indicates that the operation might work if retried in a different state.
245 """Indicates that the operation might work if retried in a different state.
246
246
247 Examples: Unresolved merge conflicts, unfinished operations.
247 Examples: Unresolved merge conflicts, unfinished operations.
248 """
248 """
249
249
250 detailed_exit_code = 20
250 detailed_exit_code = 20
251
251
252
252
253 class CanceledError(Abort):
253 class CanceledError(Abort):
254 """Indicates that the user canceled the operation.
254 """Indicates that the user canceled the operation.
255
255
256 Examples: Close commit editor with error status, quit chistedit.
256 Examples: Close commit editor with error status, quit chistedit.
257 """
257 """
258
258
259 detailed_exit_code = 250
259 detailed_exit_code = 250
260
260
261
261
262 class SecurityError(Abort):
262 class SecurityError(Abort):
263 """Indicates that some aspect of security failed.
263 """Indicates that some aspect of security failed.
264
264
265 Examples: Bad server credentials, expired local credentials for network
265 Examples: Bad server credentials, expired local credentials for network
266 filesystem, mismatched GPG signature, DoS protection.
266 filesystem, mismatched GPG signature, DoS protection.
267 """
267 """
268
268
269 detailed_exit_code = 150
269 detailed_exit_code = 150
270
270
271
271
272 class HookLoadError(Abort):
272 class HookLoadError(Abort):
273 """raised when loading a hook fails, aborting an operation
273 """raised when loading a hook fails, aborting an operation
274
274
275 Exists to allow more specialized catching."""
275 Exists to allow more specialized catching."""
276
276
277
277
278 class HookAbort(Abort):
278 class HookAbort(Abort):
279 """raised when a validation hook fails, aborting an operation
279 """raised when a validation hook fails, aborting an operation
280
280
281 Exists to allow more specialized catching."""
281 Exists to allow more specialized catching."""
282
282
283 detailed_exit_code = 40
283 detailed_exit_code = 40
284
284
285
285
286 class ConfigError(Abort):
286 class ConfigError(Abort):
287 """Exception raised when parsing config files"""
287 """Exception raised when parsing config files"""
288
288
289 detailed_exit_code = 30
289 detailed_exit_code = 30
290
290
291 def __init__(self, message, location=None, hint=None):
291 def __init__(self, message, location=None, hint=None):
292 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
292 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
293 super(ConfigError, self).__init__(message, hint=hint)
293 super(ConfigError, self).__init__(message, hint=hint)
294 self.location = location
294 self.location = location
295
295
296 def format(self):
296 def format(self):
297 # type: () -> bytes
297 # type: () -> bytes
298 from .i18n import _
298 from .i18n import _
299
299
300 if self.location is not None:
300 if self.location is not None:
301 message = _(b"config error at %s: %s\n") % (
301 message = _(b"config error at %s: %s\n") % (
302 pycompat.bytestr(self.location),
302 pycompat.bytestr(self.location),
303 self.message,
303 self.message,
304 )
304 )
305 else:
305 else:
306 message = _(b"config error: %s\n") % self.message
306 message = _(b"config error: %s\n") % self.message
307 if self.hint:
307 if self.hint:
308 message += _(b"(%s)\n") % self.hint
308 message += _(b"(%s)\n") % self.hint
309 return message
309 return message
310
310
311
311
312 class UpdateAbort(Abort):
312 class UpdateAbort(Abort):
313 """Raised when an update is aborted for destination issue"""
313 """Raised when an update is aborted for destination issue"""
314
314
315
315
316 class MergeDestAbort(Abort):
316 class MergeDestAbort(Abort):
317 """Raised when an update is aborted for destination issues"""
317 """Raised when an update is aborted for destination issues"""
318
318
319
319
320 class NoMergeDestAbort(MergeDestAbort):
320 class NoMergeDestAbort(MergeDestAbort):
321 """Raised when an update is aborted because there is nothing to merge"""
321 """Raised when an update is aborted because there is nothing to merge"""
322
322
323
323
324 class ManyMergeDestAbort(MergeDestAbort):
324 class ManyMergeDestAbort(MergeDestAbort):
325 """Raised when an update is aborted because destination is ambiguous"""
325 """Raised when an update is aborted because destination is ambiguous"""
326
326
327
327
328 class ResponseExpected(Abort):
328 class ResponseExpected(Abort):
329 """Raised when an EOF is received for a prompt"""
329 """Raised when an EOF is received for a prompt"""
330
330
331 def __init__(self):
331 def __init__(self):
332 from .i18n import _
332 from .i18n import _
333
333
334 Abort.__init__(self, _(b'response expected'))
334 Abort.__init__(self, _(b'response expected'))
335
335
336
336
337 class RemoteError(Abort):
337 class RemoteError(Abort):
338 """Exception raised when interacting with a remote repo fails"""
338 """Exception raised when interacting with a remote repo fails"""
339
339
340 detailed_exit_code = 100
340 detailed_exit_code = 100
341
341
342
342
343 class OutOfBandError(RemoteError):
343 class OutOfBandError(RemoteError):
344 """Exception raised when a remote repo reports failure"""
344 """Exception raised when a remote repo reports failure"""
345
345
346 def __init__(self, message=None, hint=None):
346 def __init__(self, message=None, hint=None):
347 # type: (Optional[bytes], Optional[bytes]) -> None
347 # type: (Optional[bytes], Optional[bytes]) -> None
348 from .i18n import _
348 from .i18n import _
349
349
350 if message:
350 if message:
351 # Abort.format() adds a trailing newline
351 # Abort.format() adds a trailing newline
352 message = _(b"remote error:\n%s") % message.rstrip(b'\n')
352 message = _(b"remote error:\n%s") % message.rstrip(b'\n')
353 else:
353 else:
354 message = _(b"remote error")
354 message = _(b"remote error")
355 super(OutOfBandError, self).__init__(message, hint=hint)
355 super(OutOfBandError, self).__init__(message, hint=hint)
356
356
357
357
358 class ParseError(Abort):
358 class ParseError(Abort):
359 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
359 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
360
360
361 detailed_exit_code = 10
361 detailed_exit_code = 10
362
362
363 def __init__(self, message, location=None, hint=None):
363 def __init__(self, message, location=None, hint=None):
364 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None
364 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None
365 super(ParseError, self).__init__(message, hint=hint)
365 super(ParseError, self).__init__(message, hint=hint)
366 self.location = location
366 self.location = location
367
367
368 def format(self):
368 def format(self):
369 # type: () -> bytes
369 # type: () -> bytes
370 from .i18n import _
370 from .i18n import _
371
371
372 if self.location is not None:
372 if self.location is not None:
373 message = _(b"hg: parse error at %s: %s\n") % (
373 message = _(b"hg: parse error at %s: %s\n") % (
374 pycompat.bytestr(self.location),
374 pycompat.bytestr(self.location),
375 self.message,
375 self.message,
376 )
376 )
377 else:
377 else:
378 message = _(b"hg: parse error: %s\n") % self.message
378 message = _(b"hg: parse error: %s\n") % self.message
379 if self.hint:
379 if self.hint:
380 message += _(b"(%s)\n") % self.hint
380 message += _(b"(%s)\n") % self.hint
381 return message
381 return message
382
382
383
383
384 class PatchError(Exception):
384 class PatchError(Exception):
385 __bytes__ = _tobytes
385 __bytes__ = _tobytes
386
386
387
387
388 class PatchParseError(PatchError):
388 class PatchParseError(PatchError):
389 __bytes__ = _tobytes
389 __bytes__ = _tobytes
390
390
391
391
392 class PatchApplicationError(PatchError):
392 class PatchApplicationError(PatchError):
393 __bytes__ = _tobytes
393 __bytes__ = _tobytes
394
394
395
395
396 def getsimilar(symbols, value):
396 def getsimilar(symbols, value):
397 # type: (Iterable[bytes], bytes) -> List[bytes]
397 # type: (Iterable[bytes], bytes) -> List[bytes]
398 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
398 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
399 # The cutoff for similarity here is pretty arbitrary. It should
399 # The cutoff for similarity here is pretty arbitrary. It should
400 # probably be investigated and tweaked.
400 # probably be investigated and tweaked.
401 return [s for s in symbols if sim(s) > 0.6]
401 return [s for s in symbols if sim(s) > 0.6]
402
402
403
403
404 def similarity_hint(similar):
404 def similarity_hint(similar):
405 # type: (List[bytes]) -> Optional[bytes]
405 # type: (List[bytes]) -> Optional[bytes]
406 from .i18n import _
406 from .i18n import _
407
407
408 if len(similar) == 1:
408 if len(similar) == 1:
409 return _(b"did you mean %s?") % similar[0]
409 return _(b"did you mean %s?") % similar[0]
410 elif similar:
410 elif similar:
411 ss = b", ".join(sorted(similar))
411 ss = b", ".join(sorted(similar))
412 return _(b"did you mean one of %s?") % ss
412 return _(b"did you mean one of %s?") % ss
413 else:
413 else:
414 return None
414 return None
415
415
416
416
417 class UnknownIdentifier(ParseError):
417 class UnknownIdentifier(ParseError):
418 """Exception raised when a {rev,file}set references an unknown identifier"""
418 """Exception raised when a {rev,file}set references an unknown identifier"""
419
419
420 def __init__(self, function, symbols):
420 def __init__(self, function, symbols):
421 # type: (bytes, Iterable[bytes]) -> None
421 # type: (bytes, Iterable[bytes]) -> None
422 from .i18n import _
422 from .i18n import _
423
423
424 similar = getsimilar(symbols, function)
424 similar = getsimilar(symbols, function)
425 hint = similarity_hint(similar)
425 hint = similarity_hint(similar)
426
426
427 ParseError.__init__(
427 ParseError.__init__(
428 self, _(b"unknown identifier: %s") % function, hint=hint
428 self, _(b"unknown identifier: %s") % function, hint=hint
429 )
429 )
430
430
431
431
432 class RepoError(Hint, Exception):
432 class RepoError(Hint, Exception):
433 __bytes__ = _tobytes
433 __bytes__ = _tobytes
434
434
435
435
436 class RepoLookupError(RepoError):
436 class RepoLookupError(RepoError):
437 pass
437 pass
438
438
439
439
440 class FilteredRepoLookupError(RepoLookupError):
440 class FilteredRepoLookupError(RepoLookupError):
441 pass
441 pass
442
442
443
443
444 class CapabilityError(RepoError):
444 class CapabilityError(RepoError):
445 pass
445 pass
446
446
447
447
448 class RequirementError(RepoError):
448 class RequirementError(RepoError):
449 """Exception raised if .hg/requires has an unknown entry."""
449 """Exception raised if .hg/requires has an unknown entry."""
450
450
451
451
452 class StdioError(IOError):
452 class StdioError(IOError):
453 """Raised if I/O to stdout or stderr fails"""
453 """Raised if I/O to stdout or stderr fails"""
454
454
455 def __init__(self, err):
455 def __init__(self, err):
456 # type: (IOError) -> None
456 # type: (IOError) -> None
457 IOError.__init__(self, err.errno, err.strerror)
457 IOError.__init__(self, err.errno, err.strerror)
458
458
459 # no __bytes__() because error message is derived from the standard IOError
459 # no __bytes__() because error message is derived from the standard IOError
460
460
461
461
462 class UnsupportedMergeRecords(Abort):
462 class UnsupportedMergeRecords(Abort):
463 def __init__(self, recordtypes):
463 def __init__(self, recordtypes):
464 # type: (Iterable[bytes]) -> None
464 # type: (Iterable[bytes]) -> None
465 from .i18n import _
465 from .i18n import _
466
466
467 self.recordtypes = sorted(recordtypes)
467 self.recordtypes = sorted(recordtypes)
468 s = b' '.join(self.recordtypes)
468 s = b' '.join(self.recordtypes)
469 Abort.__init__(
469 Abort.__init__(
470 self,
470 self,
471 _(b'unsupported merge state records: %s') % s,
471 _(b'unsupported merge state records: %s') % s,
472 hint=_(
472 hint=_(
473 b'see https://mercurial-scm.org/wiki/MergeStateRecords for '
473 b'see https://mercurial-scm.org/wiki/MergeStateRecords for '
474 b'more information'
474 b'more information'
475 ),
475 ),
476 )
476 )
477
477
478
478
479 class UnknownVersion(Abort):
479 class UnknownVersion(Abort):
480 """generic exception for aborting from an encounter with an unknown version"""
480 """generic exception for aborting from an encounter with an unknown version"""
481
481
482 def __init__(self, msg, hint=None, version=None):
482 def __init__(self, msg, hint=None, version=None):
483 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
483 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
484 self.version = version
484 self.version = version
485 super(UnknownVersion, self).__init__(msg, hint=hint)
485 super(UnknownVersion, self).__init__(msg, hint=hint)
486
486
487
487
488 class LockError(IOError):
488 class LockError(IOError):
489 def __init__(self, errno, strerror, filename, desc):
489 def __init__(self, errno, strerror, filename, desc):
490 # TODO: figure out if this should be bytes or str
490 # TODO: figure out if this should be bytes or str
491 # _type: (int, str, str, bytes) -> None
491 # _type: (int, str, str, bytes) -> None
492 IOError.__init__(self, errno, strerror, filename)
492 IOError.__init__(self, errno, strerror, filename)
493 self.desc = desc
493 self.desc = desc
494
494
495 # no __bytes__() because error message is derived from the standard IOError
495 # no __bytes__() because error message is derived from the standard IOError
496
496
497
497
498 class LockHeld(LockError):
498 class LockHeld(LockError):
499 def __init__(self, errno, filename, desc, locker):
499 def __init__(self, errno, filename, desc, locker):
500 LockError.__init__(self, errno, b'Lock held', filename, desc)
500 LockError.__init__(self, errno, b'Lock held', filename, desc)
501 self.locker = locker
501 self.locker = locker
502
502
503
503
504 class LockUnavailable(LockError):
504 class LockUnavailable(LockError):
505 pass
505 pass
506
506
507
507
508 # LockError is for errors while acquiring the lock -- this is unrelated
508 # LockError is for errors while acquiring the lock -- this is unrelated
509 class LockInheritanceContractViolation(RuntimeError):
509 class LockInheritanceContractViolation(RuntimeError):
510 __bytes__ = _tobytes
510 __bytes__ = _tobytes
511
511
512
512
513 class ResponseError(Exception):
513 class ResponseError(Exception):
514 """Raised to print an error with part of output and exit."""
514 """Raised to print an error with part of output and exit."""
515
515
516 __bytes__ = _tobytes
516 __bytes__ = _tobytes
517
517
518
518
519 # derived from KeyboardInterrupt to simplify some breakout code
519 # derived from KeyboardInterrupt to simplify some breakout code
520 class SignalInterrupt(KeyboardInterrupt):
520 class SignalInterrupt(KeyboardInterrupt):
521 """Exception raised on SIGTERM and SIGHUP."""
521 """Exception raised on SIGTERM and SIGHUP."""
522
522
523
523
524 class SignatureError(Exception):
524 class SignatureError(Exception):
525 __bytes__ = _tobytes
525 __bytes__ = _tobytes
526
526
527
527
528 class PushRaced(RuntimeError):
528 class PushRaced(RuntimeError):
529 """An exception raised during unbundling that indicate a push race"""
529 """An exception raised during unbundling that indicate a push race"""
530
530
531 __bytes__ = _tobytes
531 __bytes__ = _tobytes
532
532
533
533
534 class ProgrammingError(Hint, RuntimeError):
534 class ProgrammingError(Hint, RuntimeError):
535 """Raised if a mercurial (core or extension) developer made a mistake"""
535 """Raised if a mercurial (core or extension) developer made a mistake"""
536
536
537 def __init__(self, msg, *args, **kwargs):
537 def __init__(self, msg, *args, **kwargs):
538 # type: (AnyStr, Any, Any) -> None
538 # type: (AnyStr, Any, Any) -> None
539 # On Python 3, turn the message back into a string since this is
539 # On Python 3, turn the message back into a string since this is
540 # an internal-only error that won't be printed except in a
540 # an internal-only error that won't be printed except in a
541 # stack traces.
541 # stack traces.
542 msg = pycompat.sysstr(msg)
542 msg = pycompat.sysstr(msg)
543 super(ProgrammingError, self).__init__(msg, *args, **kwargs)
543 super(ProgrammingError, self).__init__(msg, *args, **kwargs)
544
544
545 __bytes__ = _tobytes
545 __bytes__ = _tobytes
546
546
547
547
548 class WdirUnsupported(Exception):
548 class WdirUnsupported(Exception):
549 """An exception which is raised when 'wdir()' is not supported"""
549 """An exception which is raised when 'wdir()' is not supported"""
550
550
551 __bytes__ = _tobytes
551 __bytes__ = _tobytes
552
552
553
553
554 # bundle2 related errors
554 # bundle2 related errors
555 class BundleValueError(ValueError):
555 class BundleValueError(ValueError):
556 """error raised when bundle2 cannot be processed"""
556 """error raised when bundle2 cannot be processed"""
557
557
558 __bytes__ = _tobytes
558 __bytes__ = _tobytes
559
559
560
560
561 class BundleUnknownFeatureError(BundleValueError):
561 class BundleUnknownFeatureError(BundleValueError):
562 def __init__(self, parttype=None, params=(), values=()):
562 def __init__(self, parttype=None, params=(), values=()):
563 self.parttype = parttype
563 self.parttype = parttype
564 self.params = params
564 self.params = params
565 self.values = values
565 self.values = values
566 if self.parttype is None:
566 if self.parttype is None:
567 msg = b'Stream Parameter'
567 msg = b'Stream Parameter'
568 else:
568 else:
569 msg = parttype
569 msg = parttype
570 entries = self.params
570 entries = self.params
571 if self.params and self.values:
571 if self.params and self.values:
572 assert len(self.params) == len(self.values)
572 assert len(self.params) == len(self.values)
573 entries = []
573 entries = []
574 for idx, par in enumerate(self.params):
574 for idx, par in enumerate(self.params):
575 val = self.values[idx]
575 val = self.values[idx]
576 if val is None:
576 if val is None:
577 entries.append(val)
577 entries.append(val)
578 else:
578 else:
579 entries.append(b"%s=%r" % (par, pycompat.maybebytestr(val)))
579 entries.append(b"%s=%r" % (par, pycompat.maybebytestr(val)))
580 if entries:
580 if entries:
581 msg = b'%s - %s' % (msg, b', '.join(entries))
581 msg = b'%s - %s' % (msg, b', '.join(entries))
582 ValueError.__init__(self, msg) # TODO: convert to str?
582 ValueError.__init__(self, msg) # TODO: convert to str?
583
583
584
584
585 class ReadOnlyPartError(RuntimeError):
585 class ReadOnlyPartError(RuntimeError):
586 """error raised when code tries to alter a part being generated"""
586 """error raised when code tries to alter a part being generated"""
587
587
588 __bytes__ = _tobytes
588 __bytes__ = _tobytes
589
589
590
590
591 class PushkeyFailed(Abort):
591 class PushkeyFailed(Abort):
592 """error raised when a pushkey part failed to update a value"""
592 """error raised when a pushkey part failed to update a value"""
593
593
594 def __init__(
594 def __init__(
595 self, partid, namespace=None, key=None, new=None, old=None, ret=None
595 self, partid, namespace=None, key=None, new=None, old=None, ret=None
596 ):
596 ):
597 self.partid = partid
597 self.partid = partid
598 self.namespace = namespace
598 self.namespace = namespace
599 self.key = key
599 self.key = key
600 self.new = new
600 self.new = new
601 self.old = old
601 self.old = old
602 self.ret = ret
602 self.ret = ret
603 # no i18n expected to be processed into a better message
603 # no i18n expected to be processed into a better message
604 Abort.__init__(
604 Abort.__init__(
605 self, b'failed to update value for "%s/%s"' % (namespace, key)
605 self, b'failed to update value for "%s/%s"' % (namespace, key)
606 )
606 )
607
607
608
608
609 class CensoredNodeError(StorageError):
609 class CensoredNodeError(StorageError):
610 """error raised when content verification fails on a censored node
610 """error raised when content verification fails on a censored node
611
611
612 Also contains the tombstone data substituted for the uncensored data.
612 Also contains the tombstone data substituted for the uncensored data.
613 """
613 """
614
614
615 def __init__(self, filename, node, tombstone):
615 def __init__(self, filename, node, tombstone):
616 # type: (bytes, bytes, bytes) -> None
616 # type: (bytes, bytes, bytes) -> None
617 from .node import short
617 from .node import short
618
618
619 StorageError.__init__(self, b'%s:%s' % (filename, short(node)))
619 StorageError.__init__(self, b'%s:%s' % (filename, short(node)))
620 self.tombstone = tombstone
620 self.tombstone = tombstone
621
621
622
622
623 class CensoredBaseError(StorageError):
623 class CensoredBaseError(StorageError):
624 """error raised when a delta is rejected because its base is censored
624 """error raised when a delta is rejected because its base is censored
625
625
626 A delta based on a censored revision must be formed as single patch
626 A delta based on a censored revision must be formed as single patch
627 operation which replaces the entire base with new content. This ensures
627 operation which replaces the entire base with new content. This ensures
628 the delta may be applied by clones which have not censored the base.
628 the delta may be applied by clones which have not censored the base.
629 """
629 """
630
630
631
631
632 class InvalidBundleSpecification(Exception):
632 class InvalidBundleSpecification(Exception):
633 """error raised when a bundle specification is invalid.
633 """error raised when a bundle specification is invalid.
634
634
635 This is used for syntax errors as opposed to support errors.
635 This is used for syntax errors as opposed to support errors.
636 """
636 """
637
637
638 __bytes__ = _tobytes
638 __bytes__ = _tobytes
639
639
640
640
641 class UnsupportedBundleSpecification(Exception):
641 class UnsupportedBundleSpecification(Exception):
642 """error raised when a bundle specification is not supported."""
642 """error raised when a bundle specification is not supported."""
643
643
644 __bytes__ = _tobytes
644 __bytes__ = _tobytes
645
645
646
646
647 class CorruptedState(Exception):
647 class CorruptedState(Exception):
648 """error raised when a command is not able to read its state from file"""
648 """error raised when a command is not able to read its state from file"""
649
649
650 __bytes__ = _tobytes
650 __bytes__ = _tobytes
651
651
652
652
653 class CorruptedDirstate(Exception):
654 """error raised the dirstate appears corrupted on-disk. It may be due to
655 a dirstate version mismatch (i.e. expecting v2 and finding v1 on disk)."""
656
657 __bytes__ = _tobytes
658
659
653 class PeerTransportError(Abort):
660 class PeerTransportError(Abort):
654 """Transport-level I/O error when communicating with a peer repo."""
661 """Transport-level I/O error when communicating with a peer repo."""
655
662
656
663
657 class InMemoryMergeConflictsError(Exception):
664 class InMemoryMergeConflictsError(Exception):
658 """Exception raised when merge conflicts arose during an in-memory merge."""
665 """Exception raised when merge conflicts arose during an in-memory merge."""
659
666
660 __bytes__ = _tobytes
667 __bytes__ = _tobytes
661
668
662
669
663 class WireprotoCommandError(Exception):
670 class WireprotoCommandError(Exception):
664 """Represents an error during execution of a wire protocol command.
671 """Represents an error during execution of a wire protocol command.
665
672
666 Should only be thrown by wire protocol version 2 commands.
673 Should only be thrown by wire protocol version 2 commands.
667
674
668 The error is a formatter string and an optional iterable of arguments.
675 The error is a formatter string and an optional iterable of arguments.
669 """
676 """
670
677
671 def __init__(self, message, args=None):
678 def __init__(self, message, args=None):
672 # type: (bytes, Optional[Sequence[bytes]]) -> None
679 # type: (bytes, Optional[Sequence[bytes]]) -> None
673 self.message = message
680 self.message = message
674 self.messageargs = args
681 self.messageargs = args
@@ -1,111 +1,121 b''
1 Mercurial supports generating standalone "bundle" files that hold repository
1 Mercurial supports generating standalone "bundle" files that hold repository
2 data. These "bundles" are typically saved locally and used later or exchanged
2 data. These "bundles" are typically saved locally and used later or exchanged
3 between different repositories, possibly on different machines. Example
3 between different repositories, possibly on different machines. Example
4 commands using bundles are :hg:`bundle` and :hg:`unbundle`.
4 commands using bundles are :hg:`bundle` and :hg:`unbundle`.
5
5
6 Generation of bundle files is controlled by a "bundle specification"
6 Generation of bundle files is controlled by a "bundle specification"
7 ("bundlespec") string. This string tells the bundle generation process how
7 ("bundlespec") string. This string tells the bundle generation process how
8 to create the bundle.
8 to create the bundle.
9
9
10 A "bundlespec" string is composed of the following elements:
10 A "bundlespec" string is composed of the following elements:
11
11
12 type
12 type
13 A string denoting the bundle format to use.
13 A string denoting the bundle format to use.
14
14
15 compression
15 compression
16 Denotes the compression engine to use compressing the raw bundle data.
16 Denotes the compression engine to use compressing the raw bundle data.
17
17
18 parameters
18 parameters
19 Arbitrary key-value parameters to further control bundle generation.
19 Arbitrary key-value parameters to further control bundle generation.
20
20
21 A "bundlespec" string has the following formats:
21 A "bundlespec" string has the following formats:
22
22
23 <type>
23 <type>
24 The literal bundle format string is used.
24 The literal bundle format string is used.
25
25
26 <compression>-<type>
26 <compression>-<type>
27 The compression engine and format are delimited by a hyphen (``-``).
27 The compression engine and format are delimited by a hyphen (``-``).
28
28
29 Optional parameters follow the ``<type>``. Parameters are URI escaped
29 Optional parameters follow the ``<type>``. Parameters are URI escaped
30 ``key=value`` pairs. Each pair is delimited by a semicolon (``;``). The
30 ``key=value`` pairs. Each pair is delimited by a semicolon (``;``). The
31 first parameter begins after a ``;`` immediately following the ``<type>``
31 first parameter begins after a ``;`` immediately following the ``<type>``
32 value.
32 value.
33
33
34 Available Types
34 Available Types
35 ===============
35 ===============
36
36
37 The following bundle <type> strings are available:
37 The following bundle <type> strings are available:
38
38
39 v1
39 v1
40 Produces a legacy "changegroup" version 1 bundle.
40 Produces a legacy "changegroup" version 1 bundle.
41
41
42 This format is compatible with nearly all Mercurial clients because it is
42 This format is compatible with nearly all Mercurial clients because it is
43 the oldest. However, it has some limitations, which is why it is no longer
43 the oldest. However, it has some limitations, which is why it is no longer
44 the default for new repositories.
44 the default for new repositories.
45
45
46 ``v1`` bundles can be used with modern repositories using the "generaldelta"
46 ``v1`` bundles can be used with modern repositories using the "generaldelta"
47 storage format. However, it may take longer to produce the bundle and the
47 storage format. However, it may take longer to produce the bundle and the
48 resulting bundle may be significantly larger than a ``v2`` bundle.
48 resulting bundle may be significantly larger than a ``v2`` bundle.
49
49
50 ``v1`` bundles can only use the ``gzip``, ``bzip2``, and ``none`` compression
50 ``v1`` bundles can only use the ``gzip``, ``bzip2``, and ``none`` compression
51 formats.
51 formats.
52
52
53 v2
53 v2
54 Produces a version 2 bundle.
54 Produces a version 2 bundle.
55
55
56 Version 2 bundles are an extensible format that can store additional
56 Version 2 bundles are an extensible format that can store additional
57 repository data (such as bookmarks and phases information) and they can
57 repository data (such as bookmarks and phases information) and they can
58 store data more efficiently, resulting in smaller bundles.
58 store data more efficiently, resulting in smaller bundles.
59
59
60 Version 2 bundles can also use modern compression engines, such as
60 Version 2 bundles can also use modern compression engines, such as
61 ``zstd``, making them faster to compress and often smaller.
61 ``zstd``, making them faster to compress and often smaller.
62
62
63 Available Compression Engines
63 Available Compression Engines
64 =============================
64 =============================
65
65
66 The following bundle <compression> engines can be used:
66 The following bundle <compression> engines can be used:
67
67
68 .. bundlecompressionmarker
68 .. bundlecompressionmarker
69
69
70 The compression engines can be prepended with ``stream`` to create a streaming bundle.
71 These are bundles that are extremely efficient to produce and consume,
72 but do not have guaranteed compatibility with older clients.
73
70 Available Options
74 Available Options
71 =================
75 =================
72
76
73 The following options exist:
77 The following options exist:
74
78
75 changegroup
79 changegroup
76 Include the changegroup data in the bundle (default to True).
80 Include the changegroup data in the bundle (default to True).
77
81
78 cg.version
82 cg.version
79 Select the version of the changegroup to use. Available options are : 01, 02
83 Select the version of the changegroup to use. Available options are : 01, 02
80 or 03. By default it will be automatically selected according to the current
84 or 03. By default it will be automatically selected according to the current
81 repository format.
85 repository format.
82
86
83 obsolescence
87 obsolescence
84 Include obsolescence-markers relevant to the bundled changesets.
88 Include obsolescence-markers relevant to the bundled changesets.
85
89
86 phases
90 phases
87 Include phase information relevant to the bundled changesets.
91 Include phase information relevant to the bundled changesets.
88
92
89 revbranchcache
93 revbranchcache
90 Include the "tags-fnodes" cache inside the bundle.
94 Include the "tags-fnodes" cache inside the bundle.
91
95
92
93 tagsfnodescache
96 tagsfnodescache
94 Include the "tags-fnodes" cache inside the bundle.
97 Include the "tags-fnodes" cache inside the bundle.
95
98
96
99
97 Examples
100 Examples
98 ========
101 ========
99
102
100 ``v2``
103 ``v2``
101 Produce a ``v2`` bundle using default options, including compression.
104 Produce a ``v2`` bundle using default options, including compression.
102
105
103 ``none-v1``
106 ``none-v1``
104 Produce a ``v1`` bundle with no compression.
107 Produce a ``v1`` bundle with no compression.
105
108
106 ``zstd-v2``
109 ``zstd-v2``
107 Produce a ``v2`` bundle with zstandard compression using default
110 Produce a ``v2`` bundle with zstandard compression using default
108 settings.
111 settings.
109
112
110 ``zstd-v1``
113 ``zstd-v1``
111 This errors because ``zstd`` is not supported for ``v1`` types.
114 This errors because ``zstd`` is not supported for ``v1`` types.
115
116 ``none-streamv2``
117 Produce a ``v2`` streaming bundle with no compression.
118
119 ``zstd-v2;obsolescence=true;phases=true``
120 Produce a ``v2`` bundle with zstandard compression which includes
121 obsolescence markers and phases.
@@ -1,3511 +1,3527 b''
1 # revlog.py - storage back-end for mercurial
1 # revlog.py - storage back-end for mercurial
2 # coding: utf8
2 # coding: utf8
3 #
3 #
4 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 """Storage back-end for Mercurial.
9 """Storage back-end for Mercurial.
10
10
11 This provides efficient delta storage with O(1) retrieve and append
11 This provides efficient delta storage with O(1) retrieve and append
12 and O(changes) merge between branches.
12 and O(changes) merge between branches.
13 """
13 """
14
14
15
15
16 import binascii
16 import binascii
17 import collections
17 import collections
18 import contextlib
18 import contextlib
19 import io
19 import io
20 import os
20 import os
21 import struct
21 import struct
22 import weakref
22 import weakref
23 import zlib
23 import zlib
24
24
25 # import stuff from node for others to import from revlog
25 # import stuff from node for others to import from revlog
26 from .node import (
26 from .node import (
27 bin,
27 bin,
28 hex,
28 hex,
29 nullrev,
29 nullrev,
30 sha1nodeconstants,
30 sha1nodeconstants,
31 short,
31 short,
32 wdirrev,
32 wdirrev,
33 )
33 )
34 from .i18n import _
34 from .i18n import _
35 from .pycompat import getattr
35 from .pycompat import getattr
36 from .revlogutils.constants import (
36 from .revlogutils.constants import (
37 ALL_KINDS,
37 ALL_KINDS,
38 CHANGELOGV2,
38 CHANGELOGV2,
39 COMP_MODE_DEFAULT,
39 COMP_MODE_DEFAULT,
40 COMP_MODE_INLINE,
40 COMP_MODE_INLINE,
41 COMP_MODE_PLAIN,
41 COMP_MODE_PLAIN,
42 DELTA_BASE_REUSE_NO,
42 DELTA_BASE_REUSE_NO,
43 DELTA_BASE_REUSE_TRY,
43 DELTA_BASE_REUSE_TRY,
44 ENTRY_RANK,
44 ENTRY_RANK,
45 FEATURES_BY_VERSION,
45 FEATURES_BY_VERSION,
46 FLAG_GENERALDELTA,
46 FLAG_GENERALDELTA,
47 FLAG_INLINE_DATA,
47 FLAG_INLINE_DATA,
48 INDEX_HEADER,
48 INDEX_HEADER,
49 KIND_CHANGELOG,
49 KIND_CHANGELOG,
50 KIND_FILELOG,
50 KIND_FILELOG,
51 RANK_UNKNOWN,
51 RANK_UNKNOWN,
52 REVLOGV0,
52 REVLOGV0,
53 REVLOGV1,
53 REVLOGV1,
54 REVLOGV1_FLAGS,
54 REVLOGV1_FLAGS,
55 REVLOGV2,
55 REVLOGV2,
56 REVLOGV2_FLAGS,
56 REVLOGV2_FLAGS,
57 REVLOG_DEFAULT_FLAGS,
57 REVLOG_DEFAULT_FLAGS,
58 REVLOG_DEFAULT_FORMAT,
58 REVLOG_DEFAULT_FORMAT,
59 REVLOG_DEFAULT_VERSION,
59 REVLOG_DEFAULT_VERSION,
60 SUPPORTED_FLAGS,
60 SUPPORTED_FLAGS,
61 )
61 )
62 from .revlogutils.flagutil import (
62 from .revlogutils.flagutil import (
63 REVIDX_DEFAULT_FLAGS,
63 REVIDX_DEFAULT_FLAGS,
64 REVIDX_ELLIPSIS,
64 REVIDX_ELLIPSIS,
65 REVIDX_EXTSTORED,
65 REVIDX_EXTSTORED,
66 REVIDX_FLAGS_ORDER,
66 REVIDX_FLAGS_ORDER,
67 REVIDX_HASCOPIESINFO,
67 REVIDX_HASCOPIESINFO,
68 REVIDX_ISCENSORED,
68 REVIDX_ISCENSORED,
69 REVIDX_RAWTEXT_CHANGING_FLAGS,
69 REVIDX_RAWTEXT_CHANGING_FLAGS,
70 )
70 )
71 from .thirdparty import attr
71 from .thirdparty import attr
72 from . import (
72 from . import (
73 ancestor,
73 ancestor,
74 dagop,
74 dagop,
75 error,
75 error,
76 mdiff,
76 mdiff,
77 policy,
77 policy,
78 pycompat,
78 pycompat,
79 revlogutils,
79 revlogutils,
80 templatefilters,
80 templatefilters,
81 util,
81 util,
82 )
82 )
83 from .interfaces import (
83 from .interfaces import (
84 repository,
84 repository,
85 util as interfaceutil,
85 util as interfaceutil,
86 )
86 )
87 from .revlogutils import (
87 from .revlogutils import (
88 deltas as deltautil,
88 deltas as deltautil,
89 docket as docketutil,
89 docket as docketutil,
90 flagutil,
90 flagutil,
91 nodemap as nodemaputil,
91 nodemap as nodemaputil,
92 randomaccessfile,
92 randomaccessfile,
93 revlogv0,
93 revlogv0,
94 rewrite,
94 rewrite,
95 sidedata as sidedatautil,
95 sidedata as sidedatautil,
96 )
96 )
97 from .utils import (
97 from .utils import (
98 storageutil,
98 storageutil,
99 stringutil,
99 stringutil,
100 )
100 )
101
101
102 # blanked usage of all the name to prevent pyflakes constraints
102 # blanked usage of all the name to prevent pyflakes constraints
103 # We need these name available in the module for extensions.
103 # We need these name available in the module for extensions.
104
104
105 REVLOGV0
105 REVLOGV0
106 REVLOGV1
106 REVLOGV1
107 REVLOGV2
107 REVLOGV2
108 CHANGELOGV2
108 CHANGELOGV2
109 FLAG_INLINE_DATA
109 FLAG_INLINE_DATA
110 FLAG_GENERALDELTA
110 FLAG_GENERALDELTA
111 REVLOG_DEFAULT_FLAGS
111 REVLOG_DEFAULT_FLAGS
112 REVLOG_DEFAULT_FORMAT
112 REVLOG_DEFAULT_FORMAT
113 REVLOG_DEFAULT_VERSION
113 REVLOG_DEFAULT_VERSION
114 REVLOGV1_FLAGS
114 REVLOGV1_FLAGS
115 REVLOGV2_FLAGS
115 REVLOGV2_FLAGS
116 REVIDX_ISCENSORED
116 REVIDX_ISCENSORED
117 REVIDX_ELLIPSIS
117 REVIDX_ELLIPSIS
118 REVIDX_HASCOPIESINFO
118 REVIDX_HASCOPIESINFO
119 REVIDX_EXTSTORED
119 REVIDX_EXTSTORED
120 REVIDX_DEFAULT_FLAGS
120 REVIDX_DEFAULT_FLAGS
121 REVIDX_FLAGS_ORDER
121 REVIDX_FLAGS_ORDER
122 REVIDX_RAWTEXT_CHANGING_FLAGS
122 REVIDX_RAWTEXT_CHANGING_FLAGS
123
123
124 parsers = policy.importmod('parsers')
124 parsers = policy.importmod('parsers')
125 rustancestor = policy.importrust('ancestor')
125 rustancestor = policy.importrust('ancestor')
126 rustdagop = policy.importrust('dagop')
126 rustdagop = policy.importrust('dagop')
127 rustrevlog = policy.importrust('revlog')
127 rustrevlog = policy.importrust('revlog')
128
128
129 # Aliased for performance.
129 # Aliased for performance.
130 _zlibdecompress = zlib.decompress
130 _zlibdecompress = zlib.decompress
131
131
132 # max size of inline data embedded into a revlog
132 # max size of inline data embedded into a revlog
133 _maxinline = 131072
133 _maxinline = 131072
134
134
135 # Flag processors for REVIDX_ELLIPSIS.
135 # Flag processors for REVIDX_ELLIPSIS.
136 def ellipsisreadprocessor(rl, text):
136 def ellipsisreadprocessor(rl, text):
137 return text, False
137 return text, False
138
138
139
139
140 def ellipsiswriteprocessor(rl, text):
140 def ellipsiswriteprocessor(rl, text):
141 return text, False
141 return text, False
142
142
143
143
144 def ellipsisrawprocessor(rl, text):
144 def ellipsisrawprocessor(rl, text):
145 return False
145 return False
146
146
147
147
148 ellipsisprocessor = (
148 ellipsisprocessor = (
149 ellipsisreadprocessor,
149 ellipsisreadprocessor,
150 ellipsiswriteprocessor,
150 ellipsiswriteprocessor,
151 ellipsisrawprocessor,
151 ellipsisrawprocessor,
152 )
152 )
153
153
154
154
155 def _verify_revision(rl, skipflags, state, node):
155 def _verify_revision(rl, skipflags, state, node):
156 """Verify the integrity of the given revlog ``node`` while providing a hook
156 """Verify the integrity of the given revlog ``node`` while providing a hook
157 point for extensions to influence the operation."""
157 point for extensions to influence the operation."""
158 if skipflags:
158 if skipflags:
159 state[b'skipread'].add(node)
159 state[b'skipread'].add(node)
160 else:
160 else:
161 # Side-effect: read content and verify hash.
161 # Side-effect: read content and verify hash.
162 rl.revision(node)
162 rl.revision(node)
163
163
164
164
165 # True if a fast implementation for persistent-nodemap is available
165 # True if a fast implementation for persistent-nodemap is available
166 #
166 #
167 # We also consider we have a "fast" implementation in "pure" python because
167 # We also consider we have a "fast" implementation in "pure" python because
168 # people using pure don't really have performance consideration (and a
168 # people using pure don't really have performance consideration (and a
169 # wheelbarrow of other slowness source)
169 # wheelbarrow of other slowness source)
170 HAS_FAST_PERSISTENT_NODEMAP = rustrevlog is not None or util.safehasattr(
170 HAS_FAST_PERSISTENT_NODEMAP = rustrevlog is not None or util.safehasattr(
171 parsers, 'BaseIndexObject'
171 parsers, 'BaseIndexObject'
172 )
172 )
173
173
174
174
175 @interfaceutil.implementer(repository.irevisiondelta)
175 @interfaceutil.implementer(repository.irevisiondelta)
176 @attr.s(slots=True)
176 @attr.s(slots=True)
177 class revlogrevisiondelta:
177 class revlogrevisiondelta:
178 node = attr.ib()
178 node = attr.ib()
179 p1node = attr.ib()
179 p1node = attr.ib()
180 p2node = attr.ib()
180 p2node = attr.ib()
181 basenode = attr.ib()
181 basenode = attr.ib()
182 flags = attr.ib()
182 flags = attr.ib()
183 baserevisionsize = attr.ib()
183 baserevisionsize = attr.ib()
184 revision = attr.ib()
184 revision = attr.ib()
185 delta = attr.ib()
185 delta = attr.ib()
186 sidedata = attr.ib()
186 sidedata = attr.ib()
187 protocol_flags = attr.ib()
187 protocol_flags = attr.ib()
188 linknode = attr.ib(default=None)
188 linknode = attr.ib(default=None)
189
189
190
190
191 @interfaceutil.implementer(repository.iverifyproblem)
191 @interfaceutil.implementer(repository.iverifyproblem)
192 @attr.s(frozen=True)
192 @attr.s(frozen=True)
193 class revlogproblem:
193 class revlogproblem:
194 warning = attr.ib(default=None)
194 warning = attr.ib(default=None)
195 error = attr.ib(default=None)
195 error = attr.ib(default=None)
196 node = attr.ib(default=None)
196 node = attr.ib(default=None)
197
197
198
198
199 def parse_index_v1(data, inline):
199 def parse_index_v1(data, inline):
200 # call the C implementation to parse the index data
200 # call the C implementation to parse the index data
201 index, cache = parsers.parse_index2(data, inline)
201 index, cache = parsers.parse_index2(data, inline)
202 return index, cache
202 return index, cache
203
203
204
204
205 def parse_index_v2(data, inline):
205 def parse_index_v2(data, inline):
206 # call the C implementation to parse the index data
206 # call the C implementation to parse the index data
207 index, cache = parsers.parse_index2(data, inline, format=REVLOGV2)
207 index, cache = parsers.parse_index2(data, inline, format=REVLOGV2)
208 return index, cache
208 return index, cache
209
209
210
210
211 def parse_index_cl_v2(data, inline):
211 def parse_index_cl_v2(data, inline):
212 # call the C implementation to parse the index data
212 # call the C implementation to parse the index data
213 index, cache = parsers.parse_index2(data, inline, format=CHANGELOGV2)
213 index, cache = parsers.parse_index2(data, inline, format=CHANGELOGV2)
214 return index, cache
214 return index, cache
215
215
216
216
217 if util.safehasattr(parsers, 'parse_index_devel_nodemap'):
217 if util.safehasattr(parsers, 'parse_index_devel_nodemap'):
218
218
219 def parse_index_v1_nodemap(data, inline):
219 def parse_index_v1_nodemap(data, inline):
220 index, cache = parsers.parse_index_devel_nodemap(data, inline)
220 index, cache = parsers.parse_index_devel_nodemap(data, inline)
221 return index, cache
221 return index, cache
222
222
223
223
224 else:
224 else:
225 parse_index_v1_nodemap = None
225 parse_index_v1_nodemap = None
226
226
227
227
228 def parse_index_v1_mixed(data, inline):
228 def parse_index_v1_mixed(data, inline):
229 index, cache = parse_index_v1(data, inline)
229 index, cache = parse_index_v1(data, inline)
230 return rustrevlog.MixedIndex(index), cache
230 return rustrevlog.MixedIndex(index), cache
231
231
232
232
233 # corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
233 # corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
234 # signed integer)
234 # signed integer)
235 _maxentrysize = 0x7FFFFFFF
235 _maxentrysize = 0x7FFFFFFF
236
236
237 FILE_TOO_SHORT_MSG = _(
237 FILE_TOO_SHORT_MSG = _(
238 b'cannot read from revlog %s;'
238 b'cannot read from revlog %s;'
239 b' expected %d bytes from offset %d, data size is %d'
239 b' expected %d bytes from offset %d, data size is %d'
240 )
240 )
241
241
242 hexdigits = b'0123456789abcdefABCDEF'
242 hexdigits = b'0123456789abcdefABCDEF'
243
243
244
244
245 class revlog:
245 class revlog:
246 """
246 """
247 the underlying revision storage object
247 the underlying revision storage object
248
248
249 A revlog consists of two parts, an index and the revision data.
249 A revlog consists of two parts, an index and the revision data.
250
250
251 The index is a file with a fixed record size containing
251 The index is a file with a fixed record size containing
252 information on each revision, including its nodeid (hash), the
252 information on each revision, including its nodeid (hash), the
253 nodeids of its parents, the position and offset of its data within
253 nodeids of its parents, the position and offset of its data within
254 the data file, and the revision it's based on. Finally, each entry
254 the data file, and the revision it's based on. Finally, each entry
255 contains a linkrev entry that can serve as a pointer to external
255 contains a linkrev entry that can serve as a pointer to external
256 data.
256 data.
257
257
258 The revision data itself is a linear collection of data chunks.
258 The revision data itself is a linear collection of data chunks.
259 Each chunk represents a revision and is usually represented as a
259 Each chunk represents a revision and is usually represented as a
260 delta against the previous chunk. To bound lookup time, runs of
260 delta against the previous chunk. To bound lookup time, runs of
261 deltas are limited to about 2 times the length of the original
261 deltas are limited to about 2 times the length of the original
262 version data. This makes retrieval of a version proportional to
262 version data. This makes retrieval of a version proportional to
263 its size, or O(1) relative to the number of revisions.
263 its size, or O(1) relative to the number of revisions.
264
264
265 Both pieces of the revlog are written to in an append-only
265 Both pieces of the revlog are written to in an append-only
266 fashion, which means we never need to rewrite a file to insert or
266 fashion, which means we never need to rewrite a file to insert or
267 remove data, and can use some simple techniques to avoid the need
267 remove data, and can use some simple techniques to avoid the need
268 for locking while reading.
268 for locking while reading.
269
269
270 If checkambig, indexfile is opened with checkambig=True at
270 If checkambig, indexfile is opened with checkambig=True at
271 writing, to avoid file stat ambiguity.
271 writing, to avoid file stat ambiguity.
272
272
273 If mmaplargeindex is True, and an mmapindexthreshold is set, the
273 If mmaplargeindex is True, and an mmapindexthreshold is set, the
274 index will be mmapped rather than read if it is larger than the
274 index will be mmapped rather than read if it is larger than the
275 configured threshold.
275 configured threshold.
276
276
277 If censorable is True, the revlog can have censored revisions.
277 If censorable is True, the revlog can have censored revisions.
278
278
279 If `upperboundcomp` is not None, this is the expected maximal gain from
279 If `upperboundcomp` is not None, this is the expected maximal gain from
280 compression for the data content.
280 compression for the data content.
281
281
282 `concurrencychecker` is an optional function that receives 3 arguments: a
282 `concurrencychecker` is an optional function that receives 3 arguments: a
283 file handle, a filename, and an expected position. It should check whether
283 file handle, a filename, and an expected position. It should check whether
284 the current position in the file handle is valid, and log/warn/fail (by
284 the current position in the file handle is valid, and log/warn/fail (by
285 raising).
285 raising).
286
286
287 See mercurial/revlogutils/contants.py for details about the content of an
287 See mercurial/revlogutils/contants.py for details about the content of an
288 index entry.
288 index entry.
289 """
289 """
290
290
291 _flagserrorclass = error.RevlogError
291 _flagserrorclass = error.RevlogError
292
292
293 @staticmethod
293 @staticmethod
294 def is_inline_index(header_bytes):
294 def is_inline_index(header_bytes):
295 header = INDEX_HEADER.unpack(header_bytes)[0]
295 header = INDEX_HEADER.unpack(header_bytes)[0]
296
296
297 _format_flags = header & ~0xFFFF
297 _format_flags = header & ~0xFFFF
298 _format_version = header & 0xFFFF
298 _format_version = header & 0xFFFF
299
299
300 features = FEATURES_BY_VERSION[_format_version]
300 features = FEATURES_BY_VERSION[_format_version]
301 return features[b'inline'](_format_flags)
301 return features[b'inline'](_format_flags)
302
302
303 def __init__(
303 def __init__(
304 self,
304 self,
305 opener,
305 opener,
306 target,
306 target,
307 radix,
307 radix,
308 postfix=None, # only exist for `tmpcensored` now
308 postfix=None, # only exist for `tmpcensored` now
309 checkambig=False,
309 checkambig=False,
310 mmaplargeindex=False,
310 mmaplargeindex=False,
311 censorable=False,
311 censorable=False,
312 upperboundcomp=None,
312 upperboundcomp=None,
313 persistentnodemap=False,
313 persistentnodemap=False,
314 concurrencychecker=None,
314 concurrencychecker=None,
315 trypending=False,
315 trypending=False,
316 try_split=False,
316 try_split=False,
317 canonical_parent_order=True,
317 canonical_parent_order=True,
318 ):
318 ):
319 """
319 """
320 create a revlog object
320 create a revlog object
321
321
322 opener is a function that abstracts the file opening operation
322 opener is a function that abstracts the file opening operation
323 and can be used to implement COW semantics or the like.
323 and can be used to implement COW semantics or the like.
324
324
325 `target`: a (KIND, ID) tuple that identify the content stored in
325 `target`: a (KIND, ID) tuple that identify the content stored in
326 this revlog. It help the rest of the code to understand what the revlog
326 this revlog. It help the rest of the code to understand what the revlog
327 is about without having to resort to heuristic and index filename
327 is about without having to resort to heuristic and index filename
328 analysis. Note: that this must be reliably be set by normal code, but
328 analysis. Note: that this must be reliably be set by normal code, but
329 that test, debug, or performance measurement code might not set this to
329 that test, debug, or performance measurement code might not set this to
330 accurate value.
330 accurate value.
331 """
331 """
332 self.upperboundcomp = upperboundcomp
332 self.upperboundcomp = upperboundcomp
333
333
334 self.radix = radix
334 self.radix = radix
335
335
336 self._docket_file = None
336 self._docket_file = None
337 self._indexfile = None
337 self._indexfile = None
338 self._datafile = None
338 self._datafile = None
339 self._sidedatafile = None
339 self._sidedatafile = None
340 self._nodemap_file = None
340 self._nodemap_file = None
341 self.postfix = postfix
341 self.postfix = postfix
342 self._trypending = trypending
342 self._trypending = trypending
343 self._try_split = try_split
343 self._try_split = try_split
344 self.opener = opener
344 self.opener = opener
345 if persistentnodemap:
345 if persistentnodemap:
346 self._nodemap_file = nodemaputil.get_nodemap_file(self)
346 self._nodemap_file = nodemaputil.get_nodemap_file(self)
347
347
348 assert target[0] in ALL_KINDS
348 assert target[0] in ALL_KINDS
349 assert len(target) == 2
349 assert len(target) == 2
350 self.target = target
350 self.target = target
351 # When True, indexfile is opened with checkambig=True at writing, to
351 # When True, indexfile is opened with checkambig=True at writing, to
352 # avoid file stat ambiguity.
352 # avoid file stat ambiguity.
353 self._checkambig = checkambig
353 self._checkambig = checkambig
354 self._mmaplargeindex = mmaplargeindex
354 self._mmaplargeindex = mmaplargeindex
355 self._censorable = censorable
355 self._censorable = censorable
356 # 3-tuple of (node, rev, text) for a raw revision.
356 # 3-tuple of (node, rev, text) for a raw revision.
357 self._revisioncache = None
357 self._revisioncache = None
358 # Maps rev to chain base rev.
358 # Maps rev to chain base rev.
359 self._chainbasecache = util.lrucachedict(100)
359 self._chainbasecache = util.lrucachedict(100)
360 # 2-tuple of (offset, data) of raw data from the revlog at an offset.
360 # 2-tuple of (offset, data) of raw data from the revlog at an offset.
361 self._chunkcache = (0, b'')
361 self._chunkcache = (0, b'')
362 # How much data to read and cache into the raw revlog data cache.
362 # How much data to read and cache into the raw revlog data cache.
363 self._chunkcachesize = 65536
363 self._chunkcachesize = 65536
364 self._maxchainlen = None
364 self._maxchainlen = None
365 self._deltabothparents = True
365 self._deltabothparents = True
366 self._candidate_group_chunk_size = 0
366 self._candidate_group_chunk_size = 0
367 self._debug_delta = False
367 self._debug_delta = False
368 self.index = None
368 self.index = None
369 self._docket = None
369 self._docket = None
370 self._nodemap_docket = None
370 self._nodemap_docket = None
371 # Mapping of partial identifiers to full nodes.
371 # Mapping of partial identifiers to full nodes.
372 self._pcache = {}
372 self._pcache = {}
373 # Mapping of revision integer to full node.
373 # Mapping of revision integer to full node.
374 self._compengine = b'zlib'
374 self._compengine = b'zlib'
375 self._compengineopts = {}
375 self._compengineopts = {}
376 self._maxdeltachainspan = -1
376 self._maxdeltachainspan = -1
377 self._withsparseread = False
377 self._withsparseread = False
378 self._sparserevlog = False
378 self._sparserevlog = False
379 self.hassidedata = False
379 self.hassidedata = False
380 self._srdensitythreshold = 0.50
380 self._srdensitythreshold = 0.50
381 self._srmingapsize = 262144
381 self._srmingapsize = 262144
382
382
383 # other optionnals features
383 # other optionnals features
384
384
385 # might remove rank configuration once the computation has no impact
385 # might remove rank configuration once the computation has no impact
386 self._compute_rank = False
386 self._compute_rank = False
387
387
388 # Make copy of flag processors so each revlog instance can support
388 # Make copy of flag processors so each revlog instance can support
389 # custom flags.
389 # custom flags.
390 self._flagprocessors = dict(flagutil.flagprocessors)
390 self._flagprocessors = dict(flagutil.flagprocessors)
391
391
392 # 3-tuple of file handles being used for active writing.
392 # 3-tuple of file handles being used for active writing.
393 self._writinghandles = None
393 self._writinghandles = None
394 # prevent nesting of addgroup
394 # prevent nesting of addgroup
395 self._adding_group = None
395 self._adding_group = None
396
396
397 self._loadindex()
397 self._loadindex()
398
398
399 self._concurrencychecker = concurrencychecker
399 self._concurrencychecker = concurrencychecker
400
400
401 # parent order is supposed to be semantically irrelevant, so we
401 # parent order is supposed to be semantically irrelevant, so we
402 # normally resort parents to ensure that the first parent is non-null,
402 # normally resort parents to ensure that the first parent is non-null,
403 # if there is a non-null parent at all.
403 # if there is a non-null parent at all.
404 # filelog abuses the parent order as flag to mark some instances of
404 # filelog abuses the parent order as flag to mark some instances of
405 # meta-encoded files, so allow it to disable this behavior.
405 # meta-encoded files, so allow it to disable this behavior.
406 self.canonical_parent_order = canonical_parent_order
406 self.canonical_parent_order = canonical_parent_order
407
407
408 def _init_opts(self):
408 def _init_opts(self):
409 """process options (from above/config) to setup associated default revlog mode
409 """process options (from above/config) to setup associated default revlog mode
410
410
411 These values might be affected when actually reading on disk information.
411 These values might be affected when actually reading on disk information.
412
412
413 The relevant values are returned for use in _loadindex().
413 The relevant values are returned for use in _loadindex().
414
414
415 * newversionflags:
415 * newversionflags:
416 version header to use if we need to create a new revlog
416 version header to use if we need to create a new revlog
417
417
418 * mmapindexthreshold:
418 * mmapindexthreshold:
419 minimal index size for start to use mmap
419 minimal index size for start to use mmap
420
420
421 * force_nodemap:
421 * force_nodemap:
422 force the usage of a "development" version of the nodemap code
422 force the usage of a "development" version of the nodemap code
423 """
423 """
424 mmapindexthreshold = None
424 mmapindexthreshold = None
425 opts = self.opener.options
425 opts = self.opener.options
426
426
427 if b'changelogv2' in opts and self.revlog_kind == KIND_CHANGELOG:
427 if b'changelogv2' in opts and self.revlog_kind == KIND_CHANGELOG:
428 new_header = CHANGELOGV2
428 new_header = CHANGELOGV2
429 self._compute_rank = opts.get(b'changelogv2.compute-rank', True)
429 self._compute_rank = opts.get(b'changelogv2.compute-rank', True)
430 elif b'revlogv2' in opts:
430 elif b'revlogv2' in opts:
431 new_header = REVLOGV2
431 new_header = REVLOGV2
432 elif b'revlogv1' in opts:
432 elif b'revlogv1' in opts:
433 new_header = REVLOGV1 | FLAG_INLINE_DATA
433 new_header = REVLOGV1 | FLAG_INLINE_DATA
434 if b'generaldelta' in opts:
434 if b'generaldelta' in opts:
435 new_header |= FLAG_GENERALDELTA
435 new_header |= FLAG_GENERALDELTA
436 elif b'revlogv0' in self.opener.options:
436 elif b'revlogv0' in self.opener.options:
437 new_header = REVLOGV0
437 new_header = REVLOGV0
438 else:
438 else:
439 new_header = REVLOG_DEFAULT_VERSION
439 new_header = REVLOG_DEFAULT_VERSION
440
440
441 if b'chunkcachesize' in opts:
441 if b'chunkcachesize' in opts:
442 self._chunkcachesize = opts[b'chunkcachesize']
442 self._chunkcachesize = opts[b'chunkcachesize']
443 if b'maxchainlen' in opts:
443 if b'maxchainlen' in opts:
444 self._maxchainlen = opts[b'maxchainlen']
444 self._maxchainlen = opts[b'maxchainlen']
445 if b'deltabothparents' in opts:
445 if b'deltabothparents' in opts:
446 self._deltabothparents = opts[b'deltabothparents']
446 self._deltabothparents = opts[b'deltabothparents']
447 dps_cgds = opts.get(b'delta-parent-search.candidate-group-chunk-size')
447 dps_cgds = opts.get(b'delta-parent-search.candidate-group-chunk-size')
448 if dps_cgds:
448 if dps_cgds:
449 self._candidate_group_chunk_size = dps_cgds
449 self._candidate_group_chunk_size = dps_cgds
450 self._lazydelta = bool(opts.get(b'lazydelta', True))
450 self._lazydelta = bool(opts.get(b'lazydelta', True))
451 self._lazydeltabase = False
451 self._lazydeltabase = False
452 if self._lazydelta:
452 if self._lazydelta:
453 self._lazydeltabase = bool(opts.get(b'lazydeltabase', False))
453 self._lazydeltabase = bool(opts.get(b'lazydeltabase', False))
454 if b'debug-delta' in opts:
454 if b'debug-delta' in opts:
455 self._debug_delta = opts[b'debug-delta']
455 self._debug_delta = opts[b'debug-delta']
456 if b'compengine' in opts:
456 if b'compengine' in opts:
457 self._compengine = opts[b'compengine']
457 self._compengine = opts[b'compengine']
458 if b'zlib.level' in opts:
458 if b'zlib.level' in opts:
459 self._compengineopts[b'zlib.level'] = opts[b'zlib.level']
459 self._compengineopts[b'zlib.level'] = opts[b'zlib.level']
460 if b'zstd.level' in opts:
460 if b'zstd.level' in opts:
461 self._compengineopts[b'zstd.level'] = opts[b'zstd.level']
461 self._compengineopts[b'zstd.level'] = opts[b'zstd.level']
462 if b'maxdeltachainspan' in opts:
462 if b'maxdeltachainspan' in opts:
463 self._maxdeltachainspan = opts[b'maxdeltachainspan']
463 self._maxdeltachainspan = opts[b'maxdeltachainspan']
464 if self._mmaplargeindex and b'mmapindexthreshold' in opts:
464 if self._mmaplargeindex and b'mmapindexthreshold' in opts:
465 mmapindexthreshold = opts[b'mmapindexthreshold']
465 mmapindexthreshold = opts[b'mmapindexthreshold']
466 self._sparserevlog = bool(opts.get(b'sparse-revlog', False))
466 self._sparserevlog = bool(opts.get(b'sparse-revlog', False))
467 withsparseread = bool(opts.get(b'with-sparse-read', False))
467 withsparseread = bool(opts.get(b'with-sparse-read', False))
468 # sparse-revlog forces sparse-read
468 # sparse-revlog forces sparse-read
469 self._withsparseread = self._sparserevlog or withsparseread
469 self._withsparseread = self._sparserevlog or withsparseread
470 if b'sparse-read-density-threshold' in opts:
470 if b'sparse-read-density-threshold' in opts:
471 self._srdensitythreshold = opts[b'sparse-read-density-threshold']
471 self._srdensitythreshold = opts[b'sparse-read-density-threshold']
472 if b'sparse-read-min-gap-size' in opts:
472 if b'sparse-read-min-gap-size' in opts:
473 self._srmingapsize = opts[b'sparse-read-min-gap-size']
473 self._srmingapsize = opts[b'sparse-read-min-gap-size']
474 if opts.get(b'enableellipsis'):
474 if opts.get(b'enableellipsis'):
475 self._flagprocessors[REVIDX_ELLIPSIS] = ellipsisprocessor
475 self._flagprocessors[REVIDX_ELLIPSIS] = ellipsisprocessor
476
476
477 # revlog v0 doesn't have flag processors
477 # revlog v0 doesn't have flag processors
478 for flag, processor in opts.get(b'flagprocessors', {}).items():
478 for flag, processor in opts.get(b'flagprocessors', {}).items():
479 flagutil.insertflagprocessor(flag, processor, self._flagprocessors)
479 flagutil.insertflagprocessor(flag, processor, self._flagprocessors)
480
480
481 if self._chunkcachesize <= 0:
481 if self._chunkcachesize <= 0:
482 raise error.RevlogError(
482 raise error.RevlogError(
483 _(b'revlog chunk cache size %r is not greater than 0')
483 _(b'revlog chunk cache size %r is not greater than 0')
484 % self._chunkcachesize
484 % self._chunkcachesize
485 )
485 )
486 elif self._chunkcachesize & (self._chunkcachesize - 1):
486 elif self._chunkcachesize & (self._chunkcachesize - 1):
487 raise error.RevlogError(
487 raise error.RevlogError(
488 _(b'revlog chunk cache size %r is not a power of 2')
488 _(b'revlog chunk cache size %r is not a power of 2')
489 % self._chunkcachesize
489 % self._chunkcachesize
490 )
490 )
491 force_nodemap = opts.get(b'devel-force-nodemap', False)
491 force_nodemap = opts.get(b'devel-force-nodemap', False)
492 return new_header, mmapindexthreshold, force_nodemap
492 return new_header, mmapindexthreshold, force_nodemap
493
493
494 def _get_data(self, filepath, mmap_threshold, size=None):
494 def _get_data(self, filepath, mmap_threshold, size=None):
495 """return a file content with or without mmap
495 """return a file content with or without mmap
496
496
497 If the file is missing return the empty string"""
497 If the file is missing return the empty string"""
498 try:
498 try:
499 with self.opener(filepath) as fp:
499 with self.opener(filepath) as fp:
500 if mmap_threshold is not None:
500 if mmap_threshold is not None:
501 file_size = self.opener.fstat(fp).st_size
501 file_size = self.opener.fstat(fp).st_size
502 if file_size >= mmap_threshold:
502 if file_size >= mmap_threshold:
503 if size is not None:
503 if size is not None:
504 # avoid potentiel mmap crash
504 # avoid potentiel mmap crash
505 size = min(file_size, size)
505 size = min(file_size, size)
506 # TODO: should .close() to release resources without
506 # TODO: should .close() to release resources without
507 # relying on Python GC
507 # relying on Python GC
508 if size is None:
508 if size is None:
509 return util.buffer(util.mmapread(fp))
509 return util.buffer(util.mmapread(fp))
510 else:
510 else:
511 return util.buffer(util.mmapread(fp, size))
511 return util.buffer(util.mmapread(fp, size))
512 if size is None:
512 if size is None:
513 return fp.read()
513 return fp.read()
514 else:
514 else:
515 return fp.read(size)
515 return fp.read(size)
516 except FileNotFoundError:
516 except FileNotFoundError:
517 return b''
517 return b''
518
518
519 def get_streams(self, max_linkrev, force_inline=False):
519 def get_streams(self, max_linkrev, force_inline=False):
520 n = len(self)
520 n = len(self)
521 index = self.index
521 index = self.index
522 while n > 0:
522 while n > 0:
523 linkrev = index[n - 1][4]
523 linkrev = index[n - 1][4]
524 if linkrev < max_linkrev:
524 if linkrev < max_linkrev:
525 break
525 break
526 # note: this loop will rarely go through multiple iterations, since
526 # note: this loop will rarely go through multiple iterations, since
527 # it only traverses commits created during the current streaming
527 # it only traverses commits created during the current streaming
528 # pull operation.
528 # pull operation.
529 #
529 #
530 # If this become a problem, using a binary search should cap the
530 # If this become a problem, using a binary search should cap the
531 # runtime of this.
531 # runtime of this.
532 n = n - 1
532 n = n - 1
533 if n == 0:
533 if n == 0:
534 # no data to send
534 # no data to send
535 return []
535 return []
536 index_size = n * index.entry_size
536 index_size = n * index.entry_size
537 data_size = self.end(n - 1)
537 data_size = self.end(n - 1)
538
538
539 # XXX we might have been split (or stripped) since the object
539 # XXX we might have been split (or stripped) since the object
540 # initialization, We need to close this race too, but having a way to
540 # initialization, We need to close this race too, but having a way to
541 # pre-open the file we feed to the revlog and never closing them before
541 # pre-open the file we feed to the revlog and never closing them before
542 # we are done streaming.
542 # we are done streaming.
543
543
544 if self._inline:
544 if self._inline:
545
545
546 def get_stream():
546 def get_stream():
547 with self._indexfp() as fp:
547 with self._indexfp() as fp:
548 yield None
548 yield None
549 size = index_size + data_size
549 size = index_size + data_size
550 if size <= 65536:
550 if size <= 65536:
551 yield fp.read(size)
551 yield fp.read(size)
552 else:
552 else:
553 yield from util.filechunkiter(fp, limit=size)
553 yield from util.filechunkiter(fp, limit=size)
554
554
555 inline_stream = get_stream()
555 inline_stream = get_stream()
556 next(inline_stream)
556 next(inline_stream)
557 return [
557 return [
558 (self._indexfile, inline_stream, index_size + data_size),
558 (self._indexfile, inline_stream, index_size + data_size),
559 ]
559 ]
560 elif force_inline:
560 elif force_inline:
561
561
562 def get_stream():
562 def get_stream():
563 with self._datafp() as fp_d:
563 with self._datafp() as fp_d:
564 yield None
564 yield None
565
565
566 for rev in range(n):
566 for rev in range(n):
567 idx = self.index.entry_binary(rev)
567 idx = self.index.entry_binary(rev)
568 if rev == 0 and self._docket is None:
568 if rev == 0 and self._docket is None:
569 # re-inject the inline flag
569 # re-inject the inline flag
570 header = self._format_flags
570 header = self._format_flags
571 header |= self._format_version
571 header |= self._format_version
572 header |= FLAG_INLINE_DATA
572 header |= FLAG_INLINE_DATA
573 header = self.index.pack_header(header)
573 header = self.index.pack_header(header)
574 idx = header + idx
574 idx = header + idx
575 yield idx
575 yield idx
576 yield self._getsegmentforrevs(rev, rev, df=fp_d)[1]
576 yield self._getsegmentforrevs(rev, rev, df=fp_d)[1]
577
577
578 inline_stream = get_stream()
578 inline_stream = get_stream()
579 next(inline_stream)
579 next(inline_stream)
580 return [
580 return [
581 (self._indexfile, inline_stream, index_size + data_size),
581 (self._indexfile, inline_stream, index_size + data_size),
582 ]
582 ]
583 else:
583 else:
584
584
585 def get_index_stream():
585 def get_index_stream():
586 with self._indexfp() as fp:
586 with self._indexfp() as fp:
587 yield None
587 yield None
588 if index_size <= 65536:
588 if index_size <= 65536:
589 yield fp.read(index_size)
589 yield fp.read(index_size)
590 else:
590 else:
591 yield from util.filechunkiter(fp, limit=index_size)
591 yield from util.filechunkiter(fp, limit=index_size)
592
592
593 def get_data_stream():
593 def get_data_stream():
594 with self._datafp() as fp:
594 with self._datafp() as fp:
595 yield None
595 yield None
596 if data_size <= 65536:
596 if data_size <= 65536:
597 yield fp.read(data_size)
597 yield fp.read(data_size)
598 else:
598 else:
599 yield from util.filechunkiter(fp, limit=data_size)
599 yield from util.filechunkiter(fp, limit=data_size)
600
600
601 index_stream = get_index_stream()
601 index_stream = get_index_stream()
602 next(index_stream)
602 next(index_stream)
603 data_stream = get_data_stream()
603 data_stream = get_data_stream()
604 next(data_stream)
604 next(data_stream)
605 return [
605 return [
606 (self._datafile, data_stream, data_size),
606 (self._datafile, data_stream, data_size),
607 (self._indexfile, index_stream, index_size),
607 (self._indexfile, index_stream, index_size),
608 ]
608 ]
609
609
610 def _loadindex(self, docket=None):
610 def _loadindex(self, docket=None):
611
611
612 new_header, mmapindexthreshold, force_nodemap = self._init_opts()
612 new_header, mmapindexthreshold, force_nodemap = self._init_opts()
613
613
614 if self.postfix is not None:
614 if self.postfix is not None:
615 entry_point = b'%s.i.%s' % (self.radix, self.postfix)
615 entry_point = b'%s.i.%s' % (self.radix, self.postfix)
616 elif self._trypending and self.opener.exists(b'%s.i.a' % self.radix):
616 elif self._trypending and self.opener.exists(b'%s.i.a' % self.radix):
617 entry_point = b'%s.i.a' % self.radix
617 entry_point = b'%s.i.a' % self.radix
618 elif self._try_split and self.opener.exists(b'%s.i.s' % self.radix):
618 elif self._try_split and self.opener.exists(self._split_index_file):
619 entry_point = b'%s.i.s' % self.radix
619 entry_point = self._split_index_file
620 else:
620 else:
621 entry_point = b'%s.i' % self.radix
621 entry_point = b'%s.i' % self.radix
622
622
623 if docket is not None:
623 if docket is not None:
624 self._docket = docket
624 self._docket = docket
625 self._docket_file = entry_point
625 self._docket_file = entry_point
626 else:
626 else:
627 self._initempty = True
627 self._initempty = True
628 entry_data = self._get_data(entry_point, mmapindexthreshold)
628 entry_data = self._get_data(entry_point, mmapindexthreshold)
629 if len(entry_data) > 0:
629 if len(entry_data) > 0:
630 header = INDEX_HEADER.unpack(entry_data[:4])[0]
630 header = INDEX_HEADER.unpack(entry_data[:4])[0]
631 self._initempty = False
631 self._initempty = False
632 else:
632 else:
633 header = new_header
633 header = new_header
634
634
635 self._format_flags = header & ~0xFFFF
635 self._format_flags = header & ~0xFFFF
636 self._format_version = header & 0xFFFF
636 self._format_version = header & 0xFFFF
637
637
638 supported_flags = SUPPORTED_FLAGS.get(self._format_version)
638 supported_flags = SUPPORTED_FLAGS.get(self._format_version)
639 if supported_flags is None:
639 if supported_flags is None:
640 msg = _(b'unknown version (%d) in revlog %s')
640 msg = _(b'unknown version (%d) in revlog %s')
641 msg %= (self._format_version, self.display_id)
641 msg %= (self._format_version, self.display_id)
642 raise error.RevlogError(msg)
642 raise error.RevlogError(msg)
643 elif self._format_flags & ~supported_flags:
643 elif self._format_flags & ~supported_flags:
644 msg = _(b'unknown flags (%#04x) in version %d revlog %s')
644 msg = _(b'unknown flags (%#04x) in version %d revlog %s')
645 display_flag = self._format_flags >> 16
645 display_flag = self._format_flags >> 16
646 msg %= (display_flag, self._format_version, self.display_id)
646 msg %= (display_flag, self._format_version, self.display_id)
647 raise error.RevlogError(msg)
647 raise error.RevlogError(msg)
648
648
649 features = FEATURES_BY_VERSION[self._format_version]
649 features = FEATURES_BY_VERSION[self._format_version]
650 self._inline = features[b'inline'](self._format_flags)
650 self._inline = features[b'inline'](self._format_flags)
651 self._generaldelta = features[b'generaldelta'](self._format_flags)
651 self._generaldelta = features[b'generaldelta'](self._format_flags)
652 self.hassidedata = features[b'sidedata']
652 self.hassidedata = features[b'sidedata']
653
653
654 if not features[b'docket']:
654 if not features[b'docket']:
655 self._indexfile = entry_point
655 self._indexfile = entry_point
656 index_data = entry_data
656 index_data = entry_data
657 else:
657 else:
658 self._docket_file = entry_point
658 self._docket_file = entry_point
659 if self._initempty:
659 if self._initempty:
660 self._docket = docketutil.default_docket(self, header)
660 self._docket = docketutil.default_docket(self, header)
661 else:
661 else:
662 self._docket = docketutil.parse_docket(
662 self._docket = docketutil.parse_docket(
663 self, entry_data, use_pending=self._trypending
663 self, entry_data, use_pending=self._trypending
664 )
664 )
665
665
666 if self._docket is not None:
666 if self._docket is not None:
667 self._indexfile = self._docket.index_filepath()
667 self._indexfile = self._docket.index_filepath()
668 index_data = b''
668 index_data = b''
669 index_size = self._docket.index_end
669 index_size = self._docket.index_end
670 if index_size > 0:
670 if index_size > 0:
671 index_data = self._get_data(
671 index_data = self._get_data(
672 self._indexfile, mmapindexthreshold, size=index_size
672 self._indexfile, mmapindexthreshold, size=index_size
673 )
673 )
674 if len(index_data) < index_size:
674 if len(index_data) < index_size:
675 msg = _(b'too few index data for %s: got %d, expected %d')
675 msg = _(b'too few index data for %s: got %d, expected %d')
676 msg %= (self.display_id, len(index_data), index_size)
676 msg %= (self.display_id, len(index_data), index_size)
677 raise error.RevlogError(msg)
677 raise error.RevlogError(msg)
678
678
679 self._inline = False
679 self._inline = False
680 # generaldelta implied by version 2 revlogs.
680 # generaldelta implied by version 2 revlogs.
681 self._generaldelta = True
681 self._generaldelta = True
682 # the logic for persistent nodemap will be dealt with within the
682 # the logic for persistent nodemap will be dealt with within the
683 # main docket, so disable it for now.
683 # main docket, so disable it for now.
684 self._nodemap_file = None
684 self._nodemap_file = None
685
685
686 if self._docket is not None:
686 if self._docket is not None:
687 self._datafile = self._docket.data_filepath()
687 self._datafile = self._docket.data_filepath()
688 self._sidedatafile = self._docket.sidedata_filepath()
688 self._sidedatafile = self._docket.sidedata_filepath()
689 elif self.postfix is None:
689 elif self.postfix is None:
690 self._datafile = b'%s.d' % self.radix
690 self._datafile = b'%s.d' % self.radix
691 else:
691 else:
692 self._datafile = b'%s.d.%s' % (self.radix, self.postfix)
692 self._datafile = b'%s.d.%s' % (self.radix, self.postfix)
693
693
694 self.nodeconstants = sha1nodeconstants
694 self.nodeconstants = sha1nodeconstants
695 self.nullid = self.nodeconstants.nullid
695 self.nullid = self.nodeconstants.nullid
696
696
697 # sparse-revlog can't be on without general-delta (issue6056)
697 # sparse-revlog can't be on without general-delta (issue6056)
698 if not self._generaldelta:
698 if not self._generaldelta:
699 self._sparserevlog = False
699 self._sparserevlog = False
700
700
701 self._storedeltachains = True
701 self._storedeltachains = True
702
702
703 devel_nodemap = (
703 devel_nodemap = (
704 self._nodemap_file
704 self._nodemap_file
705 and force_nodemap
705 and force_nodemap
706 and parse_index_v1_nodemap is not None
706 and parse_index_v1_nodemap is not None
707 )
707 )
708
708
709 use_rust_index = False
709 use_rust_index = False
710 if rustrevlog is not None:
710 if rustrevlog is not None:
711 if self._nodemap_file is not None:
711 if self._nodemap_file is not None:
712 use_rust_index = True
712 use_rust_index = True
713 else:
713 else:
714 use_rust_index = self.opener.options.get(b'rust.index')
714 use_rust_index = self.opener.options.get(b'rust.index')
715
715
716 self._parse_index = parse_index_v1
716 self._parse_index = parse_index_v1
717 if self._format_version == REVLOGV0:
717 if self._format_version == REVLOGV0:
718 self._parse_index = revlogv0.parse_index_v0
718 self._parse_index = revlogv0.parse_index_v0
719 elif self._format_version == REVLOGV2:
719 elif self._format_version == REVLOGV2:
720 self._parse_index = parse_index_v2
720 self._parse_index = parse_index_v2
721 elif self._format_version == CHANGELOGV2:
721 elif self._format_version == CHANGELOGV2:
722 self._parse_index = parse_index_cl_v2
722 self._parse_index = parse_index_cl_v2
723 elif devel_nodemap:
723 elif devel_nodemap:
724 self._parse_index = parse_index_v1_nodemap
724 self._parse_index = parse_index_v1_nodemap
725 elif use_rust_index:
725 elif use_rust_index:
726 self._parse_index = parse_index_v1_mixed
726 self._parse_index = parse_index_v1_mixed
727 try:
727 try:
728 d = self._parse_index(index_data, self._inline)
728 d = self._parse_index(index_data, self._inline)
729 index, chunkcache = d
729 index, chunkcache = d
730 use_nodemap = (
730 use_nodemap = (
731 not self._inline
731 not self._inline
732 and self._nodemap_file is not None
732 and self._nodemap_file is not None
733 and util.safehasattr(index, 'update_nodemap_data')
733 and util.safehasattr(index, 'update_nodemap_data')
734 )
734 )
735 if use_nodemap:
735 if use_nodemap:
736 nodemap_data = nodemaputil.persisted_data(self)
736 nodemap_data = nodemaputil.persisted_data(self)
737 if nodemap_data is not None:
737 if nodemap_data is not None:
738 docket = nodemap_data[0]
738 docket = nodemap_data[0]
739 if (
739 if (
740 len(d[0]) > docket.tip_rev
740 len(d[0]) > docket.tip_rev
741 and d[0][docket.tip_rev][7] == docket.tip_node
741 and d[0][docket.tip_rev][7] == docket.tip_node
742 ):
742 ):
743 # no changelog tampering
743 # no changelog tampering
744 self._nodemap_docket = docket
744 self._nodemap_docket = docket
745 index.update_nodemap_data(*nodemap_data)
745 index.update_nodemap_data(*nodemap_data)
746 except (ValueError, IndexError):
746 except (ValueError, IndexError):
747 raise error.RevlogError(
747 raise error.RevlogError(
748 _(b"index %s is corrupted") % self.display_id
748 _(b"index %s is corrupted") % self.display_id
749 )
749 )
750 self.index = index
750 self.index = index
751 self._segmentfile = randomaccessfile.randomaccessfile(
751 self._segmentfile = randomaccessfile.randomaccessfile(
752 self.opener,
752 self.opener,
753 (self._indexfile if self._inline else self._datafile),
753 (self._indexfile if self._inline else self._datafile),
754 self._chunkcachesize,
754 self._chunkcachesize,
755 chunkcache,
755 chunkcache,
756 )
756 )
757 self._segmentfile_sidedata = randomaccessfile.randomaccessfile(
757 self._segmentfile_sidedata = randomaccessfile.randomaccessfile(
758 self.opener,
758 self.opener,
759 self._sidedatafile,
759 self._sidedatafile,
760 self._chunkcachesize,
760 self._chunkcachesize,
761 )
761 )
762 # revnum -> (chain-length, sum-delta-length)
762 # revnum -> (chain-length, sum-delta-length)
763 self._chaininfocache = util.lrucachedict(500)
763 self._chaininfocache = util.lrucachedict(500)
764 # revlog header -> revlog compressor
764 # revlog header -> revlog compressor
765 self._decompressors = {}
765 self._decompressors = {}
766
766
767 def get_revlog(self):
767 def get_revlog(self):
768 """simple function to mirror API of other not-really-revlog API"""
768 """simple function to mirror API of other not-really-revlog API"""
769 return self
769 return self
770
770
771 @util.propertycache
771 @util.propertycache
772 def revlog_kind(self):
772 def revlog_kind(self):
773 return self.target[0]
773 return self.target[0]
774
774
775 @util.propertycache
775 @util.propertycache
776 def display_id(self):
776 def display_id(self):
777 """The public facing "ID" of the revlog that we use in message"""
777 """The public facing "ID" of the revlog that we use in message"""
778 if self.revlog_kind == KIND_FILELOG:
778 if self.revlog_kind == KIND_FILELOG:
779 # Reference the file without the "data/" prefix, so it is familiar
779 # Reference the file without the "data/" prefix, so it is familiar
780 # to the user.
780 # to the user.
781 return self.target[1]
781 return self.target[1]
782 else:
782 else:
783 return self.radix
783 return self.radix
784
784
785 def _get_decompressor(self, t):
785 def _get_decompressor(self, t):
786 try:
786 try:
787 compressor = self._decompressors[t]
787 compressor = self._decompressors[t]
788 except KeyError:
788 except KeyError:
789 try:
789 try:
790 engine = util.compengines.forrevlogheader(t)
790 engine = util.compengines.forrevlogheader(t)
791 compressor = engine.revlogcompressor(self._compengineopts)
791 compressor = engine.revlogcompressor(self._compengineopts)
792 self._decompressors[t] = compressor
792 self._decompressors[t] = compressor
793 except KeyError:
793 except KeyError:
794 raise error.RevlogError(
794 raise error.RevlogError(
795 _(b'unknown compression type %s') % binascii.hexlify(t)
795 _(b'unknown compression type %s') % binascii.hexlify(t)
796 )
796 )
797 return compressor
797 return compressor
798
798
799 @util.propertycache
799 @util.propertycache
800 def _compressor(self):
800 def _compressor(self):
801 engine = util.compengines[self._compengine]
801 engine = util.compengines[self._compengine]
802 return engine.revlogcompressor(self._compengineopts)
802 return engine.revlogcompressor(self._compengineopts)
803
803
804 @util.propertycache
804 @util.propertycache
805 def _decompressor(self):
805 def _decompressor(self):
806 """the default decompressor"""
806 """the default decompressor"""
807 if self._docket is None:
807 if self._docket is None:
808 return None
808 return None
809 t = self._docket.default_compression_header
809 t = self._docket.default_compression_header
810 c = self._get_decompressor(t)
810 c = self._get_decompressor(t)
811 return c.decompress
811 return c.decompress
812
812
813 def _indexfp(self):
813 def _indexfp(self):
814 """file object for the revlog's index file"""
814 """file object for the revlog's index file"""
815 return self.opener(self._indexfile, mode=b"r")
815 return self.opener(self._indexfile, mode=b"r")
816
816
817 def __index_write_fp(self):
817 def __index_write_fp(self):
818 # You should not use this directly and use `_writing` instead
818 # You should not use this directly and use `_writing` instead
819 try:
819 try:
820 f = self.opener(
820 f = self.opener(
821 self._indexfile, mode=b"r+", checkambig=self._checkambig
821 self._indexfile, mode=b"r+", checkambig=self._checkambig
822 )
822 )
823 if self._docket is None:
823 if self._docket is None:
824 f.seek(0, os.SEEK_END)
824 f.seek(0, os.SEEK_END)
825 else:
825 else:
826 f.seek(self._docket.index_end, os.SEEK_SET)
826 f.seek(self._docket.index_end, os.SEEK_SET)
827 return f
827 return f
828 except FileNotFoundError:
828 except FileNotFoundError:
829 return self.opener(
829 return self.opener(
830 self._indexfile, mode=b"w+", checkambig=self._checkambig
830 self._indexfile, mode=b"w+", checkambig=self._checkambig
831 )
831 )
832
832
833 def __index_new_fp(self):
833 def __index_new_fp(self):
834 # You should not use this unless you are upgrading from inline revlog
834 # You should not use this unless you are upgrading from inline revlog
835 return self.opener(
835 return self.opener(
836 self._indexfile,
836 self._indexfile,
837 mode=b"w",
837 mode=b"w",
838 checkambig=self._checkambig,
838 checkambig=self._checkambig,
839 atomictemp=True,
839 atomictemp=True,
840 )
840 )
841
841
842 def _datafp(self, mode=b'r'):
842 def _datafp(self, mode=b'r'):
843 """file object for the revlog's data file"""
843 """file object for the revlog's data file"""
844 return self.opener(self._datafile, mode=mode)
844 return self.opener(self._datafile, mode=mode)
845
845
846 @contextlib.contextmanager
846 @contextlib.contextmanager
847 def _sidedatareadfp(self):
847 def _sidedatareadfp(self):
848 """file object suitable to read sidedata"""
848 """file object suitable to read sidedata"""
849 if self._writinghandles:
849 if self._writinghandles:
850 yield self._writinghandles[2]
850 yield self._writinghandles[2]
851 else:
851 else:
852 with self.opener(self._sidedatafile) as fp:
852 with self.opener(self._sidedatafile) as fp:
853 yield fp
853 yield fp
854
854
855 def tiprev(self):
855 def tiprev(self):
856 return len(self.index) - 1
856 return len(self.index) - 1
857
857
858 def tip(self):
858 def tip(self):
859 return self.node(self.tiprev())
859 return self.node(self.tiprev())
860
860
861 def __contains__(self, rev):
861 def __contains__(self, rev):
862 return 0 <= rev < len(self)
862 return 0 <= rev < len(self)
863
863
864 def __len__(self):
864 def __len__(self):
865 return len(self.index)
865 return len(self.index)
866
866
867 def __iter__(self):
867 def __iter__(self):
868 return iter(range(len(self)))
868 return iter(range(len(self)))
869
869
870 def revs(self, start=0, stop=None):
870 def revs(self, start=0, stop=None):
871 """iterate over all rev in this revlog (from start to stop)"""
871 """iterate over all rev in this revlog (from start to stop)"""
872 return storageutil.iterrevs(len(self), start=start, stop=stop)
872 return storageutil.iterrevs(len(self), start=start, stop=stop)
873
873
874 def hasnode(self, node):
874 def hasnode(self, node):
875 try:
875 try:
876 self.rev(node)
876 self.rev(node)
877 return True
877 return True
878 except KeyError:
878 except KeyError:
879 return False
879 return False
880
880
881 def candelta(self, baserev, rev):
881 def candelta(self, baserev, rev):
882 """whether two revisions (baserev, rev) can be delta-ed or not"""
882 """whether two revisions (baserev, rev) can be delta-ed or not"""
883 # Disable delta if either rev requires a content-changing flag
883 # Disable delta if either rev requires a content-changing flag
884 # processor (ex. LFS). This is because such flag processor can alter
884 # processor (ex. LFS). This is because such flag processor can alter
885 # the rawtext content that the delta will be based on, and two clients
885 # the rawtext content that the delta will be based on, and two clients
886 # could have a same revlog node with different flags (i.e. different
886 # could have a same revlog node with different flags (i.e. different
887 # rawtext contents) and the delta could be incompatible.
887 # rawtext contents) and the delta could be incompatible.
888 if (self.flags(baserev) & REVIDX_RAWTEXT_CHANGING_FLAGS) or (
888 if (self.flags(baserev) & REVIDX_RAWTEXT_CHANGING_FLAGS) or (
889 self.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS
889 self.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS
890 ):
890 ):
891 return False
891 return False
892 return True
892 return True
893
893
894 def update_caches(self, transaction):
894 def update_caches(self, transaction):
895 if self._nodemap_file is not None:
895 if self._nodemap_file is not None:
896 if transaction is None:
896 if transaction is None:
897 nodemaputil.update_persistent_nodemap(self)
897 nodemaputil.update_persistent_nodemap(self)
898 else:
898 else:
899 nodemaputil.setup_persistent_nodemap(transaction, self)
899 nodemaputil.setup_persistent_nodemap(transaction, self)
900
900
901 def clearcaches(self):
901 def clearcaches(self):
902 self._revisioncache = None
902 self._revisioncache = None
903 self._chainbasecache.clear()
903 self._chainbasecache.clear()
904 self._segmentfile.clear_cache()
904 self._segmentfile.clear_cache()
905 self._segmentfile_sidedata.clear_cache()
905 self._segmentfile_sidedata.clear_cache()
906 self._pcache = {}
906 self._pcache = {}
907 self._nodemap_docket = None
907 self._nodemap_docket = None
908 self.index.clearcaches()
908 self.index.clearcaches()
909 # The python code is the one responsible for validating the docket, we
909 # The python code is the one responsible for validating the docket, we
910 # end up having to refresh it here.
910 # end up having to refresh it here.
911 use_nodemap = (
911 use_nodemap = (
912 not self._inline
912 not self._inline
913 and self._nodemap_file is not None
913 and self._nodemap_file is not None
914 and util.safehasattr(self.index, 'update_nodemap_data')
914 and util.safehasattr(self.index, 'update_nodemap_data')
915 )
915 )
916 if use_nodemap:
916 if use_nodemap:
917 nodemap_data = nodemaputil.persisted_data(self)
917 nodemap_data = nodemaputil.persisted_data(self)
918 if nodemap_data is not None:
918 if nodemap_data is not None:
919 self._nodemap_docket = nodemap_data[0]
919 self._nodemap_docket = nodemap_data[0]
920 self.index.update_nodemap_data(*nodemap_data)
920 self.index.update_nodemap_data(*nodemap_data)
921
921
922 def rev(self, node):
922 def rev(self, node):
923 try:
923 try:
924 return self.index.rev(node)
924 return self.index.rev(node)
925 except TypeError:
925 except TypeError:
926 raise
926 raise
927 except error.RevlogError:
927 except error.RevlogError:
928 # parsers.c radix tree lookup failed
928 # parsers.c radix tree lookup failed
929 if (
929 if (
930 node == self.nodeconstants.wdirid
930 node == self.nodeconstants.wdirid
931 or node in self.nodeconstants.wdirfilenodeids
931 or node in self.nodeconstants.wdirfilenodeids
932 ):
932 ):
933 raise error.WdirUnsupported
933 raise error.WdirUnsupported
934 raise error.LookupError(node, self.display_id, _(b'no node'))
934 raise error.LookupError(node, self.display_id, _(b'no node'))
935
935
936 # Accessors for index entries.
936 # Accessors for index entries.
937
937
938 # First tuple entry is 8 bytes. First 6 bytes are offset. Last 2 bytes
938 # First tuple entry is 8 bytes. First 6 bytes are offset. Last 2 bytes
939 # are flags.
939 # are flags.
940 def start(self, rev):
940 def start(self, rev):
941 return int(self.index[rev][0] >> 16)
941 return int(self.index[rev][0] >> 16)
942
942
943 def sidedata_cut_off(self, rev):
943 def sidedata_cut_off(self, rev):
944 sd_cut_off = self.index[rev][8]
944 sd_cut_off = self.index[rev][8]
945 if sd_cut_off != 0:
945 if sd_cut_off != 0:
946 return sd_cut_off
946 return sd_cut_off
947 # This is some annoying dance, because entries without sidedata
947 # This is some annoying dance, because entries without sidedata
948 # currently use 0 as their ofsset. (instead of previous-offset +
948 # currently use 0 as their ofsset. (instead of previous-offset +
949 # previous-size)
949 # previous-size)
950 #
950 #
951 # We should reconsider this sidedata → 0 sidata_offset policy.
951 # We should reconsider this sidedata → 0 sidata_offset policy.
952 # In the meantime, we need this.
952 # In the meantime, we need this.
953 while 0 <= rev:
953 while 0 <= rev:
954 e = self.index[rev]
954 e = self.index[rev]
955 if e[9] != 0:
955 if e[9] != 0:
956 return e[8] + e[9]
956 return e[8] + e[9]
957 rev -= 1
957 rev -= 1
958 return 0
958 return 0
959
959
960 def flags(self, rev):
960 def flags(self, rev):
961 return self.index[rev][0] & 0xFFFF
961 return self.index[rev][0] & 0xFFFF
962
962
963 def length(self, rev):
963 def length(self, rev):
964 return self.index[rev][1]
964 return self.index[rev][1]
965
965
966 def sidedata_length(self, rev):
966 def sidedata_length(self, rev):
967 if not self.hassidedata:
967 if not self.hassidedata:
968 return 0
968 return 0
969 return self.index[rev][9]
969 return self.index[rev][9]
970
970
971 def rawsize(self, rev):
971 def rawsize(self, rev):
972 """return the length of the uncompressed text for a given revision"""
972 """return the length of the uncompressed text for a given revision"""
973 l = self.index[rev][2]
973 l = self.index[rev][2]
974 if l >= 0:
974 if l >= 0:
975 return l
975 return l
976
976
977 t = self.rawdata(rev)
977 t = self.rawdata(rev)
978 return len(t)
978 return len(t)
979
979
980 def size(self, rev):
980 def size(self, rev):
981 """length of non-raw text (processed by a "read" flag processor)"""
981 """length of non-raw text (processed by a "read" flag processor)"""
982 # fast path: if no "read" flag processor could change the content,
982 # fast path: if no "read" flag processor could change the content,
983 # size is rawsize. note: ELLIPSIS is known to not change the content.
983 # size is rawsize. note: ELLIPSIS is known to not change the content.
984 flags = self.flags(rev)
984 flags = self.flags(rev)
985 if flags & (flagutil.REVIDX_KNOWN_FLAGS ^ REVIDX_ELLIPSIS) == 0:
985 if flags & (flagutil.REVIDX_KNOWN_FLAGS ^ REVIDX_ELLIPSIS) == 0:
986 return self.rawsize(rev)
986 return self.rawsize(rev)
987
987
988 return len(self.revision(rev))
988 return len(self.revision(rev))
989
989
990 def fast_rank(self, rev):
990 def fast_rank(self, rev):
991 """Return the rank of a revision if already known, or None otherwise.
991 """Return the rank of a revision if already known, or None otherwise.
992
992
993 The rank of a revision is the size of the sub-graph it defines as a
993 The rank of a revision is the size of the sub-graph it defines as a
994 head. Equivalently, the rank of a revision `r` is the size of the set
994 head. Equivalently, the rank of a revision `r` is the size of the set
995 `ancestors(r)`, `r` included.
995 `ancestors(r)`, `r` included.
996
996
997 This method returns the rank retrieved from the revlog in constant
997 This method returns the rank retrieved from the revlog in constant
998 time. It makes no attempt at computing unknown values for versions of
998 time. It makes no attempt at computing unknown values for versions of
999 the revlog which do not persist the rank.
999 the revlog which do not persist the rank.
1000 """
1000 """
1001 rank = self.index[rev][ENTRY_RANK]
1001 rank = self.index[rev][ENTRY_RANK]
1002 if self._format_version != CHANGELOGV2 or rank == RANK_UNKNOWN:
1002 if self._format_version != CHANGELOGV2 or rank == RANK_UNKNOWN:
1003 return None
1003 return None
1004 if rev == nullrev:
1004 if rev == nullrev:
1005 return 0 # convention
1005 return 0 # convention
1006 return rank
1006 return rank
1007
1007
1008 def chainbase(self, rev):
1008 def chainbase(self, rev):
1009 base = self._chainbasecache.get(rev)
1009 base = self._chainbasecache.get(rev)
1010 if base is not None:
1010 if base is not None:
1011 return base
1011 return base
1012
1012
1013 index = self.index
1013 index = self.index
1014 iterrev = rev
1014 iterrev = rev
1015 base = index[iterrev][3]
1015 base = index[iterrev][3]
1016 while base != iterrev:
1016 while base != iterrev:
1017 iterrev = base
1017 iterrev = base
1018 base = index[iterrev][3]
1018 base = index[iterrev][3]
1019
1019
1020 self._chainbasecache[rev] = base
1020 self._chainbasecache[rev] = base
1021 return base
1021 return base
1022
1022
1023 def linkrev(self, rev):
1023 def linkrev(self, rev):
1024 return self.index[rev][4]
1024 return self.index[rev][4]
1025
1025
1026 def parentrevs(self, rev):
1026 def parentrevs(self, rev):
1027 try:
1027 try:
1028 entry = self.index[rev]
1028 entry = self.index[rev]
1029 except IndexError:
1029 except IndexError:
1030 if rev == wdirrev:
1030 if rev == wdirrev:
1031 raise error.WdirUnsupported
1031 raise error.WdirUnsupported
1032 raise
1032 raise
1033
1033
1034 if self.canonical_parent_order and entry[5] == nullrev:
1034 if self.canonical_parent_order and entry[5] == nullrev:
1035 return entry[6], entry[5]
1035 return entry[6], entry[5]
1036 else:
1036 else:
1037 return entry[5], entry[6]
1037 return entry[5], entry[6]
1038
1038
1039 # fast parentrevs(rev) where rev isn't filtered
1039 # fast parentrevs(rev) where rev isn't filtered
1040 _uncheckedparentrevs = parentrevs
1040 _uncheckedparentrevs = parentrevs
1041
1041
1042 def node(self, rev):
1042 def node(self, rev):
1043 try:
1043 try:
1044 return self.index[rev][7]
1044 return self.index[rev][7]
1045 except IndexError:
1045 except IndexError:
1046 if rev == wdirrev:
1046 if rev == wdirrev:
1047 raise error.WdirUnsupported
1047 raise error.WdirUnsupported
1048 raise
1048 raise
1049
1049
1050 # Derived from index values.
1050 # Derived from index values.
1051
1051
1052 def end(self, rev):
1052 def end(self, rev):
1053 return self.start(rev) + self.length(rev)
1053 return self.start(rev) + self.length(rev)
1054
1054
1055 def parents(self, node):
1055 def parents(self, node):
1056 i = self.index
1056 i = self.index
1057 d = i[self.rev(node)]
1057 d = i[self.rev(node)]
1058 # inline node() to avoid function call overhead
1058 # inline node() to avoid function call overhead
1059 if self.canonical_parent_order and d[5] == self.nullid:
1059 if self.canonical_parent_order and d[5] == self.nullid:
1060 return i[d[6]][7], i[d[5]][7]
1060 return i[d[6]][7], i[d[5]][7]
1061 else:
1061 else:
1062 return i[d[5]][7], i[d[6]][7]
1062 return i[d[5]][7], i[d[6]][7]
1063
1063
1064 def chainlen(self, rev):
1064 def chainlen(self, rev):
1065 return self._chaininfo(rev)[0]
1065 return self._chaininfo(rev)[0]
1066
1066
1067 def _chaininfo(self, rev):
1067 def _chaininfo(self, rev):
1068 chaininfocache = self._chaininfocache
1068 chaininfocache = self._chaininfocache
1069 if rev in chaininfocache:
1069 if rev in chaininfocache:
1070 return chaininfocache[rev]
1070 return chaininfocache[rev]
1071 index = self.index
1071 index = self.index
1072 generaldelta = self._generaldelta
1072 generaldelta = self._generaldelta
1073 iterrev = rev
1073 iterrev = rev
1074 e = index[iterrev]
1074 e = index[iterrev]
1075 clen = 0
1075 clen = 0
1076 compresseddeltalen = 0
1076 compresseddeltalen = 0
1077 while iterrev != e[3]:
1077 while iterrev != e[3]:
1078 clen += 1
1078 clen += 1
1079 compresseddeltalen += e[1]
1079 compresseddeltalen += e[1]
1080 if generaldelta:
1080 if generaldelta:
1081 iterrev = e[3]
1081 iterrev = e[3]
1082 else:
1082 else:
1083 iterrev -= 1
1083 iterrev -= 1
1084 if iterrev in chaininfocache:
1084 if iterrev in chaininfocache:
1085 t = chaininfocache[iterrev]
1085 t = chaininfocache[iterrev]
1086 clen += t[0]
1086 clen += t[0]
1087 compresseddeltalen += t[1]
1087 compresseddeltalen += t[1]
1088 break
1088 break
1089 e = index[iterrev]
1089 e = index[iterrev]
1090 else:
1090 else:
1091 # Add text length of base since decompressing that also takes
1091 # Add text length of base since decompressing that also takes
1092 # work. For cache hits the length is already included.
1092 # work. For cache hits the length is already included.
1093 compresseddeltalen += e[1]
1093 compresseddeltalen += e[1]
1094 r = (clen, compresseddeltalen)
1094 r = (clen, compresseddeltalen)
1095 chaininfocache[rev] = r
1095 chaininfocache[rev] = r
1096 return r
1096 return r
1097
1097
1098 def _deltachain(self, rev, stoprev=None):
1098 def _deltachain(self, rev, stoprev=None):
1099 """Obtain the delta chain for a revision.
1099 """Obtain the delta chain for a revision.
1100
1100
1101 ``stoprev`` specifies a revision to stop at. If not specified, we
1101 ``stoprev`` specifies a revision to stop at. If not specified, we
1102 stop at the base of the chain.
1102 stop at the base of the chain.
1103
1103
1104 Returns a 2-tuple of (chain, stopped) where ``chain`` is a list of
1104 Returns a 2-tuple of (chain, stopped) where ``chain`` is a list of
1105 revs in ascending order and ``stopped`` is a bool indicating whether
1105 revs in ascending order and ``stopped`` is a bool indicating whether
1106 ``stoprev`` was hit.
1106 ``stoprev`` was hit.
1107 """
1107 """
1108 # Try C implementation.
1108 # Try C implementation.
1109 try:
1109 try:
1110 return self.index.deltachain(rev, stoprev, self._generaldelta)
1110 return self.index.deltachain(rev, stoprev, self._generaldelta)
1111 except AttributeError:
1111 except AttributeError:
1112 pass
1112 pass
1113
1113
1114 chain = []
1114 chain = []
1115
1115
1116 # Alias to prevent attribute lookup in tight loop.
1116 # Alias to prevent attribute lookup in tight loop.
1117 index = self.index
1117 index = self.index
1118 generaldelta = self._generaldelta
1118 generaldelta = self._generaldelta
1119
1119
1120 iterrev = rev
1120 iterrev = rev
1121 e = index[iterrev]
1121 e = index[iterrev]
1122 while iterrev != e[3] and iterrev != stoprev:
1122 while iterrev != e[3] and iterrev != stoprev:
1123 chain.append(iterrev)
1123 chain.append(iterrev)
1124 if generaldelta:
1124 if generaldelta:
1125 iterrev = e[3]
1125 iterrev = e[3]
1126 else:
1126 else:
1127 iterrev -= 1
1127 iterrev -= 1
1128 e = index[iterrev]
1128 e = index[iterrev]
1129
1129
1130 if iterrev == stoprev:
1130 if iterrev == stoprev:
1131 stopped = True
1131 stopped = True
1132 else:
1132 else:
1133 chain.append(iterrev)
1133 chain.append(iterrev)
1134 stopped = False
1134 stopped = False
1135
1135
1136 chain.reverse()
1136 chain.reverse()
1137 return chain, stopped
1137 return chain, stopped
1138
1138
1139 def ancestors(self, revs, stoprev=0, inclusive=False):
1139 def ancestors(self, revs, stoprev=0, inclusive=False):
1140 """Generate the ancestors of 'revs' in reverse revision order.
1140 """Generate the ancestors of 'revs' in reverse revision order.
1141 Does not generate revs lower than stoprev.
1141 Does not generate revs lower than stoprev.
1142
1142
1143 See the documentation for ancestor.lazyancestors for more details."""
1143 See the documentation for ancestor.lazyancestors for more details."""
1144
1144
1145 # first, make sure start revisions aren't filtered
1145 # first, make sure start revisions aren't filtered
1146 revs = list(revs)
1146 revs = list(revs)
1147 checkrev = self.node
1147 checkrev = self.node
1148 for r in revs:
1148 for r in revs:
1149 checkrev(r)
1149 checkrev(r)
1150 # and we're sure ancestors aren't filtered as well
1150 # and we're sure ancestors aren't filtered as well
1151
1151
1152 if rustancestor is not None and self.index.rust_ext_compat:
1152 if rustancestor is not None and self.index.rust_ext_compat:
1153 lazyancestors = rustancestor.LazyAncestors
1153 lazyancestors = rustancestor.LazyAncestors
1154 arg = self.index
1154 arg = self.index
1155 else:
1155 else:
1156 lazyancestors = ancestor.lazyancestors
1156 lazyancestors = ancestor.lazyancestors
1157 arg = self._uncheckedparentrevs
1157 arg = self._uncheckedparentrevs
1158 return lazyancestors(arg, revs, stoprev=stoprev, inclusive=inclusive)
1158 return lazyancestors(arg, revs, stoprev=stoprev, inclusive=inclusive)
1159
1159
1160 def descendants(self, revs):
1160 def descendants(self, revs):
1161 return dagop.descendantrevs(revs, self.revs, self.parentrevs)
1161 return dagop.descendantrevs(revs, self.revs, self.parentrevs)
1162
1162
1163 def findcommonmissing(self, common=None, heads=None):
1163 def findcommonmissing(self, common=None, heads=None):
1164 """Return a tuple of the ancestors of common and the ancestors of heads
1164 """Return a tuple of the ancestors of common and the ancestors of heads
1165 that are not ancestors of common. In revset terminology, we return the
1165 that are not ancestors of common. In revset terminology, we return the
1166 tuple:
1166 tuple:
1167
1167
1168 ::common, (::heads) - (::common)
1168 ::common, (::heads) - (::common)
1169
1169
1170 The list is sorted by revision number, meaning it is
1170 The list is sorted by revision number, meaning it is
1171 topologically sorted.
1171 topologically sorted.
1172
1172
1173 'heads' and 'common' are both lists of node IDs. If heads is
1173 'heads' and 'common' are both lists of node IDs. If heads is
1174 not supplied, uses all of the revlog's heads. If common is not
1174 not supplied, uses all of the revlog's heads. If common is not
1175 supplied, uses nullid."""
1175 supplied, uses nullid."""
1176 if common is None:
1176 if common is None:
1177 common = [self.nullid]
1177 common = [self.nullid]
1178 if heads is None:
1178 if heads is None:
1179 heads = self.heads()
1179 heads = self.heads()
1180
1180
1181 common = [self.rev(n) for n in common]
1181 common = [self.rev(n) for n in common]
1182 heads = [self.rev(n) for n in heads]
1182 heads = [self.rev(n) for n in heads]
1183
1183
1184 # we want the ancestors, but inclusive
1184 # we want the ancestors, but inclusive
1185 class lazyset:
1185 class lazyset:
1186 def __init__(self, lazyvalues):
1186 def __init__(self, lazyvalues):
1187 self.addedvalues = set()
1187 self.addedvalues = set()
1188 self.lazyvalues = lazyvalues
1188 self.lazyvalues = lazyvalues
1189
1189
1190 def __contains__(self, value):
1190 def __contains__(self, value):
1191 return value in self.addedvalues or value in self.lazyvalues
1191 return value in self.addedvalues or value in self.lazyvalues
1192
1192
1193 def __iter__(self):
1193 def __iter__(self):
1194 added = self.addedvalues
1194 added = self.addedvalues
1195 for r in added:
1195 for r in added:
1196 yield r
1196 yield r
1197 for r in self.lazyvalues:
1197 for r in self.lazyvalues:
1198 if not r in added:
1198 if not r in added:
1199 yield r
1199 yield r
1200
1200
1201 def add(self, value):
1201 def add(self, value):
1202 self.addedvalues.add(value)
1202 self.addedvalues.add(value)
1203
1203
1204 def update(self, values):
1204 def update(self, values):
1205 self.addedvalues.update(values)
1205 self.addedvalues.update(values)
1206
1206
1207 has = lazyset(self.ancestors(common))
1207 has = lazyset(self.ancestors(common))
1208 has.add(nullrev)
1208 has.add(nullrev)
1209 has.update(common)
1209 has.update(common)
1210
1210
1211 # take all ancestors from heads that aren't in has
1211 # take all ancestors from heads that aren't in has
1212 missing = set()
1212 missing = set()
1213 visit = collections.deque(r for r in heads if r not in has)
1213 visit = collections.deque(r for r in heads if r not in has)
1214 while visit:
1214 while visit:
1215 r = visit.popleft()
1215 r = visit.popleft()
1216 if r in missing:
1216 if r in missing:
1217 continue
1217 continue
1218 else:
1218 else:
1219 missing.add(r)
1219 missing.add(r)
1220 for p in self.parentrevs(r):
1220 for p in self.parentrevs(r):
1221 if p not in has:
1221 if p not in has:
1222 visit.append(p)
1222 visit.append(p)
1223 missing = list(missing)
1223 missing = list(missing)
1224 missing.sort()
1224 missing.sort()
1225 return has, [self.node(miss) for miss in missing]
1225 return has, [self.node(miss) for miss in missing]
1226
1226
1227 def incrementalmissingrevs(self, common=None):
1227 def incrementalmissingrevs(self, common=None):
1228 """Return an object that can be used to incrementally compute the
1228 """Return an object that can be used to incrementally compute the
1229 revision numbers of the ancestors of arbitrary sets that are not
1229 revision numbers of the ancestors of arbitrary sets that are not
1230 ancestors of common. This is an ancestor.incrementalmissingancestors
1230 ancestors of common. This is an ancestor.incrementalmissingancestors
1231 object.
1231 object.
1232
1232
1233 'common' is a list of revision numbers. If common is not supplied, uses
1233 'common' is a list of revision numbers. If common is not supplied, uses
1234 nullrev.
1234 nullrev.
1235 """
1235 """
1236 if common is None:
1236 if common is None:
1237 common = [nullrev]
1237 common = [nullrev]
1238
1238
1239 if rustancestor is not None and self.index.rust_ext_compat:
1239 if rustancestor is not None and self.index.rust_ext_compat:
1240 return rustancestor.MissingAncestors(self.index, common)
1240 return rustancestor.MissingAncestors(self.index, common)
1241 return ancestor.incrementalmissingancestors(self.parentrevs, common)
1241 return ancestor.incrementalmissingancestors(self.parentrevs, common)
1242
1242
1243 def findmissingrevs(self, common=None, heads=None):
1243 def findmissingrevs(self, common=None, heads=None):
1244 """Return the revision numbers of the ancestors of heads that
1244 """Return the revision numbers of the ancestors of heads that
1245 are not ancestors of common.
1245 are not ancestors of common.
1246
1246
1247 More specifically, return a list of revision numbers corresponding to
1247 More specifically, return a list of revision numbers corresponding to
1248 nodes N such that every N satisfies the following constraints:
1248 nodes N such that every N satisfies the following constraints:
1249
1249
1250 1. N is an ancestor of some node in 'heads'
1250 1. N is an ancestor of some node in 'heads'
1251 2. N is not an ancestor of any node in 'common'
1251 2. N is not an ancestor of any node in 'common'
1252
1252
1253 The list is sorted by revision number, meaning it is
1253 The list is sorted by revision number, meaning it is
1254 topologically sorted.
1254 topologically sorted.
1255
1255
1256 'heads' and 'common' are both lists of revision numbers. If heads is
1256 'heads' and 'common' are both lists of revision numbers. If heads is
1257 not supplied, uses all of the revlog's heads. If common is not
1257 not supplied, uses all of the revlog's heads. If common is not
1258 supplied, uses nullid."""
1258 supplied, uses nullid."""
1259 if common is None:
1259 if common is None:
1260 common = [nullrev]
1260 common = [nullrev]
1261 if heads is None:
1261 if heads is None:
1262 heads = self.headrevs()
1262 heads = self.headrevs()
1263
1263
1264 inc = self.incrementalmissingrevs(common=common)
1264 inc = self.incrementalmissingrevs(common=common)
1265 return inc.missingancestors(heads)
1265 return inc.missingancestors(heads)
1266
1266
1267 def findmissing(self, common=None, heads=None):
1267 def findmissing(self, common=None, heads=None):
1268 """Return the ancestors of heads that are not ancestors of common.
1268 """Return the ancestors of heads that are not ancestors of common.
1269
1269
1270 More specifically, return a list of nodes N such that every N
1270 More specifically, return a list of nodes N such that every N
1271 satisfies the following constraints:
1271 satisfies the following constraints:
1272
1272
1273 1. N is an ancestor of some node in 'heads'
1273 1. N is an ancestor of some node in 'heads'
1274 2. N is not an ancestor of any node in 'common'
1274 2. N is not an ancestor of any node in 'common'
1275
1275
1276 The list is sorted by revision number, meaning it is
1276 The list is sorted by revision number, meaning it is
1277 topologically sorted.
1277 topologically sorted.
1278
1278
1279 'heads' and 'common' are both lists of node IDs. If heads is
1279 'heads' and 'common' are both lists of node IDs. If heads is
1280 not supplied, uses all of the revlog's heads. If common is not
1280 not supplied, uses all of the revlog's heads. If common is not
1281 supplied, uses nullid."""
1281 supplied, uses nullid."""
1282 if common is None:
1282 if common is None:
1283 common = [self.nullid]
1283 common = [self.nullid]
1284 if heads is None:
1284 if heads is None:
1285 heads = self.heads()
1285 heads = self.heads()
1286
1286
1287 common = [self.rev(n) for n in common]
1287 common = [self.rev(n) for n in common]
1288 heads = [self.rev(n) for n in heads]
1288 heads = [self.rev(n) for n in heads]
1289
1289
1290 inc = self.incrementalmissingrevs(common=common)
1290 inc = self.incrementalmissingrevs(common=common)
1291 return [self.node(r) for r in inc.missingancestors(heads)]
1291 return [self.node(r) for r in inc.missingancestors(heads)]
1292
1292
1293 def nodesbetween(self, roots=None, heads=None):
1293 def nodesbetween(self, roots=None, heads=None):
1294 """Return a topological path from 'roots' to 'heads'.
1294 """Return a topological path from 'roots' to 'heads'.
1295
1295
1296 Return a tuple (nodes, outroots, outheads) where 'nodes' is a
1296 Return a tuple (nodes, outroots, outheads) where 'nodes' is a
1297 topologically sorted list of all nodes N that satisfy both of
1297 topologically sorted list of all nodes N that satisfy both of
1298 these constraints:
1298 these constraints:
1299
1299
1300 1. N is a descendant of some node in 'roots'
1300 1. N is a descendant of some node in 'roots'
1301 2. N is an ancestor of some node in 'heads'
1301 2. N is an ancestor of some node in 'heads'
1302
1302
1303 Every node is considered to be both a descendant and an ancestor
1303 Every node is considered to be both a descendant and an ancestor
1304 of itself, so every reachable node in 'roots' and 'heads' will be
1304 of itself, so every reachable node in 'roots' and 'heads' will be
1305 included in 'nodes'.
1305 included in 'nodes'.
1306
1306
1307 'outroots' is the list of reachable nodes in 'roots', i.e., the
1307 'outroots' is the list of reachable nodes in 'roots', i.e., the
1308 subset of 'roots' that is returned in 'nodes'. Likewise,
1308 subset of 'roots' that is returned in 'nodes'. Likewise,
1309 'outheads' is the subset of 'heads' that is also in 'nodes'.
1309 'outheads' is the subset of 'heads' that is also in 'nodes'.
1310
1310
1311 'roots' and 'heads' are both lists of node IDs. If 'roots' is
1311 'roots' and 'heads' are both lists of node IDs. If 'roots' is
1312 unspecified, uses nullid as the only root. If 'heads' is
1312 unspecified, uses nullid as the only root. If 'heads' is
1313 unspecified, uses list of all of the revlog's heads."""
1313 unspecified, uses list of all of the revlog's heads."""
1314 nonodes = ([], [], [])
1314 nonodes = ([], [], [])
1315 if roots is not None:
1315 if roots is not None:
1316 roots = list(roots)
1316 roots = list(roots)
1317 if not roots:
1317 if not roots:
1318 return nonodes
1318 return nonodes
1319 lowestrev = min([self.rev(n) for n in roots])
1319 lowestrev = min([self.rev(n) for n in roots])
1320 else:
1320 else:
1321 roots = [self.nullid] # Everybody's a descendant of nullid
1321 roots = [self.nullid] # Everybody's a descendant of nullid
1322 lowestrev = nullrev
1322 lowestrev = nullrev
1323 if (lowestrev == nullrev) and (heads is None):
1323 if (lowestrev == nullrev) and (heads is None):
1324 # We want _all_ the nodes!
1324 # We want _all_ the nodes!
1325 return (
1325 return (
1326 [self.node(r) for r in self],
1326 [self.node(r) for r in self],
1327 [self.nullid],
1327 [self.nullid],
1328 list(self.heads()),
1328 list(self.heads()),
1329 )
1329 )
1330 if heads is None:
1330 if heads is None:
1331 # All nodes are ancestors, so the latest ancestor is the last
1331 # All nodes are ancestors, so the latest ancestor is the last
1332 # node.
1332 # node.
1333 highestrev = len(self) - 1
1333 highestrev = len(self) - 1
1334 # Set ancestors to None to signal that every node is an ancestor.
1334 # Set ancestors to None to signal that every node is an ancestor.
1335 ancestors = None
1335 ancestors = None
1336 # Set heads to an empty dictionary for later discovery of heads
1336 # Set heads to an empty dictionary for later discovery of heads
1337 heads = {}
1337 heads = {}
1338 else:
1338 else:
1339 heads = list(heads)
1339 heads = list(heads)
1340 if not heads:
1340 if not heads:
1341 return nonodes
1341 return nonodes
1342 ancestors = set()
1342 ancestors = set()
1343 # Turn heads into a dictionary so we can remove 'fake' heads.
1343 # Turn heads into a dictionary so we can remove 'fake' heads.
1344 # Also, later we will be using it to filter out the heads we can't
1344 # Also, later we will be using it to filter out the heads we can't
1345 # find from roots.
1345 # find from roots.
1346 heads = dict.fromkeys(heads, False)
1346 heads = dict.fromkeys(heads, False)
1347 # Start at the top and keep marking parents until we're done.
1347 # Start at the top and keep marking parents until we're done.
1348 nodestotag = set(heads)
1348 nodestotag = set(heads)
1349 # Remember where the top was so we can use it as a limit later.
1349 # Remember where the top was so we can use it as a limit later.
1350 highestrev = max([self.rev(n) for n in nodestotag])
1350 highestrev = max([self.rev(n) for n in nodestotag])
1351 while nodestotag:
1351 while nodestotag:
1352 # grab a node to tag
1352 # grab a node to tag
1353 n = nodestotag.pop()
1353 n = nodestotag.pop()
1354 # Never tag nullid
1354 # Never tag nullid
1355 if n == self.nullid:
1355 if n == self.nullid:
1356 continue
1356 continue
1357 # A node's revision number represents its place in a
1357 # A node's revision number represents its place in a
1358 # topologically sorted list of nodes.
1358 # topologically sorted list of nodes.
1359 r = self.rev(n)
1359 r = self.rev(n)
1360 if r >= lowestrev:
1360 if r >= lowestrev:
1361 if n not in ancestors:
1361 if n not in ancestors:
1362 # If we are possibly a descendant of one of the roots
1362 # If we are possibly a descendant of one of the roots
1363 # and we haven't already been marked as an ancestor
1363 # and we haven't already been marked as an ancestor
1364 ancestors.add(n) # Mark as ancestor
1364 ancestors.add(n) # Mark as ancestor
1365 # Add non-nullid parents to list of nodes to tag.
1365 # Add non-nullid parents to list of nodes to tag.
1366 nodestotag.update(
1366 nodestotag.update(
1367 [p for p in self.parents(n) if p != self.nullid]
1367 [p for p in self.parents(n) if p != self.nullid]
1368 )
1368 )
1369 elif n in heads: # We've seen it before, is it a fake head?
1369 elif n in heads: # We've seen it before, is it a fake head?
1370 # So it is, real heads should not be the ancestors of
1370 # So it is, real heads should not be the ancestors of
1371 # any other heads.
1371 # any other heads.
1372 heads.pop(n)
1372 heads.pop(n)
1373 if not ancestors:
1373 if not ancestors:
1374 return nonodes
1374 return nonodes
1375 # Now that we have our set of ancestors, we want to remove any
1375 # Now that we have our set of ancestors, we want to remove any
1376 # roots that are not ancestors.
1376 # roots that are not ancestors.
1377
1377
1378 # If one of the roots was nullid, everything is included anyway.
1378 # If one of the roots was nullid, everything is included anyway.
1379 if lowestrev > nullrev:
1379 if lowestrev > nullrev:
1380 # But, since we weren't, let's recompute the lowest rev to not
1380 # But, since we weren't, let's recompute the lowest rev to not
1381 # include roots that aren't ancestors.
1381 # include roots that aren't ancestors.
1382
1382
1383 # Filter out roots that aren't ancestors of heads
1383 # Filter out roots that aren't ancestors of heads
1384 roots = [root for root in roots if root in ancestors]
1384 roots = [root for root in roots if root in ancestors]
1385 # Recompute the lowest revision
1385 # Recompute the lowest revision
1386 if roots:
1386 if roots:
1387 lowestrev = min([self.rev(root) for root in roots])
1387 lowestrev = min([self.rev(root) for root in roots])
1388 else:
1388 else:
1389 # No more roots? Return empty list
1389 # No more roots? Return empty list
1390 return nonodes
1390 return nonodes
1391 else:
1391 else:
1392 # We are descending from nullid, and don't need to care about
1392 # We are descending from nullid, and don't need to care about
1393 # any other roots.
1393 # any other roots.
1394 lowestrev = nullrev
1394 lowestrev = nullrev
1395 roots = [self.nullid]
1395 roots = [self.nullid]
1396 # Transform our roots list into a set.
1396 # Transform our roots list into a set.
1397 descendants = set(roots)
1397 descendants = set(roots)
1398 # Also, keep the original roots so we can filter out roots that aren't
1398 # Also, keep the original roots so we can filter out roots that aren't
1399 # 'real' roots (i.e. are descended from other roots).
1399 # 'real' roots (i.e. are descended from other roots).
1400 roots = descendants.copy()
1400 roots = descendants.copy()
1401 # Our topologically sorted list of output nodes.
1401 # Our topologically sorted list of output nodes.
1402 orderedout = []
1402 orderedout = []
1403 # Don't start at nullid since we don't want nullid in our output list,
1403 # Don't start at nullid since we don't want nullid in our output list,
1404 # and if nullid shows up in descendants, empty parents will look like
1404 # and if nullid shows up in descendants, empty parents will look like
1405 # they're descendants.
1405 # they're descendants.
1406 for r in self.revs(start=max(lowestrev, 0), stop=highestrev + 1):
1406 for r in self.revs(start=max(lowestrev, 0), stop=highestrev + 1):
1407 n = self.node(r)
1407 n = self.node(r)
1408 isdescendant = False
1408 isdescendant = False
1409 if lowestrev == nullrev: # Everybody is a descendant of nullid
1409 if lowestrev == nullrev: # Everybody is a descendant of nullid
1410 isdescendant = True
1410 isdescendant = True
1411 elif n in descendants:
1411 elif n in descendants:
1412 # n is already a descendant
1412 # n is already a descendant
1413 isdescendant = True
1413 isdescendant = True
1414 # This check only needs to be done here because all the roots
1414 # This check only needs to be done here because all the roots
1415 # will start being marked is descendants before the loop.
1415 # will start being marked is descendants before the loop.
1416 if n in roots:
1416 if n in roots:
1417 # If n was a root, check if it's a 'real' root.
1417 # If n was a root, check if it's a 'real' root.
1418 p = tuple(self.parents(n))
1418 p = tuple(self.parents(n))
1419 # If any of its parents are descendants, it's not a root.
1419 # If any of its parents are descendants, it's not a root.
1420 if (p[0] in descendants) or (p[1] in descendants):
1420 if (p[0] in descendants) or (p[1] in descendants):
1421 roots.remove(n)
1421 roots.remove(n)
1422 else:
1422 else:
1423 p = tuple(self.parents(n))
1423 p = tuple(self.parents(n))
1424 # A node is a descendant if either of its parents are
1424 # A node is a descendant if either of its parents are
1425 # descendants. (We seeded the dependents list with the roots
1425 # descendants. (We seeded the dependents list with the roots
1426 # up there, remember?)
1426 # up there, remember?)
1427 if (p[0] in descendants) or (p[1] in descendants):
1427 if (p[0] in descendants) or (p[1] in descendants):
1428 descendants.add(n)
1428 descendants.add(n)
1429 isdescendant = True
1429 isdescendant = True
1430 if isdescendant and ((ancestors is None) or (n in ancestors)):
1430 if isdescendant and ((ancestors is None) or (n in ancestors)):
1431 # Only include nodes that are both descendants and ancestors.
1431 # Only include nodes that are both descendants and ancestors.
1432 orderedout.append(n)
1432 orderedout.append(n)
1433 if (ancestors is not None) and (n in heads):
1433 if (ancestors is not None) and (n in heads):
1434 # We're trying to figure out which heads are reachable
1434 # We're trying to figure out which heads are reachable
1435 # from roots.
1435 # from roots.
1436 # Mark this head as having been reached
1436 # Mark this head as having been reached
1437 heads[n] = True
1437 heads[n] = True
1438 elif ancestors is None:
1438 elif ancestors is None:
1439 # Otherwise, we're trying to discover the heads.
1439 # Otherwise, we're trying to discover the heads.
1440 # Assume this is a head because if it isn't, the next step
1440 # Assume this is a head because if it isn't, the next step
1441 # will eventually remove it.
1441 # will eventually remove it.
1442 heads[n] = True
1442 heads[n] = True
1443 # But, obviously its parents aren't.
1443 # But, obviously its parents aren't.
1444 for p in self.parents(n):
1444 for p in self.parents(n):
1445 heads.pop(p, None)
1445 heads.pop(p, None)
1446 heads = [head for head, flag in heads.items() if flag]
1446 heads = [head for head, flag in heads.items() if flag]
1447 roots = list(roots)
1447 roots = list(roots)
1448 assert orderedout
1448 assert orderedout
1449 assert roots
1449 assert roots
1450 assert heads
1450 assert heads
1451 return (orderedout, roots, heads)
1451 return (orderedout, roots, heads)
1452
1452
1453 def headrevs(self, revs=None):
1453 def headrevs(self, revs=None):
1454 if revs is None:
1454 if revs is None:
1455 try:
1455 try:
1456 return self.index.headrevs()
1456 return self.index.headrevs()
1457 except AttributeError:
1457 except AttributeError:
1458 return self._headrevs()
1458 return self._headrevs()
1459 if rustdagop is not None and self.index.rust_ext_compat:
1459 if rustdagop is not None and self.index.rust_ext_compat:
1460 return rustdagop.headrevs(self.index, revs)
1460 return rustdagop.headrevs(self.index, revs)
1461 return dagop.headrevs(revs, self._uncheckedparentrevs)
1461 return dagop.headrevs(revs, self._uncheckedparentrevs)
1462
1462
1463 def computephases(self, roots):
1463 def computephases(self, roots):
1464 return self.index.computephasesmapsets(roots)
1464 return self.index.computephasesmapsets(roots)
1465
1465
1466 def _headrevs(self):
1466 def _headrevs(self):
1467 count = len(self)
1467 count = len(self)
1468 if not count:
1468 if not count:
1469 return [nullrev]
1469 return [nullrev]
1470 # we won't iter over filtered rev so nobody is a head at start
1470 # we won't iter over filtered rev so nobody is a head at start
1471 ishead = [0] * (count + 1)
1471 ishead = [0] * (count + 1)
1472 index = self.index
1472 index = self.index
1473 for r in self:
1473 for r in self:
1474 ishead[r] = 1 # I may be an head
1474 ishead[r] = 1 # I may be an head
1475 e = index[r]
1475 e = index[r]
1476 ishead[e[5]] = ishead[e[6]] = 0 # my parent are not
1476 ishead[e[5]] = ishead[e[6]] = 0 # my parent are not
1477 return [r for r, val in enumerate(ishead) if val]
1477 return [r for r, val in enumerate(ishead) if val]
1478
1478
1479 def heads(self, start=None, stop=None):
1479 def heads(self, start=None, stop=None):
1480 """return the list of all nodes that have no children
1480 """return the list of all nodes that have no children
1481
1481
1482 if start is specified, only heads that are descendants of
1482 if start is specified, only heads that are descendants of
1483 start will be returned
1483 start will be returned
1484 if stop is specified, it will consider all the revs from stop
1484 if stop is specified, it will consider all the revs from stop
1485 as if they had no children
1485 as if they had no children
1486 """
1486 """
1487 if start is None and stop is None:
1487 if start is None and stop is None:
1488 if not len(self):
1488 if not len(self):
1489 return [self.nullid]
1489 return [self.nullid]
1490 return [self.node(r) for r in self.headrevs()]
1490 return [self.node(r) for r in self.headrevs()]
1491
1491
1492 if start is None:
1492 if start is None:
1493 start = nullrev
1493 start = nullrev
1494 else:
1494 else:
1495 start = self.rev(start)
1495 start = self.rev(start)
1496
1496
1497 stoprevs = {self.rev(n) for n in stop or []}
1497 stoprevs = {self.rev(n) for n in stop or []}
1498
1498
1499 revs = dagop.headrevssubset(
1499 revs = dagop.headrevssubset(
1500 self.revs, self.parentrevs, startrev=start, stoprevs=stoprevs
1500 self.revs, self.parentrevs, startrev=start, stoprevs=stoprevs
1501 )
1501 )
1502
1502
1503 return [self.node(rev) for rev in revs]
1503 return [self.node(rev) for rev in revs]
1504
1504
1505 def children(self, node):
1505 def children(self, node):
1506 """find the children of a given node"""
1506 """find the children of a given node"""
1507 c = []
1507 c = []
1508 p = self.rev(node)
1508 p = self.rev(node)
1509 for r in self.revs(start=p + 1):
1509 for r in self.revs(start=p + 1):
1510 prevs = [pr for pr in self.parentrevs(r) if pr != nullrev]
1510 prevs = [pr for pr in self.parentrevs(r) if pr != nullrev]
1511 if prevs:
1511 if prevs:
1512 for pr in prevs:
1512 for pr in prevs:
1513 if pr == p:
1513 if pr == p:
1514 c.append(self.node(r))
1514 c.append(self.node(r))
1515 elif p == nullrev:
1515 elif p == nullrev:
1516 c.append(self.node(r))
1516 c.append(self.node(r))
1517 return c
1517 return c
1518
1518
1519 def commonancestorsheads(self, a, b):
1519 def commonancestorsheads(self, a, b):
1520 """calculate all the heads of the common ancestors of nodes a and b"""
1520 """calculate all the heads of the common ancestors of nodes a and b"""
1521 a, b = self.rev(a), self.rev(b)
1521 a, b = self.rev(a), self.rev(b)
1522 ancs = self._commonancestorsheads(a, b)
1522 ancs = self._commonancestorsheads(a, b)
1523 return pycompat.maplist(self.node, ancs)
1523 return pycompat.maplist(self.node, ancs)
1524
1524
1525 def _commonancestorsheads(self, *revs):
1525 def _commonancestorsheads(self, *revs):
1526 """calculate all the heads of the common ancestors of revs"""
1526 """calculate all the heads of the common ancestors of revs"""
1527 try:
1527 try:
1528 ancs = self.index.commonancestorsheads(*revs)
1528 ancs = self.index.commonancestorsheads(*revs)
1529 except (AttributeError, OverflowError): # C implementation failed
1529 except (AttributeError, OverflowError): # C implementation failed
1530 ancs = ancestor.commonancestorsheads(self.parentrevs, *revs)
1530 ancs = ancestor.commonancestorsheads(self.parentrevs, *revs)
1531 return ancs
1531 return ancs
1532
1532
1533 def isancestor(self, a, b):
1533 def isancestor(self, a, b):
1534 """return True if node a is an ancestor of node b
1534 """return True if node a is an ancestor of node b
1535
1535
1536 A revision is considered an ancestor of itself."""
1536 A revision is considered an ancestor of itself."""
1537 a, b = self.rev(a), self.rev(b)
1537 a, b = self.rev(a), self.rev(b)
1538 return self.isancestorrev(a, b)
1538 return self.isancestorrev(a, b)
1539
1539
1540 def isancestorrev(self, a, b):
1540 def isancestorrev(self, a, b):
1541 """return True if revision a is an ancestor of revision b
1541 """return True if revision a is an ancestor of revision b
1542
1542
1543 A revision is considered an ancestor of itself.
1543 A revision is considered an ancestor of itself.
1544
1544
1545 The implementation of this is trivial but the use of
1545 The implementation of this is trivial but the use of
1546 reachableroots is not."""
1546 reachableroots is not."""
1547 if a == nullrev:
1547 if a == nullrev:
1548 return True
1548 return True
1549 elif a == b:
1549 elif a == b:
1550 return True
1550 return True
1551 elif a > b:
1551 elif a > b:
1552 return False
1552 return False
1553 return bool(self.reachableroots(a, [b], [a], includepath=False))
1553 return bool(self.reachableroots(a, [b], [a], includepath=False))
1554
1554
1555 def reachableroots(self, minroot, heads, roots, includepath=False):
1555 def reachableroots(self, minroot, heads, roots, includepath=False):
1556 """return (heads(::(<roots> and <roots>::<heads>)))
1556 """return (heads(::(<roots> and <roots>::<heads>)))
1557
1557
1558 If includepath is True, return (<roots>::<heads>)."""
1558 If includepath is True, return (<roots>::<heads>)."""
1559 try:
1559 try:
1560 return self.index.reachableroots2(
1560 return self.index.reachableroots2(
1561 minroot, heads, roots, includepath
1561 minroot, heads, roots, includepath
1562 )
1562 )
1563 except AttributeError:
1563 except AttributeError:
1564 return dagop._reachablerootspure(
1564 return dagop._reachablerootspure(
1565 self.parentrevs, minroot, roots, heads, includepath
1565 self.parentrevs, minroot, roots, heads, includepath
1566 )
1566 )
1567
1567
1568 def ancestor(self, a, b):
1568 def ancestor(self, a, b):
1569 """calculate the "best" common ancestor of nodes a and b"""
1569 """calculate the "best" common ancestor of nodes a and b"""
1570
1570
1571 a, b = self.rev(a), self.rev(b)
1571 a, b = self.rev(a), self.rev(b)
1572 try:
1572 try:
1573 ancs = self.index.ancestors(a, b)
1573 ancs = self.index.ancestors(a, b)
1574 except (AttributeError, OverflowError):
1574 except (AttributeError, OverflowError):
1575 ancs = ancestor.ancestors(self.parentrevs, a, b)
1575 ancs = ancestor.ancestors(self.parentrevs, a, b)
1576 if ancs:
1576 if ancs:
1577 # choose a consistent winner when there's a tie
1577 # choose a consistent winner when there's a tie
1578 return min(map(self.node, ancs))
1578 return min(map(self.node, ancs))
1579 return self.nullid
1579 return self.nullid
1580
1580
1581 def _match(self, id):
1581 def _match(self, id):
1582 if isinstance(id, int):
1582 if isinstance(id, int):
1583 # rev
1583 # rev
1584 return self.node(id)
1584 return self.node(id)
1585 if len(id) == self.nodeconstants.nodelen:
1585 if len(id) == self.nodeconstants.nodelen:
1586 # possibly a binary node
1586 # possibly a binary node
1587 # odds of a binary node being all hex in ASCII are 1 in 10**25
1587 # odds of a binary node being all hex in ASCII are 1 in 10**25
1588 try:
1588 try:
1589 node = id
1589 node = id
1590 self.rev(node) # quick search the index
1590 self.rev(node) # quick search the index
1591 return node
1591 return node
1592 except error.LookupError:
1592 except error.LookupError:
1593 pass # may be partial hex id
1593 pass # may be partial hex id
1594 try:
1594 try:
1595 # str(rev)
1595 # str(rev)
1596 rev = int(id)
1596 rev = int(id)
1597 if b"%d" % rev != id:
1597 if b"%d" % rev != id:
1598 raise ValueError
1598 raise ValueError
1599 if rev < 0:
1599 if rev < 0:
1600 rev = len(self) + rev
1600 rev = len(self) + rev
1601 if rev < 0 or rev >= len(self):
1601 if rev < 0 or rev >= len(self):
1602 raise ValueError
1602 raise ValueError
1603 return self.node(rev)
1603 return self.node(rev)
1604 except (ValueError, OverflowError):
1604 except (ValueError, OverflowError):
1605 pass
1605 pass
1606 if len(id) == 2 * self.nodeconstants.nodelen:
1606 if len(id) == 2 * self.nodeconstants.nodelen:
1607 try:
1607 try:
1608 # a full hex nodeid?
1608 # a full hex nodeid?
1609 node = bin(id)
1609 node = bin(id)
1610 self.rev(node)
1610 self.rev(node)
1611 return node
1611 return node
1612 except (binascii.Error, error.LookupError):
1612 except (binascii.Error, error.LookupError):
1613 pass
1613 pass
1614
1614
1615 def _partialmatch(self, id):
1615 def _partialmatch(self, id):
1616 # we don't care wdirfilenodeids as they should be always full hash
1616 # we don't care wdirfilenodeids as they should be always full hash
1617 maybewdir = self.nodeconstants.wdirhex.startswith(id)
1617 maybewdir = self.nodeconstants.wdirhex.startswith(id)
1618 ambiguous = False
1618 ambiguous = False
1619 try:
1619 try:
1620 partial = self.index.partialmatch(id)
1620 partial = self.index.partialmatch(id)
1621 if partial and self.hasnode(partial):
1621 if partial and self.hasnode(partial):
1622 if maybewdir:
1622 if maybewdir:
1623 # single 'ff...' match in radix tree, ambiguous with wdir
1623 # single 'ff...' match in radix tree, ambiguous with wdir
1624 ambiguous = True
1624 ambiguous = True
1625 else:
1625 else:
1626 return partial
1626 return partial
1627 elif maybewdir:
1627 elif maybewdir:
1628 # no 'ff...' match in radix tree, wdir identified
1628 # no 'ff...' match in radix tree, wdir identified
1629 raise error.WdirUnsupported
1629 raise error.WdirUnsupported
1630 else:
1630 else:
1631 return None
1631 return None
1632 except error.RevlogError:
1632 except error.RevlogError:
1633 # parsers.c radix tree lookup gave multiple matches
1633 # parsers.c radix tree lookup gave multiple matches
1634 # fast path: for unfiltered changelog, radix tree is accurate
1634 # fast path: for unfiltered changelog, radix tree is accurate
1635 if not getattr(self, 'filteredrevs', None):
1635 if not getattr(self, 'filteredrevs', None):
1636 ambiguous = True
1636 ambiguous = True
1637 # fall through to slow path that filters hidden revisions
1637 # fall through to slow path that filters hidden revisions
1638 except (AttributeError, ValueError):
1638 except (AttributeError, ValueError):
1639 # we are pure python, or key is not hex
1639 # we are pure python, or key is not hex
1640 pass
1640 pass
1641 if ambiguous:
1641 if ambiguous:
1642 raise error.AmbiguousPrefixLookupError(
1642 raise error.AmbiguousPrefixLookupError(
1643 id, self.display_id, _(b'ambiguous identifier')
1643 id, self.display_id, _(b'ambiguous identifier')
1644 )
1644 )
1645
1645
1646 if id in self._pcache:
1646 if id in self._pcache:
1647 return self._pcache[id]
1647 return self._pcache[id]
1648
1648
1649 if len(id) <= 40:
1649 if len(id) <= 40:
1650 # hex(node)[:...]
1650 # hex(node)[:...]
1651 l = len(id) // 2 * 2 # grab an even number of digits
1651 l = len(id) // 2 * 2 # grab an even number of digits
1652 try:
1652 try:
1653 # we're dropping the last digit, so let's check that it's hex,
1653 # we're dropping the last digit, so let's check that it's hex,
1654 # to avoid the expensive computation below if it's not
1654 # to avoid the expensive computation below if it's not
1655 if len(id) % 2 > 0:
1655 if len(id) % 2 > 0:
1656 if not (id[-1] in hexdigits):
1656 if not (id[-1] in hexdigits):
1657 return None
1657 return None
1658 prefix = bin(id[:l])
1658 prefix = bin(id[:l])
1659 except binascii.Error:
1659 except binascii.Error:
1660 pass
1660 pass
1661 else:
1661 else:
1662 nl = [e[7] for e in self.index if e[7].startswith(prefix)]
1662 nl = [e[7] for e in self.index if e[7].startswith(prefix)]
1663 nl = [
1663 nl = [
1664 n for n in nl if hex(n).startswith(id) and self.hasnode(n)
1664 n for n in nl if hex(n).startswith(id) and self.hasnode(n)
1665 ]
1665 ]
1666 if self.nodeconstants.nullhex.startswith(id):
1666 if self.nodeconstants.nullhex.startswith(id):
1667 nl.append(self.nullid)
1667 nl.append(self.nullid)
1668 if len(nl) > 0:
1668 if len(nl) > 0:
1669 if len(nl) == 1 and not maybewdir:
1669 if len(nl) == 1 and not maybewdir:
1670 self._pcache[id] = nl[0]
1670 self._pcache[id] = nl[0]
1671 return nl[0]
1671 return nl[0]
1672 raise error.AmbiguousPrefixLookupError(
1672 raise error.AmbiguousPrefixLookupError(
1673 id, self.display_id, _(b'ambiguous identifier')
1673 id, self.display_id, _(b'ambiguous identifier')
1674 )
1674 )
1675 if maybewdir:
1675 if maybewdir:
1676 raise error.WdirUnsupported
1676 raise error.WdirUnsupported
1677 return None
1677 return None
1678
1678
1679 def lookup(self, id):
1679 def lookup(self, id):
1680 """locate a node based on:
1680 """locate a node based on:
1681 - revision number or str(revision number)
1681 - revision number or str(revision number)
1682 - nodeid or subset of hex nodeid
1682 - nodeid or subset of hex nodeid
1683 """
1683 """
1684 n = self._match(id)
1684 n = self._match(id)
1685 if n is not None:
1685 if n is not None:
1686 return n
1686 return n
1687 n = self._partialmatch(id)
1687 n = self._partialmatch(id)
1688 if n:
1688 if n:
1689 return n
1689 return n
1690
1690
1691 raise error.LookupError(id, self.display_id, _(b'no match found'))
1691 raise error.LookupError(id, self.display_id, _(b'no match found'))
1692
1692
1693 def shortest(self, node, minlength=1):
1693 def shortest(self, node, minlength=1):
1694 """Find the shortest unambiguous prefix that matches node."""
1694 """Find the shortest unambiguous prefix that matches node."""
1695
1695
1696 def isvalid(prefix):
1696 def isvalid(prefix):
1697 try:
1697 try:
1698 matchednode = self._partialmatch(prefix)
1698 matchednode = self._partialmatch(prefix)
1699 except error.AmbiguousPrefixLookupError:
1699 except error.AmbiguousPrefixLookupError:
1700 return False
1700 return False
1701 except error.WdirUnsupported:
1701 except error.WdirUnsupported:
1702 # single 'ff...' match
1702 # single 'ff...' match
1703 return True
1703 return True
1704 if matchednode is None:
1704 if matchednode is None:
1705 raise error.LookupError(node, self.display_id, _(b'no node'))
1705 raise error.LookupError(node, self.display_id, _(b'no node'))
1706 return True
1706 return True
1707
1707
1708 def maybewdir(prefix):
1708 def maybewdir(prefix):
1709 return all(c == b'f' for c in pycompat.iterbytestr(prefix))
1709 return all(c == b'f' for c in pycompat.iterbytestr(prefix))
1710
1710
1711 hexnode = hex(node)
1711 hexnode = hex(node)
1712
1712
1713 def disambiguate(hexnode, minlength):
1713 def disambiguate(hexnode, minlength):
1714 """Disambiguate against wdirid."""
1714 """Disambiguate against wdirid."""
1715 for length in range(minlength, len(hexnode) + 1):
1715 for length in range(minlength, len(hexnode) + 1):
1716 prefix = hexnode[:length]
1716 prefix = hexnode[:length]
1717 if not maybewdir(prefix):
1717 if not maybewdir(prefix):
1718 return prefix
1718 return prefix
1719
1719
1720 if not getattr(self, 'filteredrevs', None):
1720 if not getattr(self, 'filteredrevs', None):
1721 try:
1721 try:
1722 length = max(self.index.shortest(node), minlength)
1722 length = max(self.index.shortest(node), minlength)
1723 return disambiguate(hexnode, length)
1723 return disambiguate(hexnode, length)
1724 except error.RevlogError:
1724 except error.RevlogError:
1725 if node != self.nodeconstants.wdirid:
1725 if node != self.nodeconstants.wdirid:
1726 raise error.LookupError(
1726 raise error.LookupError(
1727 node, self.display_id, _(b'no node')
1727 node, self.display_id, _(b'no node')
1728 )
1728 )
1729 except AttributeError:
1729 except AttributeError:
1730 # Fall through to pure code
1730 # Fall through to pure code
1731 pass
1731 pass
1732
1732
1733 if node == self.nodeconstants.wdirid:
1733 if node == self.nodeconstants.wdirid:
1734 for length in range(minlength, len(hexnode) + 1):
1734 for length in range(minlength, len(hexnode) + 1):
1735 prefix = hexnode[:length]
1735 prefix = hexnode[:length]
1736 if isvalid(prefix):
1736 if isvalid(prefix):
1737 return prefix
1737 return prefix
1738
1738
1739 for length in range(minlength, len(hexnode) + 1):
1739 for length in range(minlength, len(hexnode) + 1):
1740 prefix = hexnode[:length]
1740 prefix = hexnode[:length]
1741 if isvalid(prefix):
1741 if isvalid(prefix):
1742 return disambiguate(hexnode, length)
1742 return disambiguate(hexnode, length)
1743
1743
1744 def cmp(self, node, text):
1744 def cmp(self, node, text):
1745 """compare text with a given file revision
1745 """compare text with a given file revision
1746
1746
1747 returns True if text is different than what is stored.
1747 returns True if text is different than what is stored.
1748 """
1748 """
1749 p1, p2 = self.parents(node)
1749 p1, p2 = self.parents(node)
1750 return storageutil.hashrevisionsha1(text, p1, p2) != node
1750 return storageutil.hashrevisionsha1(text, p1, p2) != node
1751
1751
1752 def _getsegmentforrevs(self, startrev, endrev, df=None):
1752 def _getsegmentforrevs(self, startrev, endrev, df=None):
1753 """Obtain a segment of raw data corresponding to a range of revisions.
1753 """Obtain a segment of raw data corresponding to a range of revisions.
1754
1754
1755 Accepts the start and end revisions and an optional already-open
1755 Accepts the start and end revisions and an optional already-open
1756 file handle to be used for reading. If the file handle is read, its
1756 file handle to be used for reading. If the file handle is read, its
1757 seek position will not be preserved.
1757 seek position will not be preserved.
1758
1758
1759 Requests for data may be satisfied by a cache.
1759 Requests for data may be satisfied by a cache.
1760
1760
1761 Returns a 2-tuple of (offset, data) for the requested range of
1761 Returns a 2-tuple of (offset, data) for the requested range of
1762 revisions. Offset is the integer offset from the beginning of the
1762 revisions. Offset is the integer offset from the beginning of the
1763 revlog and data is a str or buffer of the raw byte data.
1763 revlog and data is a str or buffer of the raw byte data.
1764
1764
1765 Callers will need to call ``self.start(rev)`` and ``self.length(rev)``
1765 Callers will need to call ``self.start(rev)`` and ``self.length(rev)``
1766 to determine where each revision's data begins and ends.
1766 to determine where each revision's data begins and ends.
1767 """
1767 """
1768 # Inlined self.start(startrev) & self.end(endrev) for perf reasons
1768 # Inlined self.start(startrev) & self.end(endrev) for perf reasons
1769 # (functions are expensive).
1769 # (functions are expensive).
1770 index = self.index
1770 index = self.index
1771 istart = index[startrev]
1771 istart = index[startrev]
1772 start = int(istart[0] >> 16)
1772 start = int(istart[0] >> 16)
1773 if startrev == endrev:
1773 if startrev == endrev:
1774 end = start + istart[1]
1774 end = start + istart[1]
1775 else:
1775 else:
1776 iend = index[endrev]
1776 iend = index[endrev]
1777 end = int(iend[0] >> 16) + iend[1]
1777 end = int(iend[0] >> 16) + iend[1]
1778
1778
1779 if self._inline:
1779 if self._inline:
1780 start += (startrev + 1) * self.index.entry_size
1780 start += (startrev + 1) * self.index.entry_size
1781 end += (endrev + 1) * self.index.entry_size
1781 end += (endrev + 1) * self.index.entry_size
1782 length = end - start
1782 length = end - start
1783
1783
1784 return start, self._segmentfile.read_chunk(start, length, df)
1784 return start, self._segmentfile.read_chunk(start, length, df)
1785
1785
1786 def _chunk(self, rev, df=None):
1786 def _chunk(self, rev, df=None):
1787 """Obtain a single decompressed chunk for a revision.
1787 """Obtain a single decompressed chunk for a revision.
1788
1788
1789 Accepts an integer revision and an optional already-open file handle
1789 Accepts an integer revision and an optional already-open file handle
1790 to be used for reading. If used, the seek position of the file will not
1790 to be used for reading. If used, the seek position of the file will not
1791 be preserved.
1791 be preserved.
1792
1792
1793 Returns a str holding uncompressed data for the requested revision.
1793 Returns a str holding uncompressed data for the requested revision.
1794 """
1794 """
1795 compression_mode = self.index[rev][10]
1795 compression_mode = self.index[rev][10]
1796 data = self._getsegmentforrevs(rev, rev, df=df)[1]
1796 data = self._getsegmentforrevs(rev, rev, df=df)[1]
1797 if compression_mode == COMP_MODE_PLAIN:
1797 if compression_mode == COMP_MODE_PLAIN:
1798 return data
1798 return data
1799 elif compression_mode == COMP_MODE_DEFAULT:
1799 elif compression_mode == COMP_MODE_DEFAULT:
1800 return self._decompressor(data)
1800 return self._decompressor(data)
1801 elif compression_mode == COMP_MODE_INLINE:
1801 elif compression_mode == COMP_MODE_INLINE:
1802 return self.decompress(data)
1802 return self.decompress(data)
1803 else:
1803 else:
1804 msg = b'unknown compression mode %d'
1804 msg = b'unknown compression mode %d'
1805 msg %= compression_mode
1805 msg %= compression_mode
1806 raise error.RevlogError(msg)
1806 raise error.RevlogError(msg)
1807
1807
1808 def _chunks(self, revs, df=None, targetsize=None):
1808 def _chunks(self, revs, df=None, targetsize=None):
1809 """Obtain decompressed chunks for the specified revisions.
1809 """Obtain decompressed chunks for the specified revisions.
1810
1810
1811 Accepts an iterable of numeric revisions that are assumed to be in
1811 Accepts an iterable of numeric revisions that are assumed to be in
1812 ascending order. Also accepts an optional already-open file handle
1812 ascending order. Also accepts an optional already-open file handle
1813 to be used for reading. If used, the seek position of the file will
1813 to be used for reading. If used, the seek position of the file will
1814 not be preserved.
1814 not be preserved.
1815
1815
1816 This function is similar to calling ``self._chunk()`` multiple times,
1816 This function is similar to calling ``self._chunk()`` multiple times,
1817 but is faster.
1817 but is faster.
1818
1818
1819 Returns a list with decompressed data for each requested revision.
1819 Returns a list with decompressed data for each requested revision.
1820 """
1820 """
1821 if not revs:
1821 if not revs:
1822 return []
1822 return []
1823 start = self.start
1823 start = self.start
1824 length = self.length
1824 length = self.length
1825 inline = self._inline
1825 inline = self._inline
1826 iosize = self.index.entry_size
1826 iosize = self.index.entry_size
1827 buffer = util.buffer
1827 buffer = util.buffer
1828
1828
1829 l = []
1829 l = []
1830 ladd = l.append
1830 ladd = l.append
1831
1831
1832 if not self._withsparseread:
1832 if not self._withsparseread:
1833 slicedchunks = (revs,)
1833 slicedchunks = (revs,)
1834 else:
1834 else:
1835 slicedchunks = deltautil.slicechunk(
1835 slicedchunks = deltautil.slicechunk(
1836 self, revs, targetsize=targetsize
1836 self, revs, targetsize=targetsize
1837 )
1837 )
1838
1838
1839 for revschunk in slicedchunks:
1839 for revschunk in slicedchunks:
1840 firstrev = revschunk[0]
1840 firstrev = revschunk[0]
1841 # Skip trailing revisions with empty diff
1841 # Skip trailing revisions with empty diff
1842 for lastrev in revschunk[::-1]:
1842 for lastrev in revschunk[::-1]:
1843 if length(lastrev) != 0:
1843 if length(lastrev) != 0:
1844 break
1844 break
1845
1845
1846 try:
1846 try:
1847 offset, data = self._getsegmentforrevs(firstrev, lastrev, df=df)
1847 offset, data = self._getsegmentforrevs(firstrev, lastrev, df=df)
1848 except OverflowError:
1848 except OverflowError:
1849 # issue4215 - we can't cache a run of chunks greater than
1849 # issue4215 - we can't cache a run of chunks greater than
1850 # 2G on Windows
1850 # 2G on Windows
1851 return [self._chunk(rev, df=df) for rev in revschunk]
1851 return [self._chunk(rev, df=df) for rev in revschunk]
1852
1852
1853 decomp = self.decompress
1853 decomp = self.decompress
1854 # self._decompressor might be None, but will not be used in that case
1854 # self._decompressor might be None, but will not be used in that case
1855 def_decomp = self._decompressor
1855 def_decomp = self._decompressor
1856 for rev in revschunk:
1856 for rev in revschunk:
1857 chunkstart = start(rev)
1857 chunkstart = start(rev)
1858 if inline:
1858 if inline:
1859 chunkstart += (rev + 1) * iosize
1859 chunkstart += (rev + 1) * iosize
1860 chunklength = length(rev)
1860 chunklength = length(rev)
1861 comp_mode = self.index[rev][10]
1861 comp_mode = self.index[rev][10]
1862 c = buffer(data, chunkstart - offset, chunklength)
1862 c = buffer(data, chunkstart - offset, chunklength)
1863 if comp_mode == COMP_MODE_PLAIN:
1863 if comp_mode == COMP_MODE_PLAIN:
1864 ladd(c)
1864 ladd(c)
1865 elif comp_mode == COMP_MODE_INLINE:
1865 elif comp_mode == COMP_MODE_INLINE:
1866 ladd(decomp(c))
1866 ladd(decomp(c))
1867 elif comp_mode == COMP_MODE_DEFAULT:
1867 elif comp_mode == COMP_MODE_DEFAULT:
1868 ladd(def_decomp(c))
1868 ladd(def_decomp(c))
1869 else:
1869 else:
1870 msg = b'unknown compression mode %d'
1870 msg = b'unknown compression mode %d'
1871 msg %= comp_mode
1871 msg %= comp_mode
1872 raise error.RevlogError(msg)
1872 raise error.RevlogError(msg)
1873
1873
1874 return l
1874 return l
1875
1875
1876 def deltaparent(self, rev):
1876 def deltaparent(self, rev):
1877 """return deltaparent of the given revision"""
1877 """return deltaparent of the given revision"""
1878 base = self.index[rev][3]
1878 base = self.index[rev][3]
1879 if base == rev:
1879 if base == rev:
1880 return nullrev
1880 return nullrev
1881 elif self._generaldelta:
1881 elif self._generaldelta:
1882 return base
1882 return base
1883 else:
1883 else:
1884 return rev - 1
1884 return rev - 1
1885
1885
1886 def issnapshot(self, rev):
1886 def issnapshot(self, rev):
1887 """tells whether rev is a snapshot"""
1887 """tells whether rev is a snapshot"""
1888 if not self._sparserevlog:
1888 if not self._sparserevlog:
1889 return self.deltaparent(rev) == nullrev
1889 return self.deltaparent(rev) == nullrev
1890 elif util.safehasattr(self.index, 'issnapshot'):
1890 elif util.safehasattr(self.index, 'issnapshot'):
1891 # directly assign the method to cache the testing and access
1891 # directly assign the method to cache the testing and access
1892 self.issnapshot = self.index.issnapshot
1892 self.issnapshot = self.index.issnapshot
1893 return self.issnapshot(rev)
1893 return self.issnapshot(rev)
1894 if rev == nullrev:
1894 if rev == nullrev:
1895 return True
1895 return True
1896 entry = self.index[rev]
1896 entry = self.index[rev]
1897 base = entry[3]
1897 base = entry[3]
1898 if base == rev:
1898 if base == rev:
1899 return True
1899 return True
1900 if base == nullrev:
1900 if base == nullrev:
1901 return True
1901 return True
1902 p1 = entry[5]
1902 p1 = entry[5]
1903 while self.length(p1) == 0:
1903 while self.length(p1) == 0:
1904 b = self.deltaparent(p1)
1904 b = self.deltaparent(p1)
1905 if b == p1:
1905 if b == p1:
1906 break
1906 break
1907 p1 = b
1907 p1 = b
1908 p2 = entry[6]
1908 p2 = entry[6]
1909 while self.length(p2) == 0:
1909 while self.length(p2) == 0:
1910 b = self.deltaparent(p2)
1910 b = self.deltaparent(p2)
1911 if b == p2:
1911 if b == p2:
1912 break
1912 break
1913 p2 = b
1913 p2 = b
1914 if base == p1 or base == p2:
1914 if base == p1 or base == p2:
1915 return False
1915 return False
1916 return self.issnapshot(base)
1916 return self.issnapshot(base)
1917
1917
1918 def snapshotdepth(self, rev):
1918 def snapshotdepth(self, rev):
1919 """number of snapshot in the chain before this one"""
1919 """number of snapshot in the chain before this one"""
1920 if not self.issnapshot(rev):
1920 if not self.issnapshot(rev):
1921 raise error.ProgrammingError(b'revision %d not a snapshot')
1921 raise error.ProgrammingError(b'revision %d not a snapshot')
1922 return len(self._deltachain(rev)[0]) - 1
1922 return len(self._deltachain(rev)[0]) - 1
1923
1923
1924 def revdiff(self, rev1, rev2):
1924 def revdiff(self, rev1, rev2):
1925 """return or calculate a delta between two revisions
1925 """return or calculate a delta between two revisions
1926
1926
1927 The delta calculated is in binary form and is intended to be written to
1927 The delta calculated is in binary form and is intended to be written to
1928 revlog data directly. So this function needs raw revision data.
1928 revlog data directly. So this function needs raw revision data.
1929 """
1929 """
1930 if rev1 != nullrev and self.deltaparent(rev2) == rev1:
1930 if rev1 != nullrev and self.deltaparent(rev2) == rev1:
1931 return bytes(self._chunk(rev2))
1931 return bytes(self._chunk(rev2))
1932
1932
1933 return mdiff.textdiff(self.rawdata(rev1), self.rawdata(rev2))
1933 return mdiff.textdiff(self.rawdata(rev1), self.rawdata(rev2))
1934
1934
1935 def revision(self, nodeorrev, _df=None):
1935 def revision(self, nodeorrev, _df=None):
1936 """return an uncompressed revision of a given node or revision
1936 """return an uncompressed revision of a given node or revision
1937 number.
1937 number.
1938
1938
1939 _df - an existing file handle to read from. (internal-only)
1939 _df - an existing file handle to read from. (internal-only)
1940 """
1940 """
1941 return self._revisiondata(nodeorrev, _df)
1941 return self._revisiondata(nodeorrev, _df)
1942
1942
1943 def sidedata(self, nodeorrev, _df=None):
1943 def sidedata(self, nodeorrev, _df=None):
1944 """a map of extra data related to the changeset but not part of the hash
1944 """a map of extra data related to the changeset but not part of the hash
1945
1945
1946 This function currently return a dictionary. However, more advanced
1946 This function currently return a dictionary. However, more advanced
1947 mapping object will likely be used in the future for a more
1947 mapping object will likely be used in the future for a more
1948 efficient/lazy code.
1948 efficient/lazy code.
1949 """
1949 """
1950 # deal with <nodeorrev> argument type
1950 # deal with <nodeorrev> argument type
1951 if isinstance(nodeorrev, int):
1951 if isinstance(nodeorrev, int):
1952 rev = nodeorrev
1952 rev = nodeorrev
1953 else:
1953 else:
1954 rev = self.rev(nodeorrev)
1954 rev = self.rev(nodeorrev)
1955 return self._sidedata(rev)
1955 return self._sidedata(rev)
1956
1956
1957 def _revisiondata(self, nodeorrev, _df=None, raw=False):
1957 def _revisiondata(self, nodeorrev, _df=None, raw=False):
1958 # deal with <nodeorrev> argument type
1958 # deal with <nodeorrev> argument type
1959 if isinstance(nodeorrev, int):
1959 if isinstance(nodeorrev, int):
1960 rev = nodeorrev
1960 rev = nodeorrev
1961 node = self.node(rev)
1961 node = self.node(rev)
1962 else:
1962 else:
1963 node = nodeorrev
1963 node = nodeorrev
1964 rev = None
1964 rev = None
1965
1965
1966 # fast path the special `nullid` rev
1966 # fast path the special `nullid` rev
1967 if node == self.nullid:
1967 if node == self.nullid:
1968 return b""
1968 return b""
1969
1969
1970 # ``rawtext`` is the text as stored inside the revlog. Might be the
1970 # ``rawtext`` is the text as stored inside the revlog. Might be the
1971 # revision or might need to be processed to retrieve the revision.
1971 # revision or might need to be processed to retrieve the revision.
1972 rev, rawtext, validated = self._rawtext(node, rev, _df=_df)
1972 rev, rawtext, validated = self._rawtext(node, rev, _df=_df)
1973
1973
1974 if raw and validated:
1974 if raw and validated:
1975 # if we don't want to process the raw text and that raw
1975 # if we don't want to process the raw text and that raw
1976 # text is cached, we can exit early.
1976 # text is cached, we can exit early.
1977 return rawtext
1977 return rawtext
1978 if rev is None:
1978 if rev is None:
1979 rev = self.rev(node)
1979 rev = self.rev(node)
1980 # the revlog's flag for this revision
1980 # the revlog's flag for this revision
1981 # (usually alter its state or content)
1981 # (usually alter its state or content)
1982 flags = self.flags(rev)
1982 flags = self.flags(rev)
1983
1983
1984 if validated and flags == REVIDX_DEFAULT_FLAGS:
1984 if validated and flags == REVIDX_DEFAULT_FLAGS:
1985 # no extra flags set, no flag processor runs, text = rawtext
1985 # no extra flags set, no flag processor runs, text = rawtext
1986 return rawtext
1986 return rawtext
1987
1987
1988 if raw:
1988 if raw:
1989 validatehash = flagutil.processflagsraw(self, rawtext, flags)
1989 validatehash = flagutil.processflagsraw(self, rawtext, flags)
1990 text = rawtext
1990 text = rawtext
1991 else:
1991 else:
1992 r = flagutil.processflagsread(self, rawtext, flags)
1992 r = flagutil.processflagsread(self, rawtext, flags)
1993 text, validatehash = r
1993 text, validatehash = r
1994 if validatehash:
1994 if validatehash:
1995 self.checkhash(text, node, rev=rev)
1995 self.checkhash(text, node, rev=rev)
1996 if not validated:
1996 if not validated:
1997 self._revisioncache = (node, rev, rawtext)
1997 self._revisioncache = (node, rev, rawtext)
1998
1998
1999 return text
1999 return text
2000
2000
2001 def _rawtext(self, node, rev, _df=None):
2001 def _rawtext(self, node, rev, _df=None):
2002 """return the possibly unvalidated rawtext for a revision
2002 """return the possibly unvalidated rawtext for a revision
2003
2003
2004 returns (rev, rawtext, validated)
2004 returns (rev, rawtext, validated)
2005 """
2005 """
2006
2006
2007 # revision in the cache (could be useful to apply delta)
2007 # revision in the cache (could be useful to apply delta)
2008 cachedrev = None
2008 cachedrev = None
2009 # An intermediate text to apply deltas to
2009 # An intermediate text to apply deltas to
2010 basetext = None
2010 basetext = None
2011
2011
2012 # Check if we have the entry in cache
2012 # Check if we have the entry in cache
2013 # The cache entry looks like (node, rev, rawtext)
2013 # The cache entry looks like (node, rev, rawtext)
2014 if self._revisioncache:
2014 if self._revisioncache:
2015 if self._revisioncache[0] == node:
2015 if self._revisioncache[0] == node:
2016 return (rev, self._revisioncache[2], True)
2016 return (rev, self._revisioncache[2], True)
2017 cachedrev = self._revisioncache[1]
2017 cachedrev = self._revisioncache[1]
2018
2018
2019 if rev is None:
2019 if rev is None:
2020 rev = self.rev(node)
2020 rev = self.rev(node)
2021
2021
2022 chain, stopped = self._deltachain(rev, stoprev=cachedrev)
2022 chain, stopped = self._deltachain(rev, stoprev=cachedrev)
2023 if stopped:
2023 if stopped:
2024 basetext = self._revisioncache[2]
2024 basetext = self._revisioncache[2]
2025
2025
2026 # drop cache to save memory, the caller is expected to
2026 # drop cache to save memory, the caller is expected to
2027 # update self._revisioncache after validating the text
2027 # update self._revisioncache after validating the text
2028 self._revisioncache = None
2028 self._revisioncache = None
2029
2029
2030 targetsize = None
2030 targetsize = None
2031 rawsize = self.index[rev][2]
2031 rawsize = self.index[rev][2]
2032 if 0 <= rawsize:
2032 if 0 <= rawsize:
2033 targetsize = 4 * rawsize
2033 targetsize = 4 * rawsize
2034
2034
2035 bins = self._chunks(chain, df=_df, targetsize=targetsize)
2035 bins = self._chunks(chain, df=_df, targetsize=targetsize)
2036 if basetext is None:
2036 if basetext is None:
2037 basetext = bytes(bins[0])
2037 basetext = bytes(bins[0])
2038 bins = bins[1:]
2038 bins = bins[1:]
2039
2039
2040 rawtext = mdiff.patches(basetext, bins)
2040 rawtext = mdiff.patches(basetext, bins)
2041 del basetext # let us have a chance to free memory early
2041 del basetext # let us have a chance to free memory early
2042 return (rev, rawtext, False)
2042 return (rev, rawtext, False)
2043
2043
2044 def _sidedata(self, rev):
2044 def _sidedata(self, rev):
2045 """Return the sidedata for a given revision number."""
2045 """Return the sidedata for a given revision number."""
2046 index_entry = self.index[rev]
2046 index_entry = self.index[rev]
2047 sidedata_offset = index_entry[8]
2047 sidedata_offset = index_entry[8]
2048 sidedata_size = index_entry[9]
2048 sidedata_size = index_entry[9]
2049
2049
2050 if self._inline:
2050 if self._inline:
2051 sidedata_offset += self.index.entry_size * (1 + rev)
2051 sidedata_offset += self.index.entry_size * (1 + rev)
2052 if sidedata_size == 0:
2052 if sidedata_size == 0:
2053 return {}
2053 return {}
2054
2054
2055 if self._docket.sidedata_end < sidedata_offset + sidedata_size:
2055 if self._docket.sidedata_end < sidedata_offset + sidedata_size:
2056 filename = self._sidedatafile
2056 filename = self._sidedatafile
2057 end = self._docket.sidedata_end
2057 end = self._docket.sidedata_end
2058 offset = sidedata_offset
2058 offset = sidedata_offset
2059 length = sidedata_size
2059 length = sidedata_size
2060 m = FILE_TOO_SHORT_MSG % (filename, length, offset, end)
2060 m = FILE_TOO_SHORT_MSG % (filename, length, offset, end)
2061 raise error.RevlogError(m)
2061 raise error.RevlogError(m)
2062
2062
2063 comp_segment = self._segmentfile_sidedata.read_chunk(
2063 comp_segment = self._segmentfile_sidedata.read_chunk(
2064 sidedata_offset, sidedata_size
2064 sidedata_offset, sidedata_size
2065 )
2065 )
2066
2066
2067 comp = self.index[rev][11]
2067 comp = self.index[rev][11]
2068 if comp == COMP_MODE_PLAIN:
2068 if comp == COMP_MODE_PLAIN:
2069 segment = comp_segment
2069 segment = comp_segment
2070 elif comp == COMP_MODE_DEFAULT:
2070 elif comp == COMP_MODE_DEFAULT:
2071 segment = self._decompressor(comp_segment)
2071 segment = self._decompressor(comp_segment)
2072 elif comp == COMP_MODE_INLINE:
2072 elif comp == COMP_MODE_INLINE:
2073 segment = self.decompress(comp_segment)
2073 segment = self.decompress(comp_segment)
2074 else:
2074 else:
2075 msg = b'unknown compression mode %d'
2075 msg = b'unknown compression mode %d'
2076 msg %= comp
2076 msg %= comp
2077 raise error.RevlogError(msg)
2077 raise error.RevlogError(msg)
2078
2078
2079 sidedata = sidedatautil.deserialize_sidedata(segment)
2079 sidedata = sidedatautil.deserialize_sidedata(segment)
2080 return sidedata
2080 return sidedata
2081
2081
2082 def rawdata(self, nodeorrev, _df=None):
2082 def rawdata(self, nodeorrev, _df=None):
2083 """return an uncompressed raw data of a given node or revision number.
2083 """return an uncompressed raw data of a given node or revision number.
2084
2084
2085 _df - an existing file handle to read from. (internal-only)
2085 _df - an existing file handle to read from. (internal-only)
2086 """
2086 """
2087 return self._revisiondata(nodeorrev, _df, raw=True)
2087 return self._revisiondata(nodeorrev, _df, raw=True)
2088
2088
2089 def hash(self, text, p1, p2):
2089 def hash(self, text, p1, p2):
2090 """Compute a node hash.
2090 """Compute a node hash.
2091
2091
2092 Available as a function so that subclasses can replace the hash
2092 Available as a function so that subclasses can replace the hash
2093 as needed.
2093 as needed.
2094 """
2094 """
2095 return storageutil.hashrevisionsha1(text, p1, p2)
2095 return storageutil.hashrevisionsha1(text, p1, p2)
2096
2096
2097 def checkhash(self, text, node, p1=None, p2=None, rev=None):
2097 def checkhash(self, text, node, p1=None, p2=None, rev=None):
2098 """Check node hash integrity.
2098 """Check node hash integrity.
2099
2099
2100 Available as a function so that subclasses can extend hash mismatch
2100 Available as a function so that subclasses can extend hash mismatch
2101 behaviors as needed.
2101 behaviors as needed.
2102 """
2102 """
2103 try:
2103 try:
2104 if p1 is None and p2 is None:
2104 if p1 is None and p2 is None:
2105 p1, p2 = self.parents(node)
2105 p1, p2 = self.parents(node)
2106 if node != self.hash(text, p1, p2):
2106 if node != self.hash(text, p1, p2):
2107 # Clear the revision cache on hash failure. The revision cache
2107 # Clear the revision cache on hash failure. The revision cache
2108 # only stores the raw revision and clearing the cache does have
2108 # only stores the raw revision and clearing the cache does have
2109 # the side-effect that we won't have a cache hit when the raw
2109 # the side-effect that we won't have a cache hit when the raw
2110 # revision data is accessed. But this case should be rare and
2110 # revision data is accessed. But this case should be rare and
2111 # it is extra work to teach the cache about the hash
2111 # it is extra work to teach the cache about the hash
2112 # verification state.
2112 # verification state.
2113 if self._revisioncache and self._revisioncache[0] == node:
2113 if self._revisioncache and self._revisioncache[0] == node:
2114 self._revisioncache = None
2114 self._revisioncache = None
2115
2115
2116 revornode = rev
2116 revornode = rev
2117 if revornode is None:
2117 if revornode is None:
2118 revornode = templatefilters.short(hex(node))
2118 revornode = templatefilters.short(hex(node))
2119 raise error.RevlogError(
2119 raise error.RevlogError(
2120 _(b"integrity check failed on %s:%s")
2120 _(b"integrity check failed on %s:%s")
2121 % (self.display_id, pycompat.bytestr(revornode))
2121 % (self.display_id, pycompat.bytestr(revornode))
2122 )
2122 )
2123 except error.RevlogError:
2123 except error.RevlogError:
2124 if self._censorable and storageutil.iscensoredtext(text):
2124 if self._censorable and storageutil.iscensoredtext(text):
2125 raise error.CensoredNodeError(self.display_id, node, text)
2125 raise error.CensoredNodeError(self.display_id, node, text)
2126 raise
2126 raise
2127
2127
2128 @property
2129 def _split_index_file(self):
2130 """the path where to expect the index of an ongoing splitting operation
2131
2132 The file will only exist if a splitting operation is in progress, but
2133 it is always expected at the same location."""
2134 parts = os.path.split(self.radix)
2135 if len(parts) > 1:
2136 # adds a '-s' prefix to the ``data/` or `meta/` base
2137 head = parts[0] + b'-s'
2138 return os.path.join(head, *parts[1:])
2139 else:
2140 # the revlog is stored at the root of the store (changelog or
2141 # manifest), no risk of collision.
2142 return self.radix + b'.i.s'
2143
2128 def _enforceinlinesize(self, tr, side_write=True):
2144 def _enforceinlinesize(self, tr, side_write=True):
2129 """Check if the revlog is too big for inline and convert if so.
2145 """Check if the revlog is too big for inline and convert if so.
2130
2146
2131 This should be called after revisions are added to the revlog. If the
2147 This should be called after revisions are added to the revlog. If the
2132 revlog has grown too large to be an inline revlog, it will convert it
2148 revlog has grown too large to be an inline revlog, it will convert it
2133 to use multiple index and data files.
2149 to use multiple index and data files.
2134 """
2150 """
2135 tiprev = len(self) - 1
2151 tiprev = len(self) - 1
2136 total_size = self.start(tiprev) + self.length(tiprev)
2152 total_size = self.start(tiprev) + self.length(tiprev)
2137 if not self._inline or total_size < _maxinline:
2153 if not self._inline or total_size < _maxinline:
2138 return
2154 return
2139
2155
2140 troffset = tr.findoffset(self._indexfile)
2156 troffset = tr.findoffset(self._indexfile)
2141 if troffset is None:
2157 if troffset is None:
2142 raise error.RevlogError(
2158 raise error.RevlogError(
2143 _(b"%s not found in the transaction") % self._indexfile
2159 _(b"%s not found in the transaction") % self._indexfile
2144 )
2160 )
2145 if troffset:
2161 if troffset:
2146 tr.addbackup(self._indexfile, for_offset=True)
2162 tr.addbackup(self._indexfile, for_offset=True)
2147 tr.add(self._datafile, 0)
2163 tr.add(self._datafile, 0)
2148
2164
2149 existing_handles = False
2165 existing_handles = False
2150 if self._writinghandles is not None:
2166 if self._writinghandles is not None:
2151 existing_handles = True
2167 existing_handles = True
2152 fp = self._writinghandles[0]
2168 fp = self._writinghandles[0]
2153 fp.flush()
2169 fp.flush()
2154 fp.close()
2170 fp.close()
2155 # We can't use the cached file handle after close(). So prevent
2171 # We can't use the cached file handle after close(). So prevent
2156 # its usage.
2172 # its usage.
2157 self._writinghandles = None
2173 self._writinghandles = None
2158 self._segmentfile.writing_handle = None
2174 self._segmentfile.writing_handle = None
2159 # No need to deal with sidedata writing handle as it is only
2175 # No need to deal with sidedata writing handle as it is only
2160 # relevant with revlog-v2 which is never inline, not reaching
2176 # relevant with revlog-v2 which is never inline, not reaching
2161 # this code
2177 # this code
2162 if side_write:
2178 if side_write:
2163 old_index_file_path = self._indexfile
2179 old_index_file_path = self._indexfile
2164 new_index_file_path = self._indexfile + b'.s'
2180 new_index_file_path = self._split_index_file
2165 opener = self.opener
2181 opener = self.opener
2166 weak_self = weakref.ref(self)
2182 weak_self = weakref.ref(self)
2167
2183
2168 # the "split" index replace the real index when the transaction is finalized
2184 # the "split" index replace the real index when the transaction is finalized
2169 def finalize_callback(tr):
2185 def finalize_callback(tr):
2170 opener.rename(
2186 opener.rename(
2171 new_index_file_path,
2187 new_index_file_path,
2172 old_index_file_path,
2188 old_index_file_path,
2173 checkambig=True,
2189 checkambig=True,
2174 )
2190 )
2175 maybe_self = weak_self()
2191 maybe_self = weak_self()
2176 if maybe_self is not None:
2192 if maybe_self is not None:
2177 maybe_self._indexfile = old_index_file_path
2193 maybe_self._indexfile = old_index_file_path
2178
2194
2179 def abort_callback(tr):
2195 def abort_callback(tr):
2180 maybe_self = weak_self()
2196 maybe_self = weak_self()
2181 if maybe_self is not None:
2197 if maybe_self is not None:
2182 maybe_self._indexfile = old_index_file_path
2198 maybe_self._indexfile = old_index_file_path
2183
2199
2184 tr.registertmp(new_index_file_path)
2200 tr.registertmp(new_index_file_path)
2185 if self.target[1] is not None:
2201 if self.target[1] is not None:
2186 callback_id = b'000-revlog-split-%d-%s' % self.target
2202 callback_id = b'000-revlog-split-%d-%s' % self.target
2187 else:
2203 else:
2188 callback_id = b'000-revlog-split-%d' % self.target[0]
2204 callback_id = b'000-revlog-split-%d' % self.target[0]
2189 tr.addfinalize(callback_id, finalize_callback)
2205 tr.addfinalize(callback_id, finalize_callback)
2190 tr.addabort(callback_id, abort_callback)
2206 tr.addabort(callback_id, abort_callback)
2191
2207
2192 new_dfh = self._datafp(b'w+')
2208 new_dfh = self._datafp(b'w+')
2193 new_dfh.truncate(0) # drop any potentially existing data
2209 new_dfh.truncate(0) # drop any potentially existing data
2194 try:
2210 try:
2195 with self._indexfp() as read_ifh:
2211 with self._indexfp() as read_ifh:
2196 for r in self:
2212 for r in self:
2197 new_dfh.write(self._getsegmentforrevs(r, r, df=read_ifh)[1])
2213 new_dfh.write(self._getsegmentforrevs(r, r, df=read_ifh)[1])
2198 new_dfh.flush()
2214 new_dfh.flush()
2199
2215
2200 if side_write:
2216 if side_write:
2201 self._indexfile = new_index_file_path
2217 self._indexfile = new_index_file_path
2202 with self.__index_new_fp() as fp:
2218 with self.__index_new_fp() as fp:
2203 self._format_flags &= ~FLAG_INLINE_DATA
2219 self._format_flags &= ~FLAG_INLINE_DATA
2204 self._inline = False
2220 self._inline = False
2205 for i in self:
2221 for i in self:
2206 e = self.index.entry_binary(i)
2222 e = self.index.entry_binary(i)
2207 if i == 0 and self._docket is None:
2223 if i == 0 and self._docket is None:
2208 header = self._format_flags | self._format_version
2224 header = self._format_flags | self._format_version
2209 header = self.index.pack_header(header)
2225 header = self.index.pack_header(header)
2210 e = header + e
2226 e = header + e
2211 fp.write(e)
2227 fp.write(e)
2212 if self._docket is not None:
2228 if self._docket is not None:
2213 self._docket.index_end = fp.tell()
2229 self._docket.index_end = fp.tell()
2214
2230
2215 # If we don't use side-write, the temp file replace the real
2231 # If we don't use side-write, the temp file replace the real
2216 # index when we exit the context manager
2232 # index when we exit the context manager
2217
2233
2218 nodemaputil.setup_persistent_nodemap(tr, self)
2234 nodemaputil.setup_persistent_nodemap(tr, self)
2219 self._segmentfile = randomaccessfile.randomaccessfile(
2235 self._segmentfile = randomaccessfile.randomaccessfile(
2220 self.opener,
2236 self.opener,
2221 self._datafile,
2237 self._datafile,
2222 self._chunkcachesize,
2238 self._chunkcachesize,
2223 )
2239 )
2224
2240
2225 if existing_handles:
2241 if existing_handles:
2226 # switched from inline to conventional reopen the index
2242 # switched from inline to conventional reopen the index
2227 ifh = self.__index_write_fp()
2243 ifh = self.__index_write_fp()
2228 self._writinghandles = (ifh, new_dfh, None)
2244 self._writinghandles = (ifh, new_dfh, None)
2229 self._segmentfile.writing_handle = new_dfh
2245 self._segmentfile.writing_handle = new_dfh
2230 new_dfh = None
2246 new_dfh = None
2231 # No need to deal with sidedata writing handle as it is only
2247 # No need to deal with sidedata writing handle as it is only
2232 # relevant with revlog-v2 which is never inline, not reaching
2248 # relevant with revlog-v2 which is never inline, not reaching
2233 # this code
2249 # this code
2234 finally:
2250 finally:
2235 if new_dfh is not None:
2251 if new_dfh is not None:
2236 new_dfh.close()
2252 new_dfh.close()
2237
2253
2238 def _nodeduplicatecallback(self, transaction, node):
2254 def _nodeduplicatecallback(self, transaction, node):
2239 """called when trying to add a node already stored."""
2255 """called when trying to add a node already stored."""
2240
2256
2241 @contextlib.contextmanager
2257 @contextlib.contextmanager
2242 def reading(self):
2258 def reading(self):
2243 """Context manager that keeps data and sidedata files open for reading"""
2259 """Context manager that keeps data and sidedata files open for reading"""
2244 with self._segmentfile.reading():
2260 with self._segmentfile.reading():
2245 with self._segmentfile_sidedata.reading():
2261 with self._segmentfile_sidedata.reading():
2246 yield
2262 yield
2247
2263
2248 @contextlib.contextmanager
2264 @contextlib.contextmanager
2249 def _writing(self, transaction):
2265 def _writing(self, transaction):
2250 if self._trypending:
2266 if self._trypending:
2251 msg = b'try to write in a `trypending` revlog: %s'
2267 msg = b'try to write in a `trypending` revlog: %s'
2252 msg %= self.display_id
2268 msg %= self.display_id
2253 raise error.ProgrammingError(msg)
2269 raise error.ProgrammingError(msg)
2254 if self._writinghandles is not None:
2270 if self._writinghandles is not None:
2255 yield
2271 yield
2256 else:
2272 else:
2257 ifh = dfh = sdfh = None
2273 ifh = dfh = sdfh = None
2258 try:
2274 try:
2259 r = len(self)
2275 r = len(self)
2260 # opening the data file.
2276 # opening the data file.
2261 dsize = 0
2277 dsize = 0
2262 if r:
2278 if r:
2263 dsize = self.end(r - 1)
2279 dsize = self.end(r - 1)
2264 dfh = None
2280 dfh = None
2265 if not self._inline:
2281 if not self._inline:
2266 try:
2282 try:
2267 dfh = self._datafp(b"r+")
2283 dfh = self._datafp(b"r+")
2268 if self._docket is None:
2284 if self._docket is None:
2269 dfh.seek(0, os.SEEK_END)
2285 dfh.seek(0, os.SEEK_END)
2270 else:
2286 else:
2271 dfh.seek(self._docket.data_end, os.SEEK_SET)
2287 dfh.seek(self._docket.data_end, os.SEEK_SET)
2272 except FileNotFoundError:
2288 except FileNotFoundError:
2273 dfh = self._datafp(b"w+")
2289 dfh = self._datafp(b"w+")
2274 transaction.add(self._datafile, dsize)
2290 transaction.add(self._datafile, dsize)
2275 if self._sidedatafile is not None:
2291 if self._sidedatafile is not None:
2276 # revlog-v2 does not inline, help Pytype
2292 # revlog-v2 does not inline, help Pytype
2277 assert dfh is not None
2293 assert dfh is not None
2278 try:
2294 try:
2279 sdfh = self.opener(self._sidedatafile, mode=b"r+")
2295 sdfh = self.opener(self._sidedatafile, mode=b"r+")
2280 dfh.seek(self._docket.sidedata_end, os.SEEK_SET)
2296 dfh.seek(self._docket.sidedata_end, os.SEEK_SET)
2281 except FileNotFoundError:
2297 except FileNotFoundError:
2282 sdfh = self.opener(self._sidedatafile, mode=b"w+")
2298 sdfh = self.opener(self._sidedatafile, mode=b"w+")
2283 transaction.add(
2299 transaction.add(
2284 self._sidedatafile, self._docket.sidedata_end
2300 self._sidedatafile, self._docket.sidedata_end
2285 )
2301 )
2286
2302
2287 # opening the index file.
2303 # opening the index file.
2288 isize = r * self.index.entry_size
2304 isize = r * self.index.entry_size
2289 ifh = self.__index_write_fp()
2305 ifh = self.__index_write_fp()
2290 if self._inline:
2306 if self._inline:
2291 transaction.add(self._indexfile, dsize + isize)
2307 transaction.add(self._indexfile, dsize + isize)
2292 else:
2308 else:
2293 transaction.add(self._indexfile, isize)
2309 transaction.add(self._indexfile, isize)
2294 # exposing all file handle for writing.
2310 # exposing all file handle for writing.
2295 self._writinghandles = (ifh, dfh, sdfh)
2311 self._writinghandles = (ifh, dfh, sdfh)
2296 self._segmentfile.writing_handle = ifh if self._inline else dfh
2312 self._segmentfile.writing_handle = ifh if self._inline else dfh
2297 self._segmentfile_sidedata.writing_handle = sdfh
2313 self._segmentfile_sidedata.writing_handle = sdfh
2298 yield
2314 yield
2299 if self._docket is not None:
2315 if self._docket is not None:
2300 self._write_docket(transaction)
2316 self._write_docket(transaction)
2301 finally:
2317 finally:
2302 self._writinghandles = None
2318 self._writinghandles = None
2303 self._segmentfile.writing_handle = None
2319 self._segmentfile.writing_handle = None
2304 self._segmentfile_sidedata.writing_handle = None
2320 self._segmentfile_sidedata.writing_handle = None
2305 if dfh is not None:
2321 if dfh is not None:
2306 dfh.close()
2322 dfh.close()
2307 if sdfh is not None:
2323 if sdfh is not None:
2308 sdfh.close()
2324 sdfh.close()
2309 # closing the index file last to avoid exposing referent to
2325 # closing the index file last to avoid exposing referent to
2310 # potential unflushed data content.
2326 # potential unflushed data content.
2311 if ifh is not None:
2327 if ifh is not None:
2312 ifh.close()
2328 ifh.close()
2313
2329
2314 def _write_docket(self, transaction):
2330 def _write_docket(self, transaction):
2315 """write the current docket on disk
2331 """write the current docket on disk
2316
2332
2317 Exist as a method to help changelog to implement transaction logic
2333 Exist as a method to help changelog to implement transaction logic
2318
2334
2319 We could also imagine using the same transaction logic for all revlog
2335 We could also imagine using the same transaction logic for all revlog
2320 since docket are cheap."""
2336 since docket are cheap."""
2321 self._docket.write(transaction)
2337 self._docket.write(transaction)
2322
2338
2323 def addrevision(
2339 def addrevision(
2324 self,
2340 self,
2325 text,
2341 text,
2326 transaction,
2342 transaction,
2327 link,
2343 link,
2328 p1,
2344 p1,
2329 p2,
2345 p2,
2330 cachedelta=None,
2346 cachedelta=None,
2331 node=None,
2347 node=None,
2332 flags=REVIDX_DEFAULT_FLAGS,
2348 flags=REVIDX_DEFAULT_FLAGS,
2333 deltacomputer=None,
2349 deltacomputer=None,
2334 sidedata=None,
2350 sidedata=None,
2335 ):
2351 ):
2336 """add a revision to the log
2352 """add a revision to the log
2337
2353
2338 text - the revision data to add
2354 text - the revision data to add
2339 transaction - the transaction object used for rollback
2355 transaction - the transaction object used for rollback
2340 link - the linkrev data to add
2356 link - the linkrev data to add
2341 p1, p2 - the parent nodeids of the revision
2357 p1, p2 - the parent nodeids of the revision
2342 cachedelta - an optional precomputed delta
2358 cachedelta - an optional precomputed delta
2343 node - nodeid of revision; typically node is not specified, and it is
2359 node - nodeid of revision; typically node is not specified, and it is
2344 computed by default as hash(text, p1, p2), however subclasses might
2360 computed by default as hash(text, p1, p2), however subclasses might
2345 use different hashing method (and override checkhash() in such case)
2361 use different hashing method (and override checkhash() in such case)
2346 flags - the known flags to set on the revision
2362 flags - the known flags to set on the revision
2347 deltacomputer - an optional deltacomputer instance shared between
2363 deltacomputer - an optional deltacomputer instance shared between
2348 multiple calls
2364 multiple calls
2349 """
2365 """
2350 if link == nullrev:
2366 if link == nullrev:
2351 raise error.RevlogError(
2367 raise error.RevlogError(
2352 _(b"attempted to add linkrev -1 to %s") % self.display_id
2368 _(b"attempted to add linkrev -1 to %s") % self.display_id
2353 )
2369 )
2354
2370
2355 if sidedata is None:
2371 if sidedata is None:
2356 sidedata = {}
2372 sidedata = {}
2357 elif sidedata and not self.hassidedata:
2373 elif sidedata and not self.hassidedata:
2358 raise error.ProgrammingError(
2374 raise error.ProgrammingError(
2359 _(b"trying to add sidedata to a revlog who don't support them")
2375 _(b"trying to add sidedata to a revlog who don't support them")
2360 )
2376 )
2361
2377
2362 if flags:
2378 if flags:
2363 node = node or self.hash(text, p1, p2)
2379 node = node or self.hash(text, p1, p2)
2364
2380
2365 rawtext, validatehash = flagutil.processflagswrite(self, text, flags)
2381 rawtext, validatehash = flagutil.processflagswrite(self, text, flags)
2366
2382
2367 # If the flag processor modifies the revision data, ignore any provided
2383 # If the flag processor modifies the revision data, ignore any provided
2368 # cachedelta.
2384 # cachedelta.
2369 if rawtext != text:
2385 if rawtext != text:
2370 cachedelta = None
2386 cachedelta = None
2371
2387
2372 if len(rawtext) > _maxentrysize:
2388 if len(rawtext) > _maxentrysize:
2373 raise error.RevlogError(
2389 raise error.RevlogError(
2374 _(
2390 _(
2375 b"%s: size of %d bytes exceeds maximum revlog storage of 2GiB"
2391 b"%s: size of %d bytes exceeds maximum revlog storage of 2GiB"
2376 )
2392 )
2377 % (self.display_id, len(rawtext))
2393 % (self.display_id, len(rawtext))
2378 )
2394 )
2379
2395
2380 node = node or self.hash(rawtext, p1, p2)
2396 node = node or self.hash(rawtext, p1, p2)
2381 rev = self.index.get_rev(node)
2397 rev = self.index.get_rev(node)
2382 if rev is not None:
2398 if rev is not None:
2383 return rev
2399 return rev
2384
2400
2385 if validatehash:
2401 if validatehash:
2386 self.checkhash(rawtext, node, p1=p1, p2=p2)
2402 self.checkhash(rawtext, node, p1=p1, p2=p2)
2387
2403
2388 return self.addrawrevision(
2404 return self.addrawrevision(
2389 rawtext,
2405 rawtext,
2390 transaction,
2406 transaction,
2391 link,
2407 link,
2392 p1,
2408 p1,
2393 p2,
2409 p2,
2394 node,
2410 node,
2395 flags,
2411 flags,
2396 cachedelta=cachedelta,
2412 cachedelta=cachedelta,
2397 deltacomputer=deltacomputer,
2413 deltacomputer=deltacomputer,
2398 sidedata=sidedata,
2414 sidedata=sidedata,
2399 )
2415 )
2400
2416
2401 def addrawrevision(
2417 def addrawrevision(
2402 self,
2418 self,
2403 rawtext,
2419 rawtext,
2404 transaction,
2420 transaction,
2405 link,
2421 link,
2406 p1,
2422 p1,
2407 p2,
2423 p2,
2408 node,
2424 node,
2409 flags,
2425 flags,
2410 cachedelta=None,
2426 cachedelta=None,
2411 deltacomputer=None,
2427 deltacomputer=None,
2412 sidedata=None,
2428 sidedata=None,
2413 ):
2429 ):
2414 """add a raw revision with known flags, node and parents
2430 """add a raw revision with known flags, node and parents
2415 useful when reusing a revision not stored in this revlog (ex: received
2431 useful when reusing a revision not stored in this revlog (ex: received
2416 over wire, or read from an external bundle).
2432 over wire, or read from an external bundle).
2417 """
2433 """
2418 with self._writing(transaction):
2434 with self._writing(transaction):
2419 return self._addrevision(
2435 return self._addrevision(
2420 node,
2436 node,
2421 rawtext,
2437 rawtext,
2422 transaction,
2438 transaction,
2423 link,
2439 link,
2424 p1,
2440 p1,
2425 p2,
2441 p2,
2426 flags,
2442 flags,
2427 cachedelta,
2443 cachedelta,
2428 deltacomputer=deltacomputer,
2444 deltacomputer=deltacomputer,
2429 sidedata=sidedata,
2445 sidedata=sidedata,
2430 )
2446 )
2431
2447
2432 def compress(self, data):
2448 def compress(self, data):
2433 """Generate a possibly-compressed representation of data."""
2449 """Generate a possibly-compressed representation of data."""
2434 if not data:
2450 if not data:
2435 return b'', data
2451 return b'', data
2436
2452
2437 compressed = self._compressor.compress(data)
2453 compressed = self._compressor.compress(data)
2438
2454
2439 if compressed:
2455 if compressed:
2440 # The revlog compressor added the header in the returned data.
2456 # The revlog compressor added the header in the returned data.
2441 return b'', compressed
2457 return b'', compressed
2442
2458
2443 if data[0:1] == b'\0':
2459 if data[0:1] == b'\0':
2444 return b'', data
2460 return b'', data
2445 return b'u', data
2461 return b'u', data
2446
2462
2447 def decompress(self, data):
2463 def decompress(self, data):
2448 """Decompress a revlog chunk.
2464 """Decompress a revlog chunk.
2449
2465
2450 The chunk is expected to begin with a header identifying the
2466 The chunk is expected to begin with a header identifying the
2451 format type so it can be routed to an appropriate decompressor.
2467 format type so it can be routed to an appropriate decompressor.
2452 """
2468 """
2453 if not data:
2469 if not data:
2454 return data
2470 return data
2455
2471
2456 # Revlogs are read much more frequently than they are written and many
2472 # Revlogs are read much more frequently than they are written and many
2457 # chunks only take microseconds to decompress, so performance is
2473 # chunks only take microseconds to decompress, so performance is
2458 # important here.
2474 # important here.
2459 #
2475 #
2460 # We can make a few assumptions about revlogs:
2476 # We can make a few assumptions about revlogs:
2461 #
2477 #
2462 # 1) the majority of chunks will be compressed (as opposed to inline
2478 # 1) the majority of chunks will be compressed (as opposed to inline
2463 # raw data).
2479 # raw data).
2464 # 2) decompressing *any* data will likely by at least 10x slower than
2480 # 2) decompressing *any* data will likely by at least 10x slower than
2465 # returning raw inline data.
2481 # returning raw inline data.
2466 # 3) we want to prioritize common and officially supported compression
2482 # 3) we want to prioritize common and officially supported compression
2467 # engines
2483 # engines
2468 #
2484 #
2469 # It follows that we want to optimize for "decompress compressed data
2485 # It follows that we want to optimize for "decompress compressed data
2470 # when encoded with common and officially supported compression engines"
2486 # when encoded with common and officially supported compression engines"
2471 # case over "raw data" and "data encoded by less common or non-official
2487 # case over "raw data" and "data encoded by less common or non-official
2472 # compression engines." That is why we have the inline lookup first
2488 # compression engines." That is why we have the inline lookup first
2473 # followed by the compengines lookup.
2489 # followed by the compengines lookup.
2474 #
2490 #
2475 # According to `hg perfrevlogchunks`, this is ~0.5% faster for zlib
2491 # According to `hg perfrevlogchunks`, this is ~0.5% faster for zlib
2476 # compressed chunks. And this matters for changelog and manifest reads.
2492 # compressed chunks. And this matters for changelog and manifest reads.
2477 t = data[0:1]
2493 t = data[0:1]
2478
2494
2479 if t == b'x':
2495 if t == b'x':
2480 try:
2496 try:
2481 return _zlibdecompress(data)
2497 return _zlibdecompress(data)
2482 except zlib.error as e:
2498 except zlib.error as e:
2483 raise error.RevlogError(
2499 raise error.RevlogError(
2484 _(b'revlog decompress error: %s')
2500 _(b'revlog decompress error: %s')
2485 % stringutil.forcebytestr(e)
2501 % stringutil.forcebytestr(e)
2486 )
2502 )
2487 # '\0' is more common than 'u' so it goes first.
2503 # '\0' is more common than 'u' so it goes first.
2488 elif t == b'\0':
2504 elif t == b'\0':
2489 return data
2505 return data
2490 elif t == b'u':
2506 elif t == b'u':
2491 return util.buffer(data, 1)
2507 return util.buffer(data, 1)
2492
2508
2493 compressor = self._get_decompressor(t)
2509 compressor = self._get_decompressor(t)
2494
2510
2495 return compressor.decompress(data)
2511 return compressor.decompress(data)
2496
2512
2497 def _addrevision(
2513 def _addrevision(
2498 self,
2514 self,
2499 node,
2515 node,
2500 rawtext,
2516 rawtext,
2501 transaction,
2517 transaction,
2502 link,
2518 link,
2503 p1,
2519 p1,
2504 p2,
2520 p2,
2505 flags,
2521 flags,
2506 cachedelta,
2522 cachedelta,
2507 alwayscache=False,
2523 alwayscache=False,
2508 deltacomputer=None,
2524 deltacomputer=None,
2509 sidedata=None,
2525 sidedata=None,
2510 ):
2526 ):
2511 """internal function to add revisions to the log
2527 """internal function to add revisions to the log
2512
2528
2513 see addrevision for argument descriptions.
2529 see addrevision for argument descriptions.
2514
2530
2515 note: "addrevision" takes non-raw text, "_addrevision" takes raw text.
2531 note: "addrevision" takes non-raw text, "_addrevision" takes raw text.
2516
2532
2517 if "deltacomputer" is not provided or None, a defaultdeltacomputer will
2533 if "deltacomputer" is not provided or None, a defaultdeltacomputer will
2518 be used.
2534 be used.
2519
2535
2520 invariants:
2536 invariants:
2521 - rawtext is optional (can be None); if not set, cachedelta must be set.
2537 - rawtext is optional (can be None); if not set, cachedelta must be set.
2522 if both are set, they must correspond to each other.
2538 if both are set, they must correspond to each other.
2523 """
2539 """
2524 if node == self.nullid:
2540 if node == self.nullid:
2525 raise error.RevlogError(
2541 raise error.RevlogError(
2526 _(b"%s: attempt to add null revision") % self.display_id
2542 _(b"%s: attempt to add null revision") % self.display_id
2527 )
2543 )
2528 if (
2544 if (
2529 node == self.nodeconstants.wdirid
2545 node == self.nodeconstants.wdirid
2530 or node in self.nodeconstants.wdirfilenodeids
2546 or node in self.nodeconstants.wdirfilenodeids
2531 ):
2547 ):
2532 raise error.RevlogError(
2548 raise error.RevlogError(
2533 _(b"%s: attempt to add wdir revision") % self.display_id
2549 _(b"%s: attempt to add wdir revision") % self.display_id
2534 )
2550 )
2535 if self._writinghandles is None:
2551 if self._writinghandles is None:
2536 msg = b'adding revision outside `revlog._writing` context'
2552 msg = b'adding revision outside `revlog._writing` context'
2537 raise error.ProgrammingError(msg)
2553 raise error.ProgrammingError(msg)
2538
2554
2539 if self._inline:
2555 if self._inline:
2540 fh = self._writinghandles[0]
2556 fh = self._writinghandles[0]
2541 else:
2557 else:
2542 fh = self._writinghandles[1]
2558 fh = self._writinghandles[1]
2543
2559
2544 btext = [rawtext]
2560 btext = [rawtext]
2545
2561
2546 curr = len(self)
2562 curr = len(self)
2547 prev = curr - 1
2563 prev = curr - 1
2548
2564
2549 offset = self._get_data_offset(prev)
2565 offset = self._get_data_offset(prev)
2550
2566
2551 if self._concurrencychecker:
2567 if self._concurrencychecker:
2552 ifh, dfh, sdfh = self._writinghandles
2568 ifh, dfh, sdfh = self._writinghandles
2553 # XXX no checking for the sidedata file
2569 # XXX no checking for the sidedata file
2554 if self._inline:
2570 if self._inline:
2555 # offset is "as if" it were in the .d file, so we need to add on
2571 # offset is "as if" it were in the .d file, so we need to add on
2556 # the size of the entry metadata.
2572 # the size of the entry metadata.
2557 self._concurrencychecker(
2573 self._concurrencychecker(
2558 ifh, self._indexfile, offset + curr * self.index.entry_size
2574 ifh, self._indexfile, offset + curr * self.index.entry_size
2559 )
2575 )
2560 else:
2576 else:
2561 # Entries in the .i are a consistent size.
2577 # Entries in the .i are a consistent size.
2562 self._concurrencychecker(
2578 self._concurrencychecker(
2563 ifh, self._indexfile, curr * self.index.entry_size
2579 ifh, self._indexfile, curr * self.index.entry_size
2564 )
2580 )
2565 self._concurrencychecker(dfh, self._datafile, offset)
2581 self._concurrencychecker(dfh, self._datafile, offset)
2566
2582
2567 p1r, p2r = self.rev(p1), self.rev(p2)
2583 p1r, p2r = self.rev(p1), self.rev(p2)
2568
2584
2569 # full versions are inserted when the needed deltas
2585 # full versions are inserted when the needed deltas
2570 # become comparable to the uncompressed text
2586 # become comparable to the uncompressed text
2571 if rawtext is None:
2587 if rawtext is None:
2572 # need rawtext size, before changed by flag processors, which is
2588 # need rawtext size, before changed by flag processors, which is
2573 # the non-raw size. use revlog explicitly to avoid filelog's extra
2589 # the non-raw size. use revlog explicitly to avoid filelog's extra
2574 # logic that might remove metadata size.
2590 # logic that might remove metadata size.
2575 textlen = mdiff.patchedsize(
2591 textlen = mdiff.patchedsize(
2576 revlog.size(self, cachedelta[0]), cachedelta[1]
2592 revlog.size(self, cachedelta[0]), cachedelta[1]
2577 )
2593 )
2578 else:
2594 else:
2579 textlen = len(rawtext)
2595 textlen = len(rawtext)
2580
2596
2581 if deltacomputer is None:
2597 if deltacomputer is None:
2582 write_debug = None
2598 write_debug = None
2583 if self._debug_delta:
2599 if self._debug_delta:
2584 write_debug = transaction._report
2600 write_debug = transaction._report
2585 deltacomputer = deltautil.deltacomputer(
2601 deltacomputer = deltautil.deltacomputer(
2586 self, write_debug=write_debug
2602 self, write_debug=write_debug
2587 )
2603 )
2588
2604
2589 if cachedelta is not None and len(cachedelta) == 2:
2605 if cachedelta is not None and len(cachedelta) == 2:
2590 # If the cached delta has no information about how it should be
2606 # If the cached delta has no information about how it should be
2591 # reused, add the default reuse instruction according to the
2607 # reused, add the default reuse instruction according to the
2592 # revlog's configuration.
2608 # revlog's configuration.
2593 if self._generaldelta and self._lazydeltabase:
2609 if self._generaldelta and self._lazydeltabase:
2594 delta_base_reuse = DELTA_BASE_REUSE_TRY
2610 delta_base_reuse = DELTA_BASE_REUSE_TRY
2595 else:
2611 else:
2596 delta_base_reuse = DELTA_BASE_REUSE_NO
2612 delta_base_reuse = DELTA_BASE_REUSE_NO
2597 cachedelta = (cachedelta[0], cachedelta[1], delta_base_reuse)
2613 cachedelta = (cachedelta[0], cachedelta[1], delta_base_reuse)
2598
2614
2599 revinfo = revlogutils.revisioninfo(
2615 revinfo = revlogutils.revisioninfo(
2600 node,
2616 node,
2601 p1,
2617 p1,
2602 p2,
2618 p2,
2603 btext,
2619 btext,
2604 textlen,
2620 textlen,
2605 cachedelta,
2621 cachedelta,
2606 flags,
2622 flags,
2607 )
2623 )
2608
2624
2609 deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
2625 deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
2610
2626
2611 compression_mode = COMP_MODE_INLINE
2627 compression_mode = COMP_MODE_INLINE
2612 if self._docket is not None:
2628 if self._docket is not None:
2613 default_comp = self._docket.default_compression_header
2629 default_comp = self._docket.default_compression_header
2614 r = deltautil.delta_compression(default_comp, deltainfo)
2630 r = deltautil.delta_compression(default_comp, deltainfo)
2615 compression_mode, deltainfo = r
2631 compression_mode, deltainfo = r
2616
2632
2617 sidedata_compression_mode = COMP_MODE_INLINE
2633 sidedata_compression_mode = COMP_MODE_INLINE
2618 if sidedata and self.hassidedata:
2634 if sidedata and self.hassidedata:
2619 sidedata_compression_mode = COMP_MODE_PLAIN
2635 sidedata_compression_mode = COMP_MODE_PLAIN
2620 serialized_sidedata = sidedatautil.serialize_sidedata(sidedata)
2636 serialized_sidedata = sidedatautil.serialize_sidedata(sidedata)
2621 sidedata_offset = self._docket.sidedata_end
2637 sidedata_offset = self._docket.sidedata_end
2622 h, comp_sidedata = self.compress(serialized_sidedata)
2638 h, comp_sidedata = self.compress(serialized_sidedata)
2623 if (
2639 if (
2624 h != b'u'
2640 h != b'u'
2625 and comp_sidedata[0:1] != b'\0'
2641 and comp_sidedata[0:1] != b'\0'
2626 and len(comp_sidedata) < len(serialized_sidedata)
2642 and len(comp_sidedata) < len(serialized_sidedata)
2627 ):
2643 ):
2628 assert not h
2644 assert not h
2629 if (
2645 if (
2630 comp_sidedata[0:1]
2646 comp_sidedata[0:1]
2631 == self._docket.default_compression_header
2647 == self._docket.default_compression_header
2632 ):
2648 ):
2633 sidedata_compression_mode = COMP_MODE_DEFAULT
2649 sidedata_compression_mode = COMP_MODE_DEFAULT
2634 serialized_sidedata = comp_sidedata
2650 serialized_sidedata = comp_sidedata
2635 else:
2651 else:
2636 sidedata_compression_mode = COMP_MODE_INLINE
2652 sidedata_compression_mode = COMP_MODE_INLINE
2637 serialized_sidedata = comp_sidedata
2653 serialized_sidedata = comp_sidedata
2638 else:
2654 else:
2639 serialized_sidedata = b""
2655 serialized_sidedata = b""
2640 # Don't store the offset if the sidedata is empty, that way
2656 # Don't store the offset if the sidedata is empty, that way
2641 # we can easily detect empty sidedata and they will be no different
2657 # we can easily detect empty sidedata and they will be no different
2642 # than ones we manually add.
2658 # than ones we manually add.
2643 sidedata_offset = 0
2659 sidedata_offset = 0
2644
2660
2645 rank = RANK_UNKNOWN
2661 rank = RANK_UNKNOWN
2646 if self._compute_rank:
2662 if self._compute_rank:
2647 if (p1r, p2r) == (nullrev, nullrev):
2663 if (p1r, p2r) == (nullrev, nullrev):
2648 rank = 1
2664 rank = 1
2649 elif p1r != nullrev and p2r == nullrev:
2665 elif p1r != nullrev and p2r == nullrev:
2650 rank = 1 + self.fast_rank(p1r)
2666 rank = 1 + self.fast_rank(p1r)
2651 elif p1r == nullrev and p2r != nullrev:
2667 elif p1r == nullrev and p2r != nullrev:
2652 rank = 1 + self.fast_rank(p2r)
2668 rank = 1 + self.fast_rank(p2r)
2653 else: # merge node
2669 else: # merge node
2654 if rustdagop is not None and self.index.rust_ext_compat:
2670 if rustdagop is not None and self.index.rust_ext_compat:
2655 rank = rustdagop.rank(self.index, p1r, p2r)
2671 rank = rustdagop.rank(self.index, p1r, p2r)
2656 else:
2672 else:
2657 pmin, pmax = sorted((p1r, p2r))
2673 pmin, pmax = sorted((p1r, p2r))
2658 rank = 1 + self.fast_rank(pmax)
2674 rank = 1 + self.fast_rank(pmax)
2659 rank += sum(1 for _ in self.findmissingrevs([pmax], [pmin]))
2675 rank += sum(1 for _ in self.findmissingrevs([pmax], [pmin]))
2660
2676
2661 e = revlogutils.entry(
2677 e = revlogutils.entry(
2662 flags=flags,
2678 flags=flags,
2663 data_offset=offset,
2679 data_offset=offset,
2664 data_compressed_length=deltainfo.deltalen,
2680 data_compressed_length=deltainfo.deltalen,
2665 data_uncompressed_length=textlen,
2681 data_uncompressed_length=textlen,
2666 data_compression_mode=compression_mode,
2682 data_compression_mode=compression_mode,
2667 data_delta_base=deltainfo.base,
2683 data_delta_base=deltainfo.base,
2668 link_rev=link,
2684 link_rev=link,
2669 parent_rev_1=p1r,
2685 parent_rev_1=p1r,
2670 parent_rev_2=p2r,
2686 parent_rev_2=p2r,
2671 node_id=node,
2687 node_id=node,
2672 sidedata_offset=sidedata_offset,
2688 sidedata_offset=sidedata_offset,
2673 sidedata_compressed_length=len(serialized_sidedata),
2689 sidedata_compressed_length=len(serialized_sidedata),
2674 sidedata_compression_mode=sidedata_compression_mode,
2690 sidedata_compression_mode=sidedata_compression_mode,
2675 rank=rank,
2691 rank=rank,
2676 )
2692 )
2677
2693
2678 self.index.append(e)
2694 self.index.append(e)
2679 entry = self.index.entry_binary(curr)
2695 entry = self.index.entry_binary(curr)
2680 if curr == 0 and self._docket is None:
2696 if curr == 0 and self._docket is None:
2681 header = self._format_flags | self._format_version
2697 header = self._format_flags | self._format_version
2682 header = self.index.pack_header(header)
2698 header = self.index.pack_header(header)
2683 entry = header + entry
2699 entry = header + entry
2684 self._writeentry(
2700 self._writeentry(
2685 transaction,
2701 transaction,
2686 entry,
2702 entry,
2687 deltainfo.data,
2703 deltainfo.data,
2688 link,
2704 link,
2689 offset,
2705 offset,
2690 serialized_sidedata,
2706 serialized_sidedata,
2691 sidedata_offset,
2707 sidedata_offset,
2692 )
2708 )
2693
2709
2694 rawtext = btext[0]
2710 rawtext = btext[0]
2695
2711
2696 if alwayscache and rawtext is None:
2712 if alwayscache and rawtext is None:
2697 rawtext = deltacomputer.buildtext(revinfo, fh)
2713 rawtext = deltacomputer.buildtext(revinfo, fh)
2698
2714
2699 if type(rawtext) == bytes: # only accept immutable objects
2715 if type(rawtext) == bytes: # only accept immutable objects
2700 self._revisioncache = (node, curr, rawtext)
2716 self._revisioncache = (node, curr, rawtext)
2701 self._chainbasecache[curr] = deltainfo.chainbase
2717 self._chainbasecache[curr] = deltainfo.chainbase
2702 return curr
2718 return curr
2703
2719
2704 def _get_data_offset(self, prev):
2720 def _get_data_offset(self, prev):
2705 """Returns the current offset in the (in-transaction) data file.
2721 """Returns the current offset in the (in-transaction) data file.
2706 Versions < 2 of the revlog can get this 0(1), revlog v2 needs a docket
2722 Versions < 2 of the revlog can get this 0(1), revlog v2 needs a docket
2707 file to store that information: since sidedata can be rewritten to the
2723 file to store that information: since sidedata can be rewritten to the
2708 end of the data file within a transaction, you can have cases where, for
2724 end of the data file within a transaction, you can have cases where, for
2709 example, rev `n` does not have sidedata while rev `n - 1` does, leading
2725 example, rev `n` does not have sidedata while rev `n - 1` does, leading
2710 to `n - 1`'s sidedata being written after `n`'s data.
2726 to `n - 1`'s sidedata being written after `n`'s data.
2711
2727
2712 TODO cache this in a docket file before getting out of experimental."""
2728 TODO cache this in a docket file before getting out of experimental."""
2713 if self._docket is None:
2729 if self._docket is None:
2714 return self.end(prev)
2730 return self.end(prev)
2715 else:
2731 else:
2716 return self._docket.data_end
2732 return self._docket.data_end
2717
2733
2718 def _writeentry(
2734 def _writeentry(
2719 self, transaction, entry, data, link, offset, sidedata, sidedata_offset
2735 self, transaction, entry, data, link, offset, sidedata, sidedata_offset
2720 ):
2736 ):
2721 # Files opened in a+ mode have inconsistent behavior on various
2737 # Files opened in a+ mode have inconsistent behavior on various
2722 # platforms. Windows requires that a file positioning call be made
2738 # platforms. Windows requires that a file positioning call be made
2723 # when the file handle transitions between reads and writes. See
2739 # when the file handle transitions between reads and writes. See
2724 # 3686fa2b8eee and the mixedfilemodewrapper in windows.py. On other
2740 # 3686fa2b8eee and the mixedfilemodewrapper in windows.py. On other
2725 # platforms, Python or the platform itself can be buggy. Some versions
2741 # platforms, Python or the platform itself can be buggy. Some versions
2726 # of Solaris have been observed to not append at the end of the file
2742 # of Solaris have been observed to not append at the end of the file
2727 # if the file was seeked to before the end. See issue4943 for more.
2743 # if the file was seeked to before the end. See issue4943 for more.
2728 #
2744 #
2729 # We work around this issue by inserting a seek() before writing.
2745 # We work around this issue by inserting a seek() before writing.
2730 # Note: This is likely not necessary on Python 3. However, because
2746 # Note: This is likely not necessary on Python 3. However, because
2731 # the file handle is reused for reads and may be seeked there, we need
2747 # the file handle is reused for reads and may be seeked there, we need
2732 # to be careful before changing this.
2748 # to be careful before changing this.
2733 if self._writinghandles is None:
2749 if self._writinghandles is None:
2734 msg = b'adding revision outside `revlog._writing` context'
2750 msg = b'adding revision outside `revlog._writing` context'
2735 raise error.ProgrammingError(msg)
2751 raise error.ProgrammingError(msg)
2736 ifh, dfh, sdfh = self._writinghandles
2752 ifh, dfh, sdfh = self._writinghandles
2737 if self._docket is None:
2753 if self._docket is None:
2738 ifh.seek(0, os.SEEK_END)
2754 ifh.seek(0, os.SEEK_END)
2739 else:
2755 else:
2740 ifh.seek(self._docket.index_end, os.SEEK_SET)
2756 ifh.seek(self._docket.index_end, os.SEEK_SET)
2741 if dfh:
2757 if dfh:
2742 if self._docket is None:
2758 if self._docket is None:
2743 dfh.seek(0, os.SEEK_END)
2759 dfh.seek(0, os.SEEK_END)
2744 else:
2760 else:
2745 dfh.seek(self._docket.data_end, os.SEEK_SET)
2761 dfh.seek(self._docket.data_end, os.SEEK_SET)
2746 if sdfh:
2762 if sdfh:
2747 sdfh.seek(self._docket.sidedata_end, os.SEEK_SET)
2763 sdfh.seek(self._docket.sidedata_end, os.SEEK_SET)
2748
2764
2749 curr = len(self) - 1
2765 curr = len(self) - 1
2750 if not self._inline:
2766 if not self._inline:
2751 transaction.add(self._datafile, offset)
2767 transaction.add(self._datafile, offset)
2752 if self._sidedatafile:
2768 if self._sidedatafile:
2753 transaction.add(self._sidedatafile, sidedata_offset)
2769 transaction.add(self._sidedatafile, sidedata_offset)
2754 transaction.add(self._indexfile, curr * len(entry))
2770 transaction.add(self._indexfile, curr * len(entry))
2755 if data[0]:
2771 if data[0]:
2756 dfh.write(data[0])
2772 dfh.write(data[0])
2757 dfh.write(data[1])
2773 dfh.write(data[1])
2758 if sidedata:
2774 if sidedata:
2759 sdfh.write(sidedata)
2775 sdfh.write(sidedata)
2760 ifh.write(entry)
2776 ifh.write(entry)
2761 else:
2777 else:
2762 offset += curr * self.index.entry_size
2778 offset += curr * self.index.entry_size
2763 transaction.add(self._indexfile, offset)
2779 transaction.add(self._indexfile, offset)
2764 ifh.write(entry)
2780 ifh.write(entry)
2765 ifh.write(data[0])
2781 ifh.write(data[0])
2766 ifh.write(data[1])
2782 ifh.write(data[1])
2767 assert not sidedata
2783 assert not sidedata
2768 self._enforceinlinesize(transaction)
2784 self._enforceinlinesize(transaction)
2769 if self._docket is not None:
2785 if self._docket is not None:
2770 # revlog-v2 always has 3 writing handles, help Pytype
2786 # revlog-v2 always has 3 writing handles, help Pytype
2771 wh1 = self._writinghandles[0]
2787 wh1 = self._writinghandles[0]
2772 wh2 = self._writinghandles[1]
2788 wh2 = self._writinghandles[1]
2773 wh3 = self._writinghandles[2]
2789 wh3 = self._writinghandles[2]
2774 assert wh1 is not None
2790 assert wh1 is not None
2775 assert wh2 is not None
2791 assert wh2 is not None
2776 assert wh3 is not None
2792 assert wh3 is not None
2777 self._docket.index_end = wh1.tell()
2793 self._docket.index_end = wh1.tell()
2778 self._docket.data_end = wh2.tell()
2794 self._docket.data_end = wh2.tell()
2779 self._docket.sidedata_end = wh3.tell()
2795 self._docket.sidedata_end = wh3.tell()
2780
2796
2781 nodemaputil.setup_persistent_nodemap(transaction, self)
2797 nodemaputil.setup_persistent_nodemap(transaction, self)
2782
2798
2783 def addgroup(
2799 def addgroup(
2784 self,
2800 self,
2785 deltas,
2801 deltas,
2786 linkmapper,
2802 linkmapper,
2787 transaction,
2803 transaction,
2788 alwayscache=False,
2804 alwayscache=False,
2789 addrevisioncb=None,
2805 addrevisioncb=None,
2790 duplicaterevisioncb=None,
2806 duplicaterevisioncb=None,
2791 debug_info=None,
2807 debug_info=None,
2792 delta_base_reuse_policy=None,
2808 delta_base_reuse_policy=None,
2793 ):
2809 ):
2794 """
2810 """
2795 add a delta group
2811 add a delta group
2796
2812
2797 given a set of deltas, add them to the revision log. the
2813 given a set of deltas, add them to the revision log. the
2798 first delta is against its parent, which should be in our
2814 first delta is against its parent, which should be in our
2799 log, the rest are against the previous delta.
2815 log, the rest are against the previous delta.
2800
2816
2801 If ``addrevisioncb`` is defined, it will be called with arguments of
2817 If ``addrevisioncb`` is defined, it will be called with arguments of
2802 this revlog and the node that was added.
2818 this revlog and the node that was added.
2803 """
2819 """
2804
2820
2805 if self._adding_group:
2821 if self._adding_group:
2806 raise error.ProgrammingError(b'cannot nest addgroup() calls')
2822 raise error.ProgrammingError(b'cannot nest addgroup() calls')
2807
2823
2808 # read the default delta-base reuse policy from revlog config if the
2824 # read the default delta-base reuse policy from revlog config if the
2809 # group did not specify one.
2825 # group did not specify one.
2810 if delta_base_reuse_policy is None:
2826 if delta_base_reuse_policy is None:
2811 if self._generaldelta and self._lazydeltabase:
2827 if self._generaldelta and self._lazydeltabase:
2812 delta_base_reuse_policy = DELTA_BASE_REUSE_TRY
2828 delta_base_reuse_policy = DELTA_BASE_REUSE_TRY
2813 else:
2829 else:
2814 delta_base_reuse_policy = DELTA_BASE_REUSE_NO
2830 delta_base_reuse_policy = DELTA_BASE_REUSE_NO
2815
2831
2816 self._adding_group = True
2832 self._adding_group = True
2817 empty = True
2833 empty = True
2818 try:
2834 try:
2819 with self._writing(transaction):
2835 with self._writing(transaction):
2820 write_debug = None
2836 write_debug = None
2821 if self._debug_delta:
2837 if self._debug_delta:
2822 write_debug = transaction._report
2838 write_debug = transaction._report
2823 deltacomputer = deltautil.deltacomputer(
2839 deltacomputer = deltautil.deltacomputer(
2824 self,
2840 self,
2825 write_debug=write_debug,
2841 write_debug=write_debug,
2826 debug_info=debug_info,
2842 debug_info=debug_info,
2827 )
2843 )
2828 # loop through our set of deltas
2844 # loop through our set of deltas
2829 for data in deltas:
2845 for data in deltas:
2830 (
2846 (
2831 node,
2847 node,
2832 p1,
2848 p1,
2833 p2,
2849 p2,
2834 linknode,
2850 linknode,
2835 deltabase,
2851 deltabase,
2836 delta,
2852 delta,
2837 flags,
2853 flags,
2838 sidedata,
2854 sidedata,
2839 ) = data
2855 ) = data
2840 link = linkmapper(linknode)
2856 link = linkmapper(linknode)
2841 flags = flags or REVIDX_DEFAULT_FLAGS
2857 flags = flags or REVIDX_DEFAULT_FLAGS
2842
2858
2843 rev = self.index.get_rev(node)
2859 rev = self.index.get_rev(node)
2844 if rev is not None:
2860 if rev is not None:
2845 # this can happen if two branches make the same change
2861 # this can happen if two branches make the same change
2846 self._nodeduplicatecallback(transaction, rev)
2862 self._nodeduplicatecallback(transaction, rev)
2847 if duplicaterevisioncb:
2863 if duplicaterevisioncb:
2848 duplicaterevisioncb(self, rev)
2864 duplicaterevisioncb(self, rev)
2849 empty = False
2865 empty = False
2850 continue
2866 continue
2851
2867
2852 for p in (p1, p2):
2868 for p in (p1, p2):
2853 if not self.index.has_node(p):
2869 if not self.index.has_node(p):
2854 raise error.LookupError(
2870 raise error.LookupError(
2855 p, self.radix, _(b'unknown parent')
2871 p, self.radix, _(b'unknown parent')
2856 )
2872 )
2857
2873
2858 if not self.index.has_node(deltabase):
2874 if not self.index.has_node(deltabase):
2859 raise error.LookupError(
2875 raise error.LookupError(
2860 deltabase, self.display_id, _(b'unknown delta base')
2876 deltabase, self.display_id, _(b'unknown delta base')
2861 )
2877 )
2862
2878
2863 baserev = self.rev(deltabase)
2879 baserev = self.rev(deltabase)
2864
2880
2865 if baserev != nullrev and self.iscensored(baserev):
2881 if baserev != nullrev and self.iscensored(baserev):
2866 # if base is censored, delta must be full replacement in a
2882 # if base is censored, delta must be full replacement in a
2867 # single patch operation
2883 # single patch operation
2868 hlen = struct.calcsize(b">lll")
2884 hlen = struct.calcsize(b">lll")
2869 oldlen = self.rawsize(baserev)
2885 oldlen = self.rawsize(baserev)
2870 newlen = len(delta) - hlen
2886 newlen = len(delta) - hlen
2871 if delta[:hlen] != mdiff.replacediffheader(
2887 if delta[:hlen] != mdiff.replacediffheader(
2872 oldlen, newlen
2888 oldlen, newlen
2873 ):
2889 ):
2874 raise error.CensoredBaseError(
2890 raise error.CensoredBaseError(
2875 self.display_id, self.node(baserev)
2891 self.display_id, self.node(baserev)
2876 )
2892 )
2877
2893
2878 if not flags and self._peek_iscensored(baserev, delta):
2894 if not flags and self._peek_iscensored(baserev, delta):
2879 flags |= REVIDX_ISCENSORED
2895 flags |= REVIDX_ISCENSORED
2880
2896
2881 # We assume consumers of addrevisioncb will want to retrieve
2897 # We assume consumers of addrevisioncb will want to retrieve
2882 # the added revision, which will require a call to
2898 # the added revision, which will require a call to
2883 # revision(). revision() will fast path if there is a cache
2899 # revision(). revision() will fast path if there is a cache
2884 # hit. So, we tell _addrevision() to always cache in this case.
2900 # hit. So, we tell _addrevision() to always cache in this case.
2885 # We're only using addgroup() in the context of changegroup
2901 # We're only using addgroup() in the context of changegroup
2886 # generation so the revision data can always be handled as raw
2902 # generation so the revision data can always be handled as raw
2887 # by the flagprocessor.
2903 # by the flagprocessor.
2888 rev = self._addrevision(
2904 rev = self._addrevision(
2889 node,
2905 node,
2890 None,
2906 None,
2891 transaction,
2907 transaction,
2892 link,
2908 link,
2893 p1,
2909 p1,
2894 p2,
2910 p2,
2895 flags,
2911 flags,
2896 (baserev, delta, delta_base_reuse_policy),
2912 (baserev, delta, delta_base_reuse_policy),
2897 alwayscache=alwayscache,
2913 alwayscache=alwayscache,
2898 deltacomputer=deltacomputer,
2914 deltacomputer=deltacomputer,
2899 sidedata=sidedata,
2915 sidedata=sidedata,
2900 )
2916 )
2901
2917
2902 if addrevisioncb:
2918 if addrevisioncb:
2903 addrevisioncb(self, rev)
2919 addrevisioncb(self, rev)
2904 empty = False
2920 empty = False
2905 finally:
2921 finally:
2906 self._adding_group = False
2922 self._adding_group = False
2907 return not empty
2923 return not empty
2908
2924
2909 def iscensored(self, rev):
2925 def iscensored(self, rev):
2910 """Check if a file revision is censored."""
2926 """Check if a file revision is censored."""
2911 if not self._censorable:
2927 if not self._censorable:
2912 return False
2928 return False
2913
2929
2914 return self.flags(rev) & REVIDX_ISCENSORED
2930 return self.flags(rev) & REVIDX_ISCENSORED
2915
2931
2916 def _peek_iscensored(self, baserev, delta):
2932 def _peek_iscensored(self, baserev, delta):
2917 """Quickly check if a delta produces a censored revision."""
2933 """Quickly check if a delta produces a censored revision."""
2918 if not self._censorable:
2934 if not self._censorable:
2919 return False
2935 return False
2920
2936
2921 return storageutil.deltaiscensored(delta, baserev, self.rawsize)
2937 return storageutil.deltaiscensored(delta, baserev, self.rawsize)
2922
2938
2923 def getstrippoint(self, minlink):
2939 def getstrippoint(self, minlink):
2924 """find the minimum rev that must be stripped to strip the linkrev
2940 """find the minimum rev that must be stripped to strip the linkrev
2925
2941
2926 Returns a tuple containing the minimum rev and a set of all revs that
2942 Returns a tuple containing the minimum rev and a set of all revs that
2927 have linkrevs that will be broken by this strip.
2943 have linkrevs that will be broken by this strip.
2928 """
2944 """
2929 return storageutil.resolvestripinfo(
2945 return storageutil.resolvestripinfo(
2930 minlink,
2946 minlink,
2931 len(self) - 1,
2947 len(self) - 1,
2932 self.headrevs(),
2948 self.headrevs(),
2933 self.linkrev,
2949 self.linkrev,
2934 self.parentrevs,
2950 self.parentrevs,
2935 )
2951 )
2936
2952
2937 def strip(self, minlink, transaction):
2953 def strip(self, minlink, transaction):
2938 """truncate the revlog on the first revision with a linkrev >= minlink
2954 """truncate the revlog on the first revision with a linkrev >= minlink
2939
2955
2940 This function is called when we're stripping revision minlink and
2956 This function is called when we're stripping revision minlink and
2941 its descendants from the repository.
2957 its descendants from the repository.
2942
2958
2943 We have to remove all revisions with linkrev >= minlink, because
2959 We have to remove all revisions with linkrev >= minlink, because
2944 the equivalent changelog revisions will be renumbered after the
2960 the equivalent changelog revisions will be renumbered after the
2945 strip.
2961 strip.
2946
2962
2947 So we truncate the revlog on the first of these revisions, and
2963 So we truncate the revlog on the first of these revisions, and
2948 trust that the caller has saved the revisions that shouldn't be
2964 trust that the caller has saved the revisions that shouldn't be
2949 removed and that it'll re-add them after this truncation.
2965 removed and that it'll re-add them after this truncation.
2950 """
2966 """
2951 if len(self) == 0:
2967 if len(self) == 0:
2952 return
2968 return
2953
2969
2954 rev, _ = self.getstrippoint(minlink)
2970 rev, _ = self.getstrippoint(minlink)
2955 if rev == len(self):
2971 if rev == len(self):
2956 return
2972 return
2957
2973
2958 # first truncate the files on disk
2974 # first truncate the files on disk
2959 data_end = self.start(rev)
2975 data_end = self.start(rev)
2960 if not self._inline:
2976 if not self._inline:
2961 transaction.add(self._datafile, data_end)
2977 transaction.add(self._datafile, data_end)
2962 end = rev * self.index.entry_size
2978 end = rev * self.index.entry_size
2963 else:
2979 else:
2964 end = data_end + (rev * self.index.entry_size)
2980 end = data_end + (rev * self.index.entry_size)
2965
2981
2966 if self._sidedatafile:
2982 if self._sidedatafile:
2967 sidedata_end = self.sidedata_cut_off(rev)
2983 sidedata_end = self.sidedata_cut_off(rev)
2968 transaction.add(self._sidedatafile, sidedata_end)
2984 transaction.add(self._sidedatafile, sidedata_end)
2969
2985
2970 transaction.add(self._indexfile, end)
2986 transaction.add(self._indexfile, end)
2971 if self._docket is not None:
2987 if self._docket is not None:
2972 # XXX we could, leverage the docket while stripping. However it is
2988 # XXX we could, leverage the docket while stripping. However it is
2973 # not powerfull enough at the time of this comment
2989 # not powerfull enough at the time of this comment
2974 self._docket.index_end = end
2990 self._docket.index_end = end
2975 self._docket.data_end = data_end
2991 self._docket.data_end = data_end
2976 self._docket.sidedata_end = sidedata_end
2992 self._docket.sidedata_end = sidedata_end
2977 self._docket.write(transaction, stripping=True)
2993 self._docket.write(transaction, stripping=True)
2978
2994
2979 # then reset internal state in memory to forget those revisions
2995 # then reset internal state in memory to forget those revisions
2980 self._revisioncache = None
2996 self._revisioncache = None
2981 self._chaininfocache = util.lrucachedict(500)
2997 self._chaininfocache = util.lrucachedict(500)
2982 self._segmentfile.clear_cache()
2998 self._segmentfile.clear_cache()
2983 self._segmentfile_sidedata.clear_cache()
2999 self._segmentfile_sidedata.clear_cache()
2984
3000
2985 del self.index[rev:-1]
3001 del self.index[rev:-1]
2986
3002
2987 def checksize(self):
3003 def checksize(self):
2988 """Check size of index and data files
3004 """Check size of index and data files
2989
3005
2990 return a (dd, di) tuple.
3006 return a (dd, di) tuple.
2991 - dd: extra bytes for the "data" file
3007 - dd: extra bytes for the "data" file
2992 - di: extra bytes for the "index" file
3008 - di: extra bytes for the "index" file
2993
3009
2994 A healthy revlog will return (0, 0).
3010 A healthy revlog will return (0, 0).
2995 """
3011 """
2996 expected = 0
3012 expected = 0
2997 if len(self):
3013 if len(self):
2998 expected = max(0, self.end(len(self) - 1))
3014 expected = max(0, self.end(len(self) - 1))
2999
3015
3000 try:
3016 try:
3001 with self._datafp() as f:
3017 with self._datafp() as f:
3002 f.seek(0, io.SEEK_END)
3018 f.seek(0, io.SEEK_END)
3003 actual = f.tell()
3019 actual = f.tell()
3004 dd = actual - expected
3020 dd = actual - expected
3005 except FileNotFoundError:
3021 except FileNotFoundError:
3006 dd = 0
3022 dd = 0
3007
3023
3008 try:
3024 try:
3009 f = self.opener(self._indexfile)
3025 f = self.opener(self._indexfile)
3010 f.seek(0, io.SEEK_END)
3026 f.seek(0, io.SEEK_END)
3011 actual = f.tell()
3027 actual = f.tell()
3012 f.close()
3028 f.close()
3013 s = self.index.entry_size
3029 s = self.index.entry_size
3014 i = max(0, actual // s)
3030 i = max(0, actual // s)
3015 di = actual - (i * s)
3031 di = actual - (i * s)
3016 if self._inline:
3032 if self._inline:
3017 databytes = 0
3033 databytes = 0
3018 for r in self:
3034 for r in self:
3019 databytes += max(0, self.length(r))
3035 databytes += max(0, self.length(r))
3020 dd = 0
3036 dd = 0
3021 di = actual - len(self) * s - databytes
3037 di = actual - len(self) * s - databytes
3022 except FileNotFoundError:
3038 except FileNotFoundError:
3023 di = 0
3039 di = 0
3024
3040
3025 return (dd, di)
3041 return (dd, di)
3026
3042
3027 def files(self):
3043 def files(self):
3028 res = [self._indexfile]
3044 res = [self._indexfile]
3029 if self._docket_file is None:
3045 if self._docket_file is None:
3030 if not self._inline:
3046 if not self._inline:
3031 res.append(self._datafile)
3047 res.append(self._datafile)
3032 else:
3048 else:
3033 res.append(self._docket_file)
3049 res.append(self._docket_file)
3034 res.extend(self._docket.old_index_filepaths(include_empty=False))
3050 res.extend(self._docket.old_index_filepaths(include_empty=False))
3035 if self._docket.data_end:
3051 if self._docket.data_end:
3036 res.append(self._datafile)
3052 res.append(self._datafile)
3037 res.extend(self._docket.old_data_filepaths(include_empty=False))
3053 res.extend(self._docket.old_data_filepaths(include_empty=False))
3038 if self._docket.sidedata_end:
3054 if self._docket.sidedata_end:
3039 res.append(self._sidedatafile)
3055 res.append(self._sidedatafile)
3040 res.extend(self._docket.old_sidedata_filepaths(include_empty=False))
3056 res.extend(self._docket.old_sidedata_filepaths(include_empty=False))
3041 return res
3057 return res
3042
3058
3043 def emitrevisions(
3059 def emitrevisions(
3044 self,
3060 self,
3045 nodes,
3061 nodes,
3046 nodesorder=None,
3062 nodesorder=None,
3047 revisiondata=False,
3063 revisiondata=False,
3048 assumehaveparentrevisions=False,
3064 assumehaveparentrevisions=False,
3049 deltamode=repository.CG_DELTAMODE_STD,
3065 deltamode=repository.CG_DELTAMODE_STD,
3050 sidedata_helpers=None,
3066 sidedata_helpers=None,
3051 debug_info=None,
3067 debug_info=None,
3052 ):
3068 ):
3053 if nodesorder not in (b'nodes', b'storage', b'linear', None):
3069 if nodesorder not in (b'nodes', b'storage', b'linear', None):
3054 raise error.ProgrammingError(
3070 raise error.ProgrammingError(
3055 b'unhandled value for nodesorder: %s' % nodesorder
3071 b'unhandled value for nodesorder: %s' % nodesorder
3056 )
3072 )
3057
3073
3058 if nodesorder is None and not self._generaldelta:
3074 if nodesorder is None and not self._generaldelta:
3059 nodesorder = b'storage'
3075 nodesorder = b'storage'
3060
3076
3061 if (
3077 if (
3062 not self._storedeltachains
3078 not self._storedeltachains
3063 and deltamode != repository.CG_DELTAMODE_PREV
3079 and deltamode != repository.CG_DELTAMODE_PREV
3064 ):
3080 ):
3065 deltamode = repository.CG_DELTAMODE_FULL
3081 deltamode = repository.CG_DELTAMODE_FULL
3066
3082
3067 return storageutil.emitrevisions(
3083 return storageutil.emitrevisions(
3068 self,
3084 self,
3069 nodes,
3085 nodes,
3070 nodesorder,
3086 nodesorder,
3071 revlogrevisiondelta,
3087 revlogrevisiondelta,
3072 deltaparentfn=self.deltaparent,
3088 deltaparentfn=self.deltaparent,
3073 candeltafn=self.candelta,
3089 candeltafn=self.candelta,
3074 rawsizefn=self.rawsize,
3090 rawsizefn=self.rawsize,
3075 revdifffn=self.revdiff,
3091 revdifffn=self.revdiff,
3076 flagsfn=self.flags,
3092 flagsfn=self.flags,
3077 deltamode=deltamode,
3093 deltamode=deltamode,
3078 revisiondata=revisiondata,
3094 revisiondata=revisiondata,
3079 assumehaveparentrevisions=assumehaveparentrevisions,
3095 assumehaveparentrevisions=assumehaveparentrevisions,
3080 sidedata_helpers=sidedata_helpers,
3096 sidedata_helpers=sidedata_helpers,
3081 debug_info=debug_info,
3097 debug_info=debug_info,
3082 )
3098 )
3083
3099
3084 DELTAREUSEALWAYS = b'always'
3100 DELTAREUSEALWAYS = b'always'
3085 DELTAREUSESAMEREVS = b'samerevs'
3101 DELTAREUSESAMEREVS = b'samerevs'
3086 DELTAREUSENEVER = b'never'
3102 DELTAREUSENEVER = b'never'
3087
3103
3088 DELTAREUSEFULLADD = b'fulladd'
3104 DELTAREUSEFULLADD = b'fulladd'
3089
3105
3090 DELTAREUSEALL = {b'always', b'samerevs', b'never', b'fulladd'}
3106 DELTAREUSEALL = {b'always', b'samerevs', b'never', b'fulladd'}
3091
3107
3092 def clone(
3108 def clone(
3093 self,
3109 self,
3094 tr,
3110 tr,
3095 destrevlog,
3111 destrevlog,
3096 addrevisioncb=None,
3112 addrevisioncb=None,
3097 deltareuse=DELTAREUSESAMEREVS,
3113 deltareuse=DELTAREUSESAMEREVS,
3098 forcedeltabothparents=None,
3114 forcedeltabothparents=None,
3099 sidedata_helpers=None,
3115 sidedata_helpers=None,
3100 ):
3116 ):
3101 """Copy this revlog to another, possibly with format changes.
3117 """Copy this revlog to another, possibly with format changes.
3102
3118
3103 The destination revlog will contain the same revisions and nodes.
3119 The destination revlog will contain the same revisions and nodes.
3104 However, it may not be bit-for-bit identical due to e.g. delta encoding
3120 However, it may not be bit-for-bit identical due to e.g. delta encoding
3105 differences.
3121 differences.
3106
3122
3107 The ``deltareuse`` argument control how deltas from the existing revlog
3123 The ``deltareuse`` argument control how deltas from the existing revlog
3108 are preserved in the destination revlog. The argument can have the
3124 are preserved in the destination revlog. The argument can have the
3109 following values:
3125 following values:
3110
3126
3111 DELTAREUSEALWAYS
3127 DELTAREUSEALWAYS
3112 Deltas will always be reused (if possible), even if the destination
3128 Deltas will always be reused (if possible), even if the destination
3113 revlog would not select the same revisions for the delta. This is the
3129 revlog would not select the same revisions for the delta. This is the
3114 fastest mode of operation.
3130 fastest mode of operation.
3115 DELTAREUSESAMEREVS
3131 DELTAREUSESAMEREVS
3116 Deltas will be reused if the destination revlog would pick the same
3132 Deltas will be reused if the destination revlog would pick the same
3117 revisions for the delta. This mode strikes a balance between speed
3133 revisions for the delta. This mode strikes a balance between speed
3118 and optimization.
3134 and optimization.
3119 DELTAREUSENEVER
3135 DELTAREUSENEVER
3120 Deltas will never be reused. This is the slowest mode of execution.
3136 Deltas will never be reused. This is the slowest mode of execution.
3121 This mode can be used to recompute deltas (e.g. if the diff/delta
3137 This mode can be used to recompute deltas (e.g. if the diff/delta
3122 algorithm changes).
3138 algorithm changes).
3123 DELTAREUSEFULLADD
3139 DELTAREUSEFULLADD
3124 Revision will be re-added as if their were new content. This is
3140 Revision will be re-added as if their were new content. This is
3125 slower than DELTAREUSEALWAYS but allow more mechanism to kicks in.
3141 slower than DELTAREUSEALWAYS but allow more mechanism to kicks in.
3126 eg: large file detection and handling.
3142 eg: large file detection and handling.
3127
3143
3128 Delta computation can be slow, so the choice of delta reuse policy can
3144 Delta computation can be slow, so the choice of delta reuse policy can
3129 significantly affect run time.
3145 significantly affect run time.
3130
3146
3131 The default policy (``DELTAREUSESAMEREVS``) strikes a balance between
3147 The default policy (``DELTAREUSESAMEREVS``) strikes a balance between
3132 two extremes. Deltas will be reused if they are appropriate. But if the
3148 two extremes. Deltas will be reused if they are appropriate. But if the
3133 delta could choose a better revision, it will do so. This means if you
3149 delta could choose a better revision, it will do so. This means if you
3134 are converting a non-generaldelta revlog to a generaldelta revlog,
3150 are converting a non-generaldelta revlog to a generaldelta revlog,
3135 deltas will be recomputed if the delta's parent isn't a parent of the
3151 deltas will be recomputed if the delta's parent isn't a parent of the
3136 revision.
3152 revision.
3137
3153
3138 In addition to the delta policy, the ``forcedeltabothparents``
3154 In addition to the delta policy, the ``forcedeltabothparents``
3139 argument controls whether to force compute deltas against both parents
3155 argument controls whether to force compute deltas against both parents
3140 for merges. By default, the current default is used.
3156 for merges. By default, the current default is used.
3141
3157
3142 See `revlogutil.sidedata.get_sidedata_helpers` for the doc on
3158 See `revlogutil.sidedata.get_sidedata_helpers` for the doc on
3143 `sidedata_helpers`.
3159 `sidedata_helpers`.
3144 """
3160 """
3145 if deltareuse not in self.DELTAREUSEALL:
3161 if deltareuse not in self.DELTAREUSEALL:
3146 raise ValueError(
3162 raise ValueError(
3147 _(b'value for deltareuse invalid: %s') % deltareuse
3163 _(b'value for deltareuse invalid: %s') % deltareuse
3148 )
3164 )
3149
3165
3150 if len(destrevlog):
3166 if len(destrevlog):
3151 raise ValueError(_(b'destination revlog is not empty'))
3167 raise ValueError(_(b'destination revlog is not empty'))
3152
3168
3153 if getattr(self, 'filteredrevs', None):
3169 if getattr(self, 'filteredrevs', None):
3154 raise ValueError(_(b'source revlog has filtered revisions'))
3170 raise ValueError(_(b'source revlog has filtered revisions'))
3155 if getattr(destrevlog, 'filteredrevs', None):
3171 if getattr(destrevlog, 'filteredrevs', None):
3156 raise ValueError(_(b'destination revlog has filtered revisions'))
3172 raise ValueError(_(b'destination revlog has filtered revisions'))
3157
3173
3158 # lazydelta and lazydeltabase controls whether to reuse a cached delta,
3174 # lazydelta and lazydeltabase controls whether to reuse a cached delta,
3159 # if possible.
3175 # if possible.
3160 oldlazydelta = destrevlog._lazydelta
3176 oldlazydelta = destrevlog._lazydelta
3161 oldlazydeltabase = destrevlog._lazydeltabase
3177 oldlazydeltabase = destrevlog._lazydeltabase
3162 oldamd = destrevlog._deltabothparents
3178 oldamd = destrevlog._deltabothparents
3163
3179
3164 try:
3180 try:
3165 if deltareuse == self.DELTAREUSEALWAYS:
3181 if deltareuse == self.DELTAREUSEALWAYS:
3166 destrevlog._lazydeltabase = True
3182 destrevlog._lazydeltabase = True
3167 destrevlog._lazydelta = True
3183 destrevlog._lazydelta = True
3168 elif deltareuse == self.DELTAREUSESAMEREVS:
3184 elif deltareuse == self.DELTAREUSESAMEREVS:
3169 destrevlog._lazydeltabase = False
3185 destrevlog._lazydeltabase = False
3170 destrevlog._lazydelta = True
3186 destrevlog._lazydelta = True
3171 elif deltareuse == self.DELTAREUSENEVER:
3187 elif deltareuse == self.DELTAREUSENEVER:
3172 destrevlog._lazydeltabase = False
3188 destrevlog._lazydeltabase = False
3173 destrevlog._lazydelta = False
3189 destrevlog._lazydelta = False
3174
3190
3175 destrevlog._deltabothparents = forcedeltabothparents or oldamd
3191 destrevlog._deltabothparents = forcedeltabothparents or oldamd
3176
3192
3177 self._clone(
3193 self._clone(
3178 tr,
3194 tr,
3179 destrevlog,
3195 destrevlog,
3180 addrevisioncb,
3196 addrevisioncb,
3181 deltareuse,
3197 deltareuse,
3182 forcedeltabothparents,
3198 forcedeltabothparents,
3183 sidedata_helpers,
3199 sidedata_helpers,
3184 )
3200 )
3185
3201
3186 finally:
3202 finally:
3187 destrevlog._lazydelta = oldlazydelta
3203 destrevlog._lazydelta = oldlazydelta
3188 destrevlog._lazydeltabase = oldlazydeltabase
3204 destrevlog._lazydeltabase = oldlazydeltabase
3189 destrevlog._deltabothparents = oldamd
3205 destrevlog._deltabothparents = oldamd
3190
3206
3191 def _clone(
3207 def _clone(
3192 self,
3208 self,
3193 tr,
3209 tr,
3194 destrevlog,
3210 destrevlog,
3195 addrevisioncb,
3211 addrevisioncb,
3196 deltareuse,
3212 deltareuse,
3197 forcedeltabothparents,
3213 forcedeltabothparents,
3198 sidedata_helpers,
3214 sidedata_helpers,
3199 ):
3215 ):
3200 """perform the core duty of `revlog.clone` after parameter processing"""
3216 """perform the core duty of `revlog.clone` after parameter processing"""
3201 write_debug = None
3217 write_debug = None
3202 if self._debug_delta:
3218 if self._debug_delta:
3203 write_debug = tr._report
3219 write_debug = tr._report
3204 deltacomputer = deltautil.deltacomputer(
3220 deltacomputer = deltautil.deltacomputer(
3205 destrevlog,
3221 destrevlog,
3206 write_debug=write_debug,
3222 write_debug=write_debug,
3207 )
3223 )
3208 index = self.index
3224 index = self.index
3209 for rev in self:
3225 for rev in self:
3210 entry = index[rev]
3226 entry = index[rev]
3211
3227
3212 # Some classes override linkrev to take filtered revs into
3228 # Some classes override linkrev to take filtered revs into
3213 # account. Use raw entry from index.
3229 # account. Use raw entry from index.
3214 flags = entry[0] & 0xFFFF
3230 flags = entry[0] & 0xFFFF
3215 linkrev = entry[4]
3231 linkrev = entry[4]
3216 p1 = index[entry[5]][7]
3232 p1 = index[entry[5]][7]
3217 p2 = index[entry[6]][7]
3233 p2 = index[entry[6]][7]
3218 node = entry[7]
3234 node = entry[7]
3219
3235
3220 # (Possibly) reuse the delta from the revlog if allowed and
3236 # (Possibly) reuse the delta from the revlog if allowed and
3221 # the revlog chunk is a delta.
3237 # the revlog chunk is a delta.
3222 cachedelta = None
3238 cachedelta = None
3223 rawtext = None
3239 rawtext = None
3224 if deltareuse == self.DELTAREUSEFULLADD:
3240 if deltareuse == self.DELTAREUSEFULLADD:
3225 text = self._revisiondata(rev)
3241 text = self._revisiondata(rev)
3226 sidedata = self.sidedata(rev)
3242 sidedata = self.sidedata(rev)
3227
3243
3228 if sidedata_helpers is not None:
3244 if sidedata_helpers is not None:
3229 (sidedata, new_flags) = sidedatautil.run_sidedata_helpers(
3245 (sidedata, new_flags) = sidedatautil.run_sidedata_helpers(
3230 self, sidedata_helpers, sidedata, rev
3246 self, sidedata_helpers, sidedata, rev
3231 )
3247 )
3232 flags = flags | new_flags[0] & ~new_flags[1]
3248 flags = flags | new_flags[0] & ~new_flags[1]
3233
3249
3234 destrevlog.addrevision(
3250 destrevlog.addrevision(
3235 text,
3251 text,
3236 tr,
3252 tr,
3237 linkrev,
3253 linkrev,
3238 p1,
3254 p1,
3239 p2,
3255 p2,
3240 cachedelta=cachedelta,
3256 cachedelta=cachedelta,
3241 node=node,
3257 node=node,
3242 flags=flags,
3258 flags=flags,
3243 deltacomputer=deltacomputer,
3259 deltacomputer=deltacomputer,
3244 sidedata=sidedata,
3260 sidedata=sidedata,
3245 )
3261 )
3246 else:
3262 else:
3247 if destrevlog._lazydelta:
3263 if destrevlog._lazydelta:
3248 dp = self.deltaparent(rev)
3264 dp = self.deltaparent(rev)
3249 if dp != nullrev:
3265 if dp != nullrev:
3250 cachedelta = (dp, bytes(self._chunk(rev)))
3266 cachedelta = (dp, bytes(self._chunk(rev)))
3251
3267
3252 sidedata = None
3268 sidedata = None
3253 if not cachedelta:
3269 if not cachedelta:
3254 rawtext = self._revisiondata(rev)
3270 rawtext = self._revisiondata(rev)
3255 sidedata = self.sidedata(rev)
3271 sidedata = self.sidedata(rev)
3256 if sidedata is None:
3272 if sidedata is None:
3257 sidedata = self.sidedata(rev)
3273 sidedata = self.sidedata(rev)
3258
3274
3259 if sidedata_helpers is not None:
3275 if sidedata_helpers is not None:
3260 (sidedata, new_flags) = sidedatautil.run_sidedata_helpers(
3276 (sidedata, new_flags) = sidedatautil.run_sidedata_helpers(
3261 self, sidedata_helpers, sidedata, rev
3277 self, sidedata_helpers, sidedata, rev
3262 )
3278 )
3263 flags = flags | new_flags[0] & ~new_flags[1]
3279 flags = flags | new_flags[0] & ~new_flags[1]
3264
3280
3265 with destrevlog._writing(tr):
3281 with destrevlog._writing(tr):
3266 destrevlog._addrevision(
3282 destrevlog._addrevision(
3267 node,
3283 node,
3268 rawtext,
3284 rawtext,
3269 tr,
3285 tr,
3270 linkrev,
3286 linkrev,
3271 p1,
3287 p1,
3272 p2,
3288 p2,
3273 flags,
3289 flags,
3274 cachedelta,
3290 cachedelta,
3275 deltacomputer=deltacomputer,
3291 deltacomputer=deltacomputer,
3276 sidedata=sidedata,
3292 sidedata=sidedata,
3277 )
3293 )
3278
3294
3279 if addrevisioncb:
3295 if addrevisioncb:
3280 addrevisioncb(self, rev, node)
3296 addrevisioncb(self, rev, node)
3281
3297
3282 def censorrevision(self, tr, censornode, tombstone=b''):
3298 def censorrevision(self, tr, censornode, tombstone=b''):
3283 if self._format_version == REVLOGV0:
3299 if self._format_version == REVLOGV0:
3284 raise error.RevlogError(
3300 raise error.RevlogError(
3285 _(b'cannot censor with version %d revlogs')
3301 _(b'cannot censor with version %d revlogs')
3286 % self._format_version
3302 % self._format_version
3287 )
3303 )
3288 elif self._format_version == REVLOGV1:
3304 elif self._format_version == REVLOGV1:
3289 rewrite.v1_censor(self, tr, censornode, tombstone)
3305 rewrite.v1_censor(self, tr, censornode, tombstone)
3290 else:
3306 else:
3291 rewrite.v2_censor(self, tr, censornode, tombstone)
3307 rewrite.v2_censor(self, tr, censornode, tombstone)
3292
3308
3293 def verifyintegrity(self, state):
3309 def verifyintegrity(self, state):
3294 """Verifies the integrity of the revlog.
3310 """Verifies the integrity of the revlog.
3295
3311
3296 Yields ``revlogproblem`` instances describing problems that are
3312 Yields ``revlogproblem`` instances describing problems that are
3297 found.
3313 found.
3298 """
3314 """
3299 dd, di = self.checksize()
3315 dd, di = self.checksize()
3300 if dd:
3316 if dd:
3301 yield revlogproblem(error=_(b'data length off by %d bytes') % dd)
3317 yield revlogproblem(error=_(b'data length off by %d bytes') % dd)
3302 if di:
3318 if di:
3303 yield revlogproblem(error=_(b'index contains %d extra bytes') % di)
3319 yield revlogproblem(error=_(b'index contains %d extra bytes') % di)
3304
3320
3305 version = self._format_version
3321 version = self._format_version
3306
3322
3307 # The verifier tells us what version revlog we should be.
3323 # The verifier tells us what version revlog we should be.
3308 if version != state[b'expectedversion']:
3324 if version != state[b'expectedversion']:
3309 yield revlogproblem(
3325 yield revlogproblem(
3310 warning=_(b"warning: '%s' uses revlog format %d; expected %d")
3326 warning=_(b"warning: '%s' uses revlog format %d; expected %d")
3311 % (self.display_id, version, state[b'expectedversion'])
3327 % (self.display_id, version, state[b'expectedversion'])
3312 )
3328 )
3313
3329
3314 state[b'skipread'] = set()
3330 state[b'skipread'] = set()
3315 state[b'safe_renamed'] = set()
3331 state[b'safe_renamed'] = set()
3316
3332
3317 for rev in self:
3333 for rev in self:
3318 node = self.node(rev)
3334 node = self.node(rev)
3319
3335
3320 # Verify contents. 4 cases to care about:
3336 # Verify contents. 4 cases to care about:
3321 #
3337 #
3322 # common: the most common case
3338 # common: the most common case
3323 # rename: with a rename
3339 # rename: with a rename
3324 # meta: file content starts with b'\1\n', the metadata
3340 # meta: file content starts with b'\1\n', the metadata
3325 # header defined in filelog.py, but without a rename
3341 # header defined in filelog.py, but without a rename
3326 # ext: content stored externally
3342 # ext: content stored externally
3327 #
3343 #
3328 # More formally, their differences are shown below:
3344 # More formally, their differences are shown below:
3329 #
3345 #
3330 # | common | rename | meta | ext
3346 # | common | rename | meta | ext
3331 # -------------------------------------------------------
3347 # -------------------------------------------------------
3332 # flags() | 0 | 0 | 0 | not 0
3348 # flags() | 0 | 0 | 0 | not 0
3333 # renamed() | False | True | False | ?
3349 # renamed() | False | True | False | ?
3334 # rawtext[0:2]=='\1\n'| False | True | True | ?
3350 # rawtext[0:2]=='\1\n'| False | True | True | ?
3335 #
3351 #
3336 # "rawtext" means the raw text stored in revlog data, which
3352 # "rawtext" means the raw text stored in revlog data, which
3337 # could be retrieved by "rawdata(rev)". "text"
3353 # could be retrieved by "rawdata(rev)". "text"
3338 # mentioned below is "revision(rev)".
3354 # mentioned below is "revision(rev)".
3339 #
3355 #
3340 # There are 3 different lengths stored physically:
3356 # There are 3 different lengths stored physically:
3341 # 1. L1: rawsize, stored in revlog index
3357 # 1. L1: rawsize, stored in revlog index
3342 # 2. L2: len(rawtext), stored in revlog data
3358 # 2. L2: len(rawtext), stored in revlog data
3343 # 3. L3: len(text), stored in revlog data if flags==0, or
3359 # 3. L3: len(text), stored in revlog data if flags==0, or
3344 # possibly somewhere else if flags!=0
3360 # possibly somewhere else if flags!=0
3345 #
3361 #
3346 # L1 should be equal to L2. L3 could be different from them.
3362 # L1 should be equal to L2. L3 could be different from them.
3347 # "text" may or may not affect commit hash depending on flag
3363 # "text" may or may not affect commit hash depending on flag
3348 # processors (see flagutil.addflagprocessor).
3364 # processors (see flagutil.addflagprocessor).
3349 #
3365 #
3350 # | common | rename | meta | ext
3366 # | common | rename | meta | ext
3351 # -------------------------------------------------
3367 # -------------------------------------------------
3352 # rawsize() | L1 | L1 | L1 | L1
3368 # rawsize() | L1 | L1 | L1 | L1
3353 # size() | L1 | L2-LM | L1(*) | L1 (?)
3369 # size() | L1 | L2-LM | L1(*) | L1 (?)
3354 # len(rawtext) | L2 | L2 | L2 | L2
3370 # len(rawtext) | L2 | L2 | L2 | L2
3355 # len(text) | L2 | L2 | L2 | L3
3371 # len(text) | L2 | L2 | L2 | L3
3356 # len(read()) | L2 | L2-LM | L2-LM | L3 (?)
3372 # len(read()) | L2 | L2-LM | L2-LM | L3 (?)
3357 #
3373 #
3358 # LM: length of metadata, depending on rawtext
3374 # LM: length of metadata, depending on rawtext
3359 # (*): not ideal, see comment in filelog.size
3375 # (*): not ideal, see comment in filelog.size
3360 # (?): could be "- len(meta)" if the resolved content has
3376 # (?): could be "- len(meta)" if the resolved content has
3361 # rename metadata
3377 # rename metadata
3362 #
3378 #
3363 # Checks needed to be done:
3379 # Checks needed to be done:
3364 # 1. length check: L1 == L2, in all cases.
3380 # 1. length check: L1 == L2, in all cases.
3365 # 2. hash check: depending on flag processor, we may need to
3381 # 2. hash check: depending on flag processor, we may need to
3366 # use either "text" (external), or "rawtext" (in revlog).
3382 # use either "text" (external), or "rawtext" (in revlog).
3367
3383
3368 try:
3384 try:
3369 skipflags = state.get(b'skipflags', 0)
3385 skipflags = state.get(b'skipflags', 0)
3370 if skipflags:
3386 if skipflags:
3371 skipflags &= self.flags(rev)
3387 skipflags &= self.flags(rev)
3372
3388
3373 _verify_revision(self, skipflags, state, node)
3389 _verify_revision(self, skipflags, state, node)
3374
3390
3375 l1 = self.rawsize(rev)
3391 l1 = self.rawsize(rev)
3376 l2 = len(self.rawdata(node))
3392 l2 = len(self.rawdata(node))
3377
3393
3378 if l1 != l2:
3394 if l1 != l2:
3379 yield revlogproblem(
3395 yield revlogproblem(
3380 error=_(b'unpacked size is %d, %d expected') % (l2, l1),
3396 error=_(b'unpacked size is %d, %d expected') % (l2, l1),
3381 node=node,
3397 node=node,
3382 )
3398 )
3383
3399
3384 except error.CensoredNodeError:
3400 except error.CensoredNodeError:
3385 if state[b'erroroncensored']:
3401 if state[b'erroroncensored']:
3386 yield revlogproblem(
3402 yield revlogproblem(
3387 error=_(b'censored file data'), node=node
3403 error=_(b'censored file data'), node=node
3388 )
3404 )
3389 state[b'skipread'].add(node)
3405 state[b'skipread'].add(node)
3390 except Exception as e:
3406 except Exception as e:
3391 yield revlogproblem(
3407 yield revlogproblem(
3392 error=_(b'unpacking %s: %s')
3408 error=_(b'unpacking %s: %s')
3393 % (short(node), stringutil.forcebytestr(e)),
3409 % (short(node), stringutil.forcebytestr(e)),
3394 node=node,
3410 node=node,
3395 )
3411 )
3396 state[b'skipread'].add(node)
3412 state[b'skipread'].add(node)
3397
3413
3398 def storageinfo(
3414 def storageinfo(
3399 self,
3415 self,
3400 exclusivefiles=False,
3416 exclusivefiles=False,
3401 sharedfiles=False,
3417 sharedfiles=False,
3402 revisionscount=False,
3418 revisionscount=False,
3403 trackedsize=False,
3419 trackedsize=False,
3404 storedsize=False,
3420 storedsize=False,
3405 ):
3421 ):
3406 d = {}
3422 d = {}
3407
3423
3408 if exclusivefiles:
3424 if exclusivefiles:
3409 d[b'exclusivefiles'] = [(self.opener, self._indexfile)]
3425 d[b'exclusivefiles'] = [(self.opener, self._indexfile)]
3410 if not self._inline:
3426 if not self._inline:
3411 d[b'exclusivefiles'].append((self.opener, self._datafile))
3427 d[b'exclusivefiles'].append((self.opener, self._datafile))
3412
3428
3413 if sharedfiles:
3429 if sharedfiles:
3414 d[b'sharedfiles'] = []
3430 d[b'sharedfiles'] = []
3415
3431
3416 if revisionscount:
3432 if revisionscount:
3417 d[b'revisionscount'] = len(self)
3433 d[b'revisionscount'] = len(self)
3418
3434
3419 if trackedsize:
3435 if trackedsize:
3420 d[b'trackedsize'] = sum(map(self.rawsize, iter(self)))
3436 d[b'trackedsize'] = sum(map(self.rawsize, iter(self)))
3421
3437
3422 if storedsize:
3438 if storedsize:
3423 d[b'storedsize'] = sum(
3439 d[b'storedsize'] = sum(
3424 self.opener.stat(path).st_size for path in self.files()
3440 self.opener.stat(path).st_size for path in self.files()
3425 )
3441 )
3426
3442
3427 return d
3443 return d
3428
3444
3429 def rewrite_sidedata(self, transaction, helpers, startrev, endrev):
3445 def rewrite_sidedata(self, transaction, helpers, startrev, endrev):
3430 if not self.hassidedata:
3446 if not self.hassidedata:
3431 return
3447 return
3432 # revlog formats with sidedata support does not support inline
3448 # revlog formats with sidedata support does not support inline
3433 assert not self._inline
3449 assert not self._inline
3434 if not helpers[1] and not helpers[2]:
3450 if not helpers[1] and not helpers[2]:
3435 # Nothing to generate or remove
3451 # Nothing to generate or remove
3436 return
3452 return
3437
3453
3438 new_entries = []
3454 new_entries = []
3439 # append the new sidedata
3455 # append the new sidedata
3440 with self._writing(transaction):
3456 with self._writing(transaction):
3441 ifh, dfh, sdfh = self._writinghandles
3457 ifh, dfh, sdfh = self._writinghandles
3442 dfh.seek(self._docket.sidedata_end, os.SEEK_SET)
3458 dfh.seek(self._docket.sidedata_end, os.SEEK_SET)
3443
3459
3444 current_offset = sdfh.tell()
3460 current_offset = sdfh.tell()
3445 for rev in range(startrev, endrev + 1):
3461 for rev in range(startrev, endrev + 1):
3446 entry = self.index[rev]
3462 entry = self.index[rev]
3447 new_sidedata, flags = sidedatautil.run_sidedata_helpers(
3463 new_sidedata, flags = sidedatautil.run_sidedata_helpers(
3448 store=self,
3464 store=self,
3449 sidedata_helpers=helpers,
3465 sidedata_helpers=helpers,
3450 sidedata={},
3466 sidedata={},
3451 rev=rev,
3467 rev=rev,
3452 )
3468 )
3453
3469
3454 serialized_sidedata = sidedatautil.serialize_sidedata(
3470 serialized_sidedata = sidedatautil.serialize_sidedata(
3455 new_sidedata
3471 new_sidedata
3456 )
3472 )
3457
3473
3458 sidedata_compression_mode = COMP_MODE_INLINE
3474 sidedata_compression_mode = COMP_MODE_INLINE
3459 if serialized_sidedata and self.hassidedata:
3475 if serialized_sidedata and self.hassidedata:
3460 sidedata_compression_mode = COMP_MODE_PLAIN
3476 sidedata_compression_mode = COMP_MODE_PLAIN
3461 h, comp_sidedata = self.compress(serialized_sidedata)
3477 h, comp_sidedata = self.compress(serialized_sidedata)
3462 if (
3478 if (
3463 h != b'u'
3479 h != b'u'
3464 and comp_sidedata[0] != b'\0'
3480 and comp_sidedata[0] != b'\0'
3465 and len(comp_sidedata) < len(serialized_sidedata)
3481 and len(comp_sidedata) < len(serialized_sidedata)
3466 ):
3482 ):
3467 assert not h
3483 assert not h
3468 if (
3484 if (
3469 comp_sidedata[0]
3485 comp_sidedata[0]
3470 == self._docket.default_compression_header
3486 == self._docket.default_compression_header
3471 ):
3487 ):
3472 sidedata_compression_mode = COMP_MODE_DEFAULT
3488 sidedata_compression_mode = COMP_MODE_DEFAULT
3473 serialized_sidedata = comp_sidedata
3489 serialized_sidedata = comp_sidedata
3474 else:
3490 else:
3475 sidedata_compression_mode = COMP_MODE_INLINE
3491 sidedata_compression_mode = COMP_MODE_INLINE
3476 serialized_sidedata = comp_sidedata
3492 serialized_sidedata = comp_sidedata
3477 if entry[8] != 0 or entry[9] != 0:
3493 if entry[8] != 0 or entry[9] != 0:
3478 # rewriting entries that already have sidedata is not
3494 # rewriting entries that already have sidedata is not
3479 # supported yet, because it introduces garbage data in the
3495 # supported yet, because it introduces garbage data in the
3480 # revlog.
3496 # revlog.
3481 msg = b"rewriting existing sidedata is not supported yet"
3497 msg = b"rewriting existing sidedata is not supported yet"
3482 raise error.Abort(msg)
3498 raise error.Abort(msg)
3483
3499
3484 # Apply (potential) flags to add and to remove after running
3500 # Apply (potential) flags to add and to remove after running
3485 # the sidedata helpers
3501 # the sidedata helpers
3486 new_offset_flags = entry[0] | flags[0] & ~flags[1]
3502 new_offset_flags = entry[0] | flags[0] & ~flags[1]
3487 entry_update = (
3503 entry_update = (
3488 current_offset,
3504 current_offset,
3489 len(serialized_sidedata),
3505 len(serialized_sidedata),
3490 new_offset_flags,
3506 new_offset_flags,
3491 sidedata_compression_mode,
3507 sidedata_compression_mode,
3492 )
3508 )
3493
3509
3494 # the sidedata computation might have move the file cursors around
3510 # the sidedata computation might have move the file cursors around
3495 sdfh.seek(current_offset, os.SEEK_SET)
3511 sdfh.seek(current_offset, os.SEEK_SET)
3496 sdfh.write(serialized_sidedata)
3512 sdfh.write(serialized_sidedata)
3497 new_entries.append(entry_update)
3513 new_entries.append(entry_update)
3498 current_offset += len(serialized_sidedata)
3514 current_offset += len(serialized_sidedata)
3499 self._docket.sidedata_end = sdfh.tell()
3515 self._docket.sidedata_end = sdfh.tell()
3500
3516
3501 # rewrite the new index entries
3517 # rewrite the new index entries
3502 ifh.seek(startrev * self.index.entry_size)
3518 ifh.seek(startrev * self.index.entry_size)
3503 for i, e in enumerate(new_entries):
3519 for i, e in enumerate(new_entries):
3504 rev = startrev + i
3520 rev = startrev + i
3505 self.index.replace_sidedata_info(rev, *e)
3521 self.index.replace_sidedata_info(rev, *e)
3506 packed = self.index.entry_binary(rev)
3522 packed = self.index.entry_binary(rev)
3507 if rev == 0 and self._docket is None:
3523 if rev == 0 and self._docket is None:
3508 header = self._format_flags | self._format_version
3524 header = self._format_flags | self._format_version
3509 header = self.index.pack_header(header)
3525 header = self.index.pack_header(header)
3510 packed = header + packed
3526 packed = header + packed
3511 ifh.write(packed)
3527 ifh.write(packed)
@@ -1,1530 +1,1631 b''
1 # revlogdeltas.py - Logic around delta computation for revlog
1 # revlogdeltas.py - Logic around delta computation for revlog
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 # Copyright 2018 Octobus <contact@octobus.net>
4 # Copyright 2018 Octobus <contact@octobus.net>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8 """Helper class to compute deltas stored inside revlogs"""
8 """Helper class to compute deltas stored inside revlogs"""
9
9
10
10
11 import collections
11 import collections
12 import struct
12 import struct
13
13
14 # import stuff from node for others to import from revlog
14 # import stuff from node for others to import from revlog
15 from ..node import nullrev
15 from ..node import nullrev
16 from ..i18n import _
16 from ..i18n import _
17 from ..pycompat import getattr
17 from ..pycompat import getattr
18
18
19 from .constants import (
19 from .constants import (
20 COMP_MODE_DEFAULT,
20 COMP_MODE_DEFAULT,
21 COMP_MODE_INLINE,
21 COMP_MODE_INLINE,
22 COMP_MODE_PLAIN,
22 COMP_MODE_PLAIN,
23 DELTA_BASE_REUSE_FORCE,
23 DELTA_BASE_REUSE_FORCE,
24 DELTA_BASE_REUSE_NO,
24 DELTA_BASE_REUSE_NO,
25 KIND_CHANGELOG,
25 KIND_CHANGELOG,
26 KIND_FILELOG,
26 KIND_FILELOG,
27 KIND_MANIFESTLOG,
27 KIND_MANIFESTLOG,
28 REVIDX_ISCENSORED,
28 REVIDX_ISCENSORED,
29 REVIDX_RAWTEXT_CHANGING_FLAGS,
29 REVIDX_RAWTEXT_CHANGING_FLAGS,
30 )
30 )
31
31
32 from ..thirdparty import attr
32 from ..thirdparty import attr
33
33
34 from .. import (
34 from .. import (
35 error,
35 error,
36 mdiff,
36 mdiff,
37 util,
37 util,
38 )
38 )
39
39
40 from . import flagutil
40 from . import flagutil
41
41
42 # maximum <delta-chain-data>/<revision-text-length> ratio
42 # maximum <delta-chain-data>/<revision-text-length> ratio
43 LIMIT_DELTA2TEXT = 2
43 LIMIT_DELTA2TEXT = 2
44
44
45
45
46 class _testrevlog:
46 class _testrevlog:
47 """minimalist fake revlog to use in doctests"""
47 """minimalist fake revlog to use in doctests"""
48
48
49 def __init__(self, data, density=0.5, mingap=0, snapshot=()):
49 def __init__(self, data, density=0.5, mingap=0, snapshot=()):
50 """data is an list of revision payload boundaries"""
50 """data is an list of revision payload boundaries"""
51 self._data = data
51 self._data = data
52 self._srdensitythreshold = density
52 self._srdensitythreshold = density
53 self._srmingapsize = mingap
53 self._srmingapsize = mingap
54 self._snapshot = set(snapshot)
54 self._snapshot = set(snapshot)
55 self.index = None
55 self.index = None
56
56
57 def start(self, rev):
57 def start(self, rev):
58 if rev == nullrev:
58 if rev == nullrev:
59 return 0
59 return 0
60 if rev == 0:
60 if rev == 0:
61 return 0
61 return 0
62 return self._data[rev - 1]
62 return self._data[rev - 1]
63
63
64 def end(self, rev):
64 def end(self, rev):
65 if rev == nullrev:
65 if rev == nullrev:
66 return 0
66 return 0
67 return self._data[rev]
67 return self._data[rev]
68
68
69 def length(self, rev):
69 def length(self, rev):
70 return self.end(rev) - self.start(rev)
70 return self.end(rev) - self.start(rev)
71
71
72 def __len__(self):
72 def __len__(self):
73 return len(self._data)
73 return len(self._data)
74
74
75 def issnapshot(self, rev):
75 def issnapshot(self, rev):
76 if rev == nullrev:
76 if rev == nullrev:
77 return True
77 return True
78 return rev in self._snapshot
78 return rev in self._snapshot
79
79
80
80
81 def slicechunk(revlog, revs, targetsize=None):
81 def slicechunk(revlog, revs, targetsize=None):
82 """slice revs to reduce the amount of unrelated data to be read from disk.
82 """slice revs to reduce the amount of unrelated data to be read from disk.
83
83
84 ``revs`` is sliced into groups that should be read in one time.
84 ``revs`` is sliced into groups that should be read in one time.
85 Assume that revs are sorted.
85 Assume that revs are sorted.
86
86
87 The initial chunk is sliced until the overall density (payload/chunks-span
87 The initial chunk is sliced until the overall density (payload/chunks-span
88 ratio) is above `revlog._srdensitythreshold`. No gap smaller than
88 ratio) is above `revlog._srdensitythreshold`. No gap smaller than
89 `revlog._srmingapsize` is skipped.
89 `revlog._srmingapsize` is skipped.
90
90
91 If `targetsize` is set, no chunk larger than `targetsize` will be yield.
91 If `targetsize` is set, no chunk larger than `targetsize` will be yield.
92 For consistency with other slicing choice, this limit won't go lower than
92 For consistency with other slicing choice, this limit won't go lower than
93 `revlog._srmingapsize`.
93 `revlog._srmingapsize`.
94
94
95 If individual revisions chunk are larger than this limit, they will still
95 If individual revisions chunk are larger than this limit, they will still
96 be raised individually.
96 be raised individually.
97
97
98 >>> data = [
98 >>> data = [
99 ... 5, #00 (5)
99 ... 5, #00 (5)
100 ... 10, #01 (5)
100 ... 10, #01 (5)
101 ... 12, #02 (2)
101 ... 12, #02 (2)
102 ... 12, #03 (empty)
102 ... 12, #03 (empty)
103 ... 27, #04 (15)
103 ... 27, #04 (15)
104 ... 31, #05 (4)
104 ... 31, #05 (4)
105 ... 31, #06 (empty)
105 ... 31, #06 (empty)
106 ... 42, #07 (11)
106 ... 42, #07 (11)
107 ... 47, #08 (5)
107 ... 47, #08 (5)
108 ... 47, #09 (empty)
108 ... 47, #09 (empty)
109 ... 48, #10 (1)
109 ... 48, #10 (1)
110 ... 51, #11 (3)
110 ... 51, #11 (3)
111 ... 74, #12 (23)
111 ... 74, #12 (23)
112 ... 85, #13 (11)
112 ... 85, #13 (11)
113 ... 86, #14 (1)
113 ... 86, #14 (1)
114 ... 91, #15 (5)
114 ... 91, #15 (5)
115 ... ]
115 ... ]
116 >>> revlog = _testrevlog(data, snapshot=range(16))
116 >>> revlog = _testrevlog(data, snapshot=range(16))
117
117
118 >>> list(slicechunk(revlog, list(range(16))))
118 >>> list(slicechunk(revlog, list(range(16))))
119 [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
119 [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
120 >>> list(slicechunk(revlog, [0, 15]))
120 >>> list(slicechunk(revlog, [0, 15]))
121 [[0], [15]]
121 [[0], [15]]
122 >>> list(slicechunk(revlog, [0, 11, 15]))
122 >>> list(slicechunk(revlog, [0, 11, 15]))
123 [[0], [11], [15]]
123 [[0], [11], [15]]
124 >>> list(slicechunk(revlog, [0, 11, 13, 15]))
124 >>> list(slicechunk(revlog, [0, 11, 13, 15]))
125 [[0], [11, 13, 15]]
125 [[0], [11, 13, 15]]
126 >>> list(slicechunk(revlog, [1, 2, 3, 5, 8, 10, 11, 14]))
126 >>> list(slicechunk(revlog, [1, 2, 3, 5, 8, 10, 11, 14]))
127 [[1, 2], [5, 8, 10, 11], [14]]
127 [[1, 2], [5, 8, 10, 11], [14]]
128
128
129 Slicing with a maximum chunk size
129 Slicing with a maximum chunk size
130 >>> list(slicechunk(revlog, [0, 11, 13, 15], targetsize=15))
130 >>> list(slicechunk(revlog, [0, 11, 13, 15], targetsize=15))
131 [[0], [11], [13], [15]]
131 [[0], [11], [13], [15]]
132 >>> list(slicechunk(revlog, [0, 11, 13, 15], targetsize=20))
132 >>> list(slicechunk(revlog, [0, 11, 13, 15], targetsize=20))
133 [[0], [11], [13, 15]]
133 [[0], [11], [13, 15]]
134
134
135 Slicing involving nullrev
135 Slicing involving nullrev
136 >>> list(slicechunk(revlog, [-1, 0, 11, 13, 15], targetsize=20))
136 >>> list(slicechunk(revlog, [-1, 0, 11, 13, 15], targetsize=20))
137 [[-1, 0], [11], [13, 15]]
137 [[-1, 0], [11], [13, 15]]
138 >>> list(slicechunk(revlog, [-1, 13, 15], targetsize=5))
138 >>> list(slicechunk(revlog, [-1, 13, 15], targetsize=5))
139 [[-1], [13], [15]]
139 [[-1], [13], [15]]
140 """
140 """
141 if targetsize is not None:
141 if targetsize is not None:
142 targetsize = max(targetsize, revlog._srmingapsize)
142 targetsize = max(targetsize, revlog._srmingapsize)
143 # targetsize should not be specified when evaluating delta candidates:
143 # targetsize should not be specified when evaluating delta candidates:
144 # * targetsize is used to ensure we stay within specification when reading,
144 # * targetsize is used to ensure we stay within specification when reading,
145 densityslicing = getattr(revlog.index, 'slicechunktodensity', None)
145 densityslicing = getattr(revlog.index, 'slicechunktodensity', None)
146 if densityslicing is None:
146 if densityslicing is None:
147 densityslicing = lambda x, y, z: _slicechunktodensity(revlog, x, y, z)
147 densityslicing = lambda x, y, z: _slicechunktodensity(revlog, x, y, z)
148 for chunk in densityslicing(
148 for chunk in densityslicing(
149 revs, revlog._srdensitythreshold, revlog._srmingapsize
149 revs, revlog._srdensitythreshold, revlog._srmingapsize
150 ):
150 ):
151 for subchunk in _slicechunktosize(revlog, chunk, targetsize):
151 for subchunk in _slicechunktosize(revlog, chunk, targetsize):
152 yield subchunk
152 yield subchunk
153
153
154
154
155 def _slicechunktosize(revlog, revs, targetsize=None):
155 def _slicechunktosize(revlog, revs, targetsize=None):
156 """slice revs to match the target size
156 """slice revs to match the target size
157
157
158 This is intended to be used on chunk that density slicing selected by that
158 This is intended to be used on chunk that density slicing selected by that
159 are still too large compared to the read garantee of revlog. This might
159 are still too large compared to the read garantee of revlog. This might
160 happens when "minimal gap size" interrupted the slicing or when chain are
160 happens when "minimal gap size" interrupted the slicing or when chain are
161 built in a way that create large blocks next to each other.
161 built in a way that create large blocks next to each other.
162
162
163 >>> data = [
163 >>> data = [
164 ... 3, #0 (3)
164 ... 3, #0 (3)
165 ... 5, #1 (2)
165 ... 5, #1 (2)
166 ... 6, #2 (1)
166 ... 6, #2 (1)
167 ... 8, #3 (2)
167 ... 8, #3 (2)
168 ... 8, #4 (empty)
168 ... 8, #4 (empty)
169 ... 11, #5 (3)
169 ... 11, #5 (3)
170 ... 12, #6 (1)
170 ... 12, #6 (1)
171 ... 13, #7 (1)
171 ... 13, #7 (1)
172 ... 14, #8 (1)
172 ... 14, #8 (1)
173 ... ]
173 ... ]
174
174
175 == All snapshots cases ==
175 == All snapshots cases ==
176 >>> revlog = _testrevlog(data, snapshot=range(9))
176 >>> revlog = _testrevlog(data, snapshot=range(9))
177
177
178 Cases where chunk is already small enough
178 Cases where chunk is already small enough
179 >>> list(_slicechunktosize(revlog, [0], 3))
179 >>> list(_slicechunktosize(revlog, [0], 3))
180 [[0]]
180 [[0]]
181 >>> list(_slicechunktosize(revlog, [6, 7], 3))
181 >>> list(_slicechunktosize(revlog, [6, 7], 3))
182 [[6, 7]]
182 [[6, 7]]
183 >>> list(_slicechunktosize(revlog, [0], None))
183 >>> list(_slicechunktosize(revlog, [0], None))
184 [[0]]
184 [[0]]
185 >>> list(_slicechunktosize(revlog, [6, 7], None))
185 >>> list(_slicechunktosize(revlog, [6, 7], None))
186 [[6, 7]]
186 [[6, 7]]
187
187
188 cases where we need actual slicing
188 cases where we need actual slicing
189 >>> list(_slicechunktosize(revlog, [0, 1], 3))
189 >>> list(_slicechunktosize(revlog, [0, 1], 3))
190 [[0], [1]]
190 [[0], [1]]
191 >>> list(_slicechunktosize(revlog, [1, 3], 3))
191 >>> list(_slicechunktosize(revlog, [1, 3], 3))
192 [[1], [3]]
192 [[1], [3]]
193 >>> list(_slicechunktosize(revlog, [1, 2, 3], 3))
193 >>> list(_slicechunktosize(revlog, [1, 2, 3], 3))
194 [[1, 2], [3]]
194 [[1, 2], [3]]
195 >>> list(_slicechunktosize(revlog, [3, 5], 3))
195 >>> list(_slicechunktosize(revlog, [3, 5], 3))
196 [[3], [5]]
196 [[3], [5]]
197 >>> list(_slicechunktosize(revlog, [3, 4, 5], 3))
197 >>> list(_slicechunktosize(revlog, [3, 4, 5], 3))
198 [[3], [5]]
198 [[3], [5]]
199 >>> list(_slicechunktosize(revlog, [5, 6, 7, 8], 3))
199 >>> list(_slicechunktosize(revlog, [5, 6, 7, 8], 3))
200 [[5], [6, 7, 8]]
200 [[5], [6, 7, 8]]
201 >>> list(_slicechunktosize(revlog, [0, 1, 2, 3, 4, 5, 6, 7, 8], 3))
201 >>> list(_slicechunktosize(revlog, [0, 1, 2, 3, 4, 5, 6, 7, 8], 3))
202 [[0], [1, 2], [3], [5], [6, 7, 8]]
202 [[0], [1, 2], [3], [5], [6, 7, 8]]
203
203
204 Case with too large individual chunk (must return valid chunk)
204 Case with too large individual chunk (must return valid chunk)
205 >>> list(_slicechunktosize(revlog, [0, 1], 2))
205 >>> list(_slicechunktosize(revlog, [0, 1], 2))
206 [[0], [1]]
206 [[0], [1]]
207 >>> list(_slicechunktosize(revlog, [1, 3], 1))
207 >>> list(_slicechunktosize(revlog, [1, 3], 1))
208 [[1], [3]]
208 [[1], [3]]
209 >>> list(_slicechunktosize(revlog, [3, 4, 5], 2))
209 >>> list(_slicechunktosize(revlog, [3, 4, 5], 2))
210 [[3], [5]]
210 [[3], [5]]
211
211
212 == No Snapshot cases ==
212 == No Snapshot cases ==
213 >>> revlog = _testrevlog(data)
213 >>> revlog = _testrevlog(data)
214
214
215 Cases where chunk is already small enough
215 Cases where chunk is already small enough
216 >>> list(_slicechunktosize(revlog, [0], 3))
216 >>> list(_slicechunktosize(revlog, [0], 3))
217 [[0]]
217 [[0]]
218 >>> list(_slicechunktosize(revlog, [6, 7], 3))
218 >>> list(_slicechunktosize(revlog, [6, 7], 3))
219 [[6, 7]]
219 [[6, 7]]
220 >>> list(_slicechunktosize(revlog, [0], None))
220 >>> list(_slicechunktosize(revlog, [0], None))
221 [[0]]
221 [[0]]
222 >>> list(_slicechunktosize(revlog, [6, 7], None))
222 >>> list(_slicechunktosize(revlog, [6, 7], None))
223 [[6, 7]]
223 [[6, 7]]
224
224
225 cases where we need actual slicing
225 cases where we need actual slicing
226 >>> list(_slicechunktosize(revlog, [0, 1], 3))
226 >>> list(_slicechunktosize(revlog, [0, 1], 3))
227 [[0], [1]]
227 [[0], [1]]
228 >>> list(_slicechunktosize(revlog, [1, 3], 3))
228 >>> list(_slicechunktosize(revlog, [1, 3], 3))
229 [[1], [3]]
229 [[1], [3]]
230 >>> list(_slicechunktosize(revlog, [1, 2, 3], 3))
230 >>> list(_slicechunktosize(revlog, [1, 2, 3], 3))
231 [[1], [2, 3]]
231 [[1], [2, 3]]
232 >>> list(_slicechunktosize(revlog, [3, 5], 3))
232 >>> list(_slicechunktosize(revlog, [3, 5], 3))
233 [[3], [5]]
233 [[3], [5]]
234 >>> list(_slicechunktosize(revlog, [3, 4, 5], 3))
234 >>> list(_slicechunktosize(revlog, [3, 4, 5], 3))
235 [[3], [4, 5]]
235 [[3], [4, 5]]
236 >>> list(_slicechunktosize(revlog, [5, 6, 7, 8], 3))
236 >>> list(_slicechunktosize(revlog, [5, 6, 7, 8], 3))
237 [[5], [6, 7, 8]]
237 [[5], [6, 7, 8]]
238 >>> list(_slicechunktosize(revlog, [0, 1, 2, 3, 4, 5, 6, 7, 8], 3))
238 >>> list(_slicechunktosize(revlog, [0, 1, 2, 3, 4, 5, 6, 7, 8], 3))
239 [[0], [1, 2], [3], [5], [6, 7, 8]]
239 [[0], [1, 2], [3], [5], [6, 7, 8]]
240
240
241 Case with too large individual chunk (must return valid chunk)
241 Case with too large individual chunk (must return valid chunk)
242 >>> list(_slicechunktosize(revlog, [0, 1], 2))
242 >>> list(_slicechunktosize(revlog, [0, 1], 2))
243 [[0], [1]]
243 [[0], [1]]
244 >>> list(_slicechunktosize(revlog, [1, 3], 1))
244 >>> list(_slicechunktosize(revlog, [1, 3], 1))
245 [[1], [3]]
245 [[1], [3]]
246 >>> list(_slicechunktosize(revlog, [3, 4, 5], 2))
246 >>> list(_slicechunktosize(revlog, [3, 4, 5], 2))
247 [[3], [5]]
247 [[3], [5]]
248
248
249 == mixed case ==
249 == mixed case ==
250 >>> revlog = _testrevlog(data, snapshot=[0, 1, 2])
250 >>> revlog = _testrevlog(data, snapshot=[0, 1, 2])
251 >>> list(_slicechunktosize(revlog, list(range(9)), 5))
251 >>> list(_slicechunktosize(revlog, list(range(9)), 5))
252 [[0, 1], [2], [3, 4, 5], [6, 7, 8]]
252 [[0, 1], [2], [3, 4, 5], [6, 7, 8]]
253 """
253 """
254 assert targetsize is None or 0 <= targetsize
254 assert targetsize is None or 0 <= targetsize
255 startdata = revlog.start(revs[0])
255 startdata = revlog.start(revs[0])
256 enddata = revlog.end(revs[-1])
256 enddata = revlog.end(revs[-1])
257 fullspan = enddata - startdata
257 fullspan = enddata - startdata
258 if targetsize is None or fullspan <= targetsize:
258 if targetsize is None or fullspan <= targetsize:
259 yield revs
259 yield revs
260 return
260 return
261
261
262 startrevidx = 0
262 startrevidx = 0
263 endrevidx = 1
263 endrevidx = 1
264 iterrevs = enumerate(revs)
264 iterrevs = enumerate(revs)
265 next(iterrevs) # skip first rev.
265 next(iterrevs) # skip first rev.
266 # first step: get snapshots out of the way
266 # first step: get snapshots out of the way
267 for idx, r in iterrevs:
267 for idx, r in iterrevs:
268 span = revlog.end(r) - startdata
268 span = revlog.end(r) - startdata
269 snapshot = revlog.issnapshot(r)
269 snapshot = revlog.issnapshot(r)
270 if span <= targetsize and snapshot:
270 if span <= targetsize and snapshot:
271 endrevidx = idx + 1
271 endrevidx = idx + 1
272 else:
272 else:
273 chunk = _trimchunk(revlog, revs, startrevidx, endrevidx)
273 chunk = _trimchunk(revlog, revs, startrevidx, endrevidx)
274 if chunk:
274 if chunk:
275 yield chunk
275 yield chunk
276 startrevidx = idx
276 startrevidx = idx
277 startdata = revlog.start(r)
277 startdata = revlog.start(r)
278 endrevidx = idx + 1
278 endrevidx = idx + 1
279 if not snapshot:
279 if not snapshot:
280 break
280 break
281
281
282 # for the others, we use binary slicing to quickly converge toward valid
282 # for the others, we use binary slicing to quickly converge toward valid
283 # chunks (otherwise, we might end up looking for start/end of many
283 # chunks (otherwise, we might end up looking for start/end of many
284 # revisions). This logic is not looking for the perfect slicing point, it
284 # revisions). This logic is not looking for the perfect slicing point, it
285 # focuses on quickly converging toward valid chunks.
285 # focuses on quickly converging toward valid chunks.
286 nbitem = len(revs)
286 nbitem = len(revs)
287 while (enddata - startdata) > targetsize:
287 while (enddata - startdata) > targetsize:
288 endrevidx = nbitem
288 endrevidx = nbitem
289 if nbitem - startrevidx <= 1:
289 if nbitem - startrevidx <= 1:
290 break # protect against individual chunk larger than limit
290 break # protect against individual chunk larger than limit
291 localenddata = revlog.end(revs[endrevidx - 1])
291 localenddata = revlog.end(revs[endrevidx - 1])
292 span = localenddata - startdata
292 span = localenddata - startdata
293 while span > targetsize:
293 while span > targetsize:
294 if endrevidx - startrevidx <= 1:
294 if endrevidx - startrevidx <= 1:
295 break # protect against individual chunk larger than limit
295 break # protect against individual chunk larger than limit
296 endrevidx -= (endrevidx - startrevidx) // 2
296 endrevidx -= (endrevidx - startrevidx) // 2
297 localenddata = revlog.end(revs[endrevidx - 1])
297 localenddata = revlog.end(revs[endrevidx - 1])
298 span = localenddata - startdata
298 span = localenddata - startdata
299 chunk = _trimchunk(revlog, revs, startrevidx, endrevidx)
299 chunk = _trimchunk(revlog, revs, startrevidx, endrevidx)
300 if chunk:
300 if chunk:
301 yield chunk
301 yield chunk
302 startrevidx = endrevidx
302 startrevidx = endrevidx
303 startdata = revlog.start(revs[startrevidx])
303 startdata = revlog.start(revs[startrevidx])
304
304
305 chunk = _trimchunk(revlog, revs, startrevidx)
305 chunk = _trimchunk(revlog, revs, startrevidx)
306 if chunk:
306 if chunk:
307 yield chunk
307 yield chunk
308
308
309
309
310 def _slicechunktodensity(revlog, revs, targetdensity=0.5, mingapsize=0):
310 def _slicechunktodensity(revlog, revs, targetdensity=0.5, mingapsize=0):
311 """slice revs to reduce the amount of unrelated data to be read from disk.
311 """slice revs to reduce the amount of unrelated data to be read from disk.
312
312
313 ``revs`` is sliced into groups that should be read in one time.
313 ``revs`` is sliced into groups that should be read in one time.
314 Assume that revs are sorted.
314 Assume that revs are sorted.
315
315
316 The initial chunk is sliced until the overall density (payload/chunks-span
316 The initial chunk is sliced until the overall density (payload/chunks-span
317 ratio) is above `targetdensity`. No gap smaller than `mingapsize` is
317 ratio) is above `targetdensity`. No gap smaller than `mingapsize` is
318 skipped.
318 skipped.
319
319
320 >>> revlog = _testrevlog([
320 >>> revlog = _testrevlog([
321 ... 5, #00 (5)
321 ... 5, #00 (5)
322 ... 10, #01 (5)
322 ... 10, #01 (5)
323 ... 12, #02 (2)
323 ... 12, #02 (2)
324 ... 12, #03 (empty)
324 ... 12, #03 (empty)
325 ... 27, #04 (15)
325 ... 27, #04 (15)
326 ... 31, #05 (4)
326 ... 31, #05 (4)
327 ... 31, #06 (empty)
327 ... 31, #06 (empty)
328 ... 42, #07 (11)
328 ... 42, #07 (11)
329 ... 47, #08 (5)
329 ... 47, #08 (5)
330 ... 47, #09 (empty)
330 ... 47, #09 (empty)
331 ... 48, #10 (1)
331 ... 48, #10 (1)
332 ... 51, #11 (3)
332 ... 51, #11 (3)
333 ... 74, #12 (23)
333 ... 74, #12 (23)
334 ... 85, #13 (11)
334 ... 85, #13 (11)
335 ... 86, #14 (1)
335 ... 86, #14 (1)
336 ... 91, #15 (5)
336 ... 91, #15 (5)
337 ... ])
337 ... ])
338
338
339 >>> list(_slicechunktodensity(revlog, list(range(16))))
339 >>> list(_slicechunktodensity(revlog, list(range(16))))
340 [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
340 [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
341 >>> list(_slicechunktodensity(revlog, [0, 15]))
341 >>> list(_slicechunktodensity(revlog, [0, 15]))
342 [[0], [15]]
342 [[0], [15]]
343 >>> list(_slicechunktodensity(revlog, [0, 11, 15]))
343 >>> list(_slicechunktodensity(revlog, [0, 11, 15]))
344 [[0], [11], [15]]
344 [[0], [11], [15]]
345 >>> list(_slicechunktodensity(revlog, [0, 11, 13, 15]))
345 >>> list(_slicechunktodensity(revlog, [0, 11, 13, 15]))
346 [[0], [11, 13, 15]]
346 [[0], [11, 13, 15]]
347 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14]))
347 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14]))
348 [[1, 2], [5, 8, 10, 11], [14]]
348 [[1, 2], [5, 8, 10, 11], [14]]
349 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
349 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
350 ... mingapsize=20))
350 ... mingapsize=20))
351 [[1, 2, 3, 5, 8, 10, 11], [14]]
351 [[1, 2, 3, 5, 8, 10, 11], [14]]
352 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
352 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
353 ... targetdensity=0.95))
353 ... targetdensity=0.95))
354 [[1, 2], [5], [8, 10, 11], [14]]
354 [[1, 2], [5], [8, 10, 11], [14]]
355 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
355 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
356 ... targetdensity=0.95, mingapsize=12))
356 ... targetdensity=0.95, mingapsize=12))
357 [[1, 2], [5, 8, 10, 11], [14]]
357 [[1, 2], [5, 8, 10, 11], [14]]
358 """
358 """
359 start = revlog.start
359 start = revlog.start
360 length = revlog.length
360 length = revlog.length
361
361
362 if len(revs) <= 1:
362 if len(revs) <= 1:
363 yield revs
363 yield revs
364 return
364 return
365
365
366 deltachainspan = segmentspan(revlog, revs)
366 deltachainspan = segmentspan(revlog, revs)
367
367
368 if deltachainspan < mingapsize:
368 if deltachainspan < mingapsize:
369 yield revs
369 yield revs
370 return
370 return
371
371
372 readdata = deltachainspan
372 readdata = deltachainspan
373 chainpayload = sum(length(r) for r in revs)
373 chainpayload = sum(length(r) for r in revs)
374
374
375 if deltachainspan:
375 if deltachainspan:
376 density = chainpayload / float(deltachainspan)
376 density = chainpayload / float(deltachainspan)
377 else:
377 else:
378 density = 1.0
378 density = 1.0
379
379
380 if density >= targetdensity:
380 if density >= targetdensity:
381 yield revs
381 yield revs
382 return
382 return
383
383
384 # Store the gaps in a heap to have them sorted by decreasing size
384 # Store the gaps in a heap to have them sorted by decreasing size
385 gaps = []
385 gaps = []
386 prevend = None
386 prevend = None
387 for i, rev in enumerate(revs):
387 for i, rev in enumerate(revs):
388 revstart = start(rev)
388 revstart = start(rev)
389 revlen = length(rev)
389 revlen = length(rev)
390
390
391 # Skip empty revisions to form larger holes
391 # Skip empty revisions to form larger holes
392 if revlen == 0:
392 if revlen == 0:
393 continue
393 continue
394
394
395 if prevend is not None:
395 if prevend is not None:
396 gapsize = revstart - prevend
396 gapsize = revstart - prevend
397 # only consider holes that are large enough
397 # only consider holes that are large enough
398 if gapsize > mingapsize:
398 if gapsize > mingapsize:
399 gaps.append((gapsize, i))
399 gaps.append((gapsize, i))
400
400
401 prevend = revstart + revlen
401 prevend = revstart + revlen
402 # sort the gaps to pop them from largest to small
402 # sort the gaps to pop them from largest to small
403 gaps.sort()
403 gaps.sort()
404
404
405 # Collect the indices of the largest holes until the density is acceptable
405 # Collect the indices of the largest holes until the density is acceptable
406 selected = []
406 selected = []
407 while gaps and density < targetdensity:
407 while gaps and density < targetdensity:
408 gapsize, gapidx = gaps.pop()
408 gapsize, gapidx = gaps.pop()
409
409
410 selected.append(gapidx)
410 selected.append(gapidx)
411
411
412 # the gap sizes are stored as negatives to be sorted decreasingly
412 # the gap sizes are stored as negatives to be sorted decreasingly
413 # by the heap
413 # by the heap
414 readdata -= gapsize
414 readdata -= gapsize
415 if readdata > 0:
415 if readdata > 0:
416 density = chainpayload / float(readdata)
416 density = chainpayload / float(readdata)
417 else:
417 else:
418 density = 1.0
418 density = 1.0
419 selected.sort()
419 selected.sort()
420
420
421 # Cut the revs at collected indices
421 # Cut the revs at collected indices
422 previdx = 0
422 previdx = 0
423 for idx in selected:
423 for idx in selected:
424
424
425 chunk = _trimchunk(revlog, revs, previdx, idx)
425 chunk = _trimchunk(revlog, revs, previdx, idx)
426 if chunk:
426 if chunk:
427 yield chunk
427 yield chunk
428
428
429 previdx = idx
429 previdx = idx
430
430
431 chunk = _trimchunk(revlog, revs, previdx)
431 chunk = _trimchunk(revlog, revs, previdx)
432 if chunk:
432 if chunk:
433 yield chunk
433 yield chunk
434
434
435
435
436 def _trimchunk(revlog, revs, startidx, endidx=None):
436 def _trimchunk(revlog, revs, startidx, endidx=None):
437 """returns revs[startidx:endidx] without empty trailing revs
437 """returns revs[startidx:endidx] without empty trailing revs
438
438
439 Doctest Setup
439 Doctest Setup
440 >>> revlog = _testrevlog([
440 >>> revlog = _testrevlog([
441 ... 5, #0
441 ... 5, #0
442 ... 10, #1
442 ... 10, #1
443 ... 12, #2
443 ... 12, #2
444 ... 12, #3 (empty)
444 ... 12, #3 (empty)
445 ... 17, #4
445 ... 17, #4
446 ... 21, #5
446 ... 21, #5
447 ... 21, #6 (empty)
447 ... 21, #6 (empty)
448 ... ])
448 ... ])
449
449
450 Contiguous cases:
450 Contiguous cases:
451 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0)
451 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0)
452 [0, 1, 2, 3, 4, 5]
452 [0, 1, 2, 3, 4, 5]
453 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0, 5)
453 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0, 5)
454 [0, 1, 2, 3, 4]
454 [0, 1, 2, 3, 4]
455 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0, 4)
455 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0, 4)
456 [0, 1, 2]
456 [0, 1, 2]
457 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 2, 4)
457 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 2, 4)
458 [2]
458 [2]
459 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 3)
459 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 3)
460 [3, 4, 5]
460 [3, 4, 5]
461 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 3, 5)
461 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 3, 5)
462 [3, 4]
462 [3, 4]
463
463
464 Discontiguous cases:
464 Discontiguous cases:
465 >>> _trimchunk(revlog, [1, 3, 5, 6], 0)
465 >>> _trimchunk(revlog, [1, 3, 5, 6], 0)
466 [1, 3, 5]
466 [1, 3, 5]
467 >>> _trimchunk(revlog, [1, 3, 5, 6], 0, 2)
467 >>> _trimchunk(revlog, [1, 3, 5, 6], 0, 2)
468 [1]
468 [1]
469 >>> _trimchunk(revlog, [1, 3, 5, 6], 1, 3)
469 >>> _trimchunk(revlog, [1, 3, 5, 6], 1, 3)
470 [3, 5]
470 [3, 5]
471 >>> _trimchunk(revlog, [1, 3, 5, 6], 1)
471 >>> _trimchunk(revlog, [1, 3, 5, 6], 1)
472 [3, 5]
472 [3, 5]
473 """
473 """
474 length = revlog.length
474 length = revlog.length
475
475
476 if endidx is None:
476 if endidx is None:
477 endidx = len(revs)
477 endidx = len(revs)
478
478
479 # If we have a non-emtpy delta candidate, there are nothing to trim
479 # If we have a non-emtpy delta candidate, there are nothing to trim
480 if revs[endidx - 1] < len(revlog):
480 if revs[endidx - 1] < len(revlog):
481 # Trim empty revs at the end, except the very first revision of a chain
481 # Trim empty revs at the end, except the very first revision of a chain
482 while (
482 while (
483 endidx > 1 and endidx > startidx and length(revs[endidx - 1]) == 0
483 endidx > 1 and endidx > startidx and length(revs[endidx - 1]) == 0
484 ):
484 ):
485 endidx -= 1
485 endidx -= 1
486
486
487 return revs[startidx:endidx]
487 return revs[startidx:endidx]
488
488
489
489
490 def segmentspan(revlog, revs):
490 def segmentspan(revlog, revs):
491 """Get the byte span of a segment of revisions
491 """Get the byte span of a segment of revisions
492
492
493 revs is a sorted array of revision numbers
493 revs is a sorted array of revision numbers
494
494
495 >>> revlog = _testrevlog([
495 >>> revlog = _testrevlog([
496 ... 5, #0
496 ... 5, #0
497 ... 10, #1
497 ... 10, #1
498 ... 12, #2
498 ... 12, #2
499 ... 12, #3 (empty)
499 ... 12, #3 (empty)
500 ... 17, #4
500 ... 17, #4
501 ... ])
501 ... ])
502
502
503 >>> segmentspan(revlog, [0, 1, 2, 3, 4])
503 >>> segmentspan(revlog, [0, 1, 2, 3, 4])
504 17
504 17
505 >>> segmentspan(revlog, [0, 4])
505 >>> segmentspan(revlog, [0, 4])
506 17
506 17
507 >>> segmentspan(revlog, [3, 4])
507 >>> segmentspan(revlog, [3, 4])
508 5
508 5
509 >>> segmentspan(revlog, [1, 2, 3,])
509 >>> segmentspan(revlog, [1, 2, 3,])
510 7
510 7
511 >>> segmentspan(revlog, [1, 3])
511 >>> segmentspan(revlog, [1, 3])
512 7
512 7
513 """
513 """
514 if not revs:
514 if not revs:
515 return 0
515 return 0
516 end = revlog.end(revs[-1])
516 end = revlog.end(revs[-1])
517 return end - revlog.start(revs[0])
517 return end - revlog.start(revs[0])
518
518
519
519
520 def _textfromdelta(fh, revlog, baserev, delta, p1, p2, flags, expectednode):
520 def _textfromdelta(fh, revlog, baserev, delta, p1, p2, flags, expectednode):
521 """build full text from a (base, delta) pair and other metadata"""
521 """build full text from a (base, delta) pair and other metadata"""
522 # special case deltas which replace entire base; no need to decode
522 # special case deltas which replace entire base; no need to decode
523 # base revision. this neatly avoids censored bases, which throw when
523 # base revision. this neatly avoids censored bases, which throw when
524 # they're decoded.
524 # they're decoded.
525 hlen = struct.calcsize(b">lll")
525 hlen = struct.calcsize(b">lll")
526 if delta[:hlen] == mdiff.replacediffheader(
526 if delta[:hlen] == mdiff.replacediffheader(
527 revlog.rawsize(baserev), len(delta) - hlen
527 revlog.rawsize(baserev), len(delta) - hlen
528 ):
528 ):
529 fulltext = delta[hlen:]
529 fulltext = delta[hlen:]
530 else:
530 else:
531 # deltabase is rawtext before changed by flag processors, which is
531 # deltabase is rawtext before changed by flag processors, which is
532 # equivalent to non-raw text
532 # equivalent to non-raw text
533 basetext = revlog.revision(baserev, _df=fh)
533 basetext = revlog.revision(baserev, _df=fh)
534 fulltext = mdiff.patch(basetext, delta)
534 fulltext = mdiff.patch(basetext, delta)
535
535
536 try:
536 try:
537 validatehash = flagutil.processflagsraw(revlog, fulltext, flags)
537 validatehash = flagutil.processflagsraw(revlog, fulltext, flags)
538 if validatehash:
538 if validatehash:
539 revlog.checkhash(fulltext, expectednode, p1=p1, p2=p2)
539 revlog.checkhash(fulltext, expectednode, p1=p1, p2=p2)
540 if flags & REVIDX_ISCENSORED:
540 if flags & REVIDX_ISCENSORED:
541 raise error.StorageError(
541 raise error.StorageError(
542 _(b'node %s is not censored') % expectednode
542 _(b'node %s is not censored') % expectednode
543 )
543 )
544 except error.CensoredNodeError:
544 except error.CensoredNodeError:
545 # must pass the censored index flag to add censored revisions
545 # must pass the censored index flag to add censored revisions
546 if not flags & REVIDX_ISCENSORED:
546 if not flags & REVIDX_ISCENSORED:
547 raise
547 raise
548 return fulltext
548 return fulltext
549
549
550
550
551 @attr.s(slots=True, frozen=True)
551 @attr.s(slots=True, frozen=True)
552 class _deltainfo:
552 class _deltainfo:
553 distance = attr.ib()
553 distance = attr.ib()
554 deltalen = attr.ib()
554 deltalen = attr.ib()
555 data = attr.ib()
555 data = attr.ib()
556 base = attr.ib()
556 base = attr.ib()
557 chainbase = attr.ib()
557 chainbase = attr.ib()
558 chainlen = attr.ib()
558 chainlen = attr.ib()
559 compresseddeltalen = attr.ib()
559 compresseddeltalen = attr.ib()
560 snapshotdepth = attr.ib()
560 snapshotdepth = attr.ib()
561
561
562
562
563 def drop_u_compression(delta):
563 def drop_u_compression(delta):
564 """turn into a "u" (no-compression) into no-compression without header
564 """turn into a "u" (no-compression) into no-compression without header
565
565
566 This is useful for revlog format that has better compression method.
566 This is useful for revlog format that has better compression method.
567 """
567 """
568 assert delta.data[0] == b'u', delta.data[0]
568 assert delta.data[0] == b'u', delta.data[0]
569 return _deltainfo(
569 return _deltainfo(
570 delta.distance,
570 delta.distance,
571 delta.deltalen - 1,
571 delta.deltalen - 1,
572 (b'', delta.data[1]),
572 (b'', delta.data[1]),
573 delta.base,
573 delta.base,
574 delta.chainbase,
574 delta.chainbase,
575 delta.chainlen,
575 delta.chainlen,
576 delta.compresseddeltalen,
576 delta.compresseddeltalen,
577 delta.snapshotdepth,
577 delta.snapshotdepth,
578 )
578 )
579
579
580
580
581 def is_good_delta_info(revlog, deltainfo, revinfo):
581 def is_good_delta_info(revlog, deltainfo, revinfo):
582 """Returns True if the given delta is good. Good means that it is within
582 """Returns True if the given delta is good. Good means that it is within
583 the disk span, disk size, and chain length bounds that we know to be
583 the disk span, disk size, and chain length bounds that we know to be
584 performant."""
584 performant."""
585 if deltainfo is None:
585 if deltainfo is None:
586 return False
586 return False
587
587
588 if (
588 if (
589 revinfo.cachedelta is not None
589 revinfo.cachedelta is not None
590 and deltainfo.base == revinfo.cachedelta[0]
590 and deltainfo.base == revinfo.cachedelta[0]
591 and revinfo.cachedelta[2] == DELTA_BASE_REUSE_FORCE
591 and revinfo.cachedelta[2] == DELTA_BASE_REUSE_FORCE
592 ):
592 ):
593 return True
593 return True
594
594
595 # - 'deltainfo.distance' is the distance from the base revision --
595 # - 'deltainfo.distance' is the distance from the base revision --
596 # bounding it limits the amount of I/O we need to do.
596 # bounding it limits the amount of I/O we need to do.
597 # - 'deltainfo.compresseddeltalen' is the sum of the total size of
597 # - 'deltainfo.compresseddeltalen' is the sum of the total size of
598 # deltas we need to apply -- bounding it limits the amount of CPU
598 # deltas we need to apply -- bounding it limits the amount of CPU
599 # we consume.
599 # we consume.
600
600
601 textlen = revinfo.textlen
601 textlen = revinfo.textlen
602 defaultmax = textlen * 4
602 defaultmax = textlen * 4
603 maxdist = revlog._maxdeltachainspan
603 maxdist = revlog._maxdeltachainspan
604 if not maxdist:
604 if not maxdist:
605 maxdist = deltainfo.distance # ensure the conditional pass
605 maxdist = deltainfo.distance # ensure the conditional pass
606 maxdist = max(maxdist, defaultmax)
606 maxdist = max(maxdist, defaultmax)
607
607
608 # Bad delta from read span:
608 # Bad delta from read span:
609 #
609 #
610 # If the span of data read is larger than the maximum allowed.
610 # If the span of data read is larger than the maximum allowed.
611 #
611 #
612 # In the sparse-revlog case, we rely on the associated "sparse reading"
612 # In the sparse-revlog case, we rely on the associated "sparse reading"
613 # to avoid issue related to the span of data. In theory, it would be
613 # to avoid issue related to the span of data. In theory, it would be
614 # possible to build pathological revlog where delta pattern would lead
614 # possible to build pathological revlog where delta pattern would lead
615 # to too many reads. However, they do not happen in practice at all. So
615 # to too many reads. However, they do not happen in practice at all. So
616 # we skip the span check entirely.
616 # we skip the span check entirely.
617 if not revlog._sparserevlog and maxdist < deltainfo.distance:
617 if not revlog._sparserevlog and maxdist < deltainfo.distance:
618 return False
618 return False
619
619
620 # Bad delta from new delta size:
620 # Bad delta from new delta size:
621 #
621 #
622 # If the delta size is larger than the target text, storing the
622 # If the delta size is larger than the target text, storing the
623 # delta will be inefficient.
623 # delta will be inefficient.
624 if textlen < deltainfo.deltalen:
624 if textlen < deltainfo.deltalen:
625 return False
625 return False
626
626
627 # Bad delta from cumulated payload size:
627 # Bad delta from cumulated payload size:
628 #
628 #
629 # If the sum of delta get larger than K * target text length.
629 # If the sum of delta get larger than K * target text length.
630 if textlen * LIMIT_DELTA2TEXT < deltainfo.compresseddeltalen:
630 if textlen * LIMIT_DELTA2TEXT < deltainfo.compresseddeltalen:
631 return False
631 return False
632
632
633 # Bad delta from chain length:
633 # Bad delta from chain length:
634 #
634 #
635 # If the number of delta in the chain gets too high.
635 # If the number of delta in the chain gets too high.
636 if revlog._maxchainlen and revlog._maxchainlen < deltainfo.chainlen:
636 if revlog._maxchainlen and revlog._maxchainlen < deltainfo.chainlen:
637 return False
637 return False
638
638
639 # bad delta from intermediate snapshot size limit
639 # bad delta from intermediate snapshot size limit
640 #
640 #
641 # If an intermediate snapshot size is higher than the limit. The
641 # If an intermediate snapshot size is higher than the limit. The
642 # limit exist to prevent endless chain of intermediate delta to be
642 # limit exist to prevent endless chain of intermediate delta to be
643 # created.
643 # created.
644 if (
644 if (
645 deltainfo.snapshotdepth is not None
645 deltainfo.snapshotdepth is not None
646 and (textlen >> deltainfo.snapshotdepth) < deltainfo.deltalen
646 and (textlen >> deltainfo.snapshotdepth) < deltainfo.deltalen
647 ):
647 ):
648 return False
648 return False
649
649
650 # bad delta if new intermediate snapshot is larger than the previous
650 # bad delta if new intermediate snapshot is larger than the previous
651 # snapshot
651 # snapshot
652 if (
652 if (
653 deltainfo.snapshotdepth
653 deltainfo.snapshotdepth
654 and revlog.length(deltainfo.base) < deltainfo.deltalen
654 and revlog.length(deltainfo.base) < deltainfo.deltalen
655 ):
655 ):
656 return False
656 return False
657
657
658 return True
658 return True
659
659
660
660
661 # If a revision's full text is that much bigger than a base candidate full
661 # If a revision's full text is that much bigger than a base candidate full
662 # text's, it is very unlikely that it will produce a valid delta. We no longer
662 # text's, it is very unlikely that it will produce a valid delta. We no longer
663 # consider these candidates.
663 # consider these candidates.
664 LIMIT_BASE2TEXT = 500
664 LIMIT_BASE2TEXT = 500
665
665
666
666
667 def _candidategroups(
667 def _candidategroups(
668 revlog,
668 revlog,
669 textlen,
669 textlen,
670 p1,
670 p1,
671 p2,
671 p2,
672 cachedelta,
672 cachedelta,
673 excluded_bases=None,
673 excluded_bases=None,
674 target_rev=None,
674 target_rev=None,
675 snapshot_cache=None,
675 snapshot_cache=None,
676 ):
676 ):
677 """Provides group of revision to be tested as delta base
677 """Provides group of revision to be tested as delta base
678
678
679 This top level function focus on emitting groups with unique and worthwhile
679 This top level function focus on emitting groups with unique and worthwhile
680 content. See _raw_candidate_groups for details about the group order.
680 content. See _raw_candidate_groups for details about the group order.
681 """
681 """
682 # should we try to build a delta?
682 # should we try to build a delta?
683 if not (len(revlog) and revlog._storedeltachains):
683 if not (len(revlog) and revlog._storedeltachains):
684 yield None
684 yield None
685 return
685 return
686
686
687 if target_rev is None:
687 if target_rev is None:
688 target_rev = len(revlog)
688 target_rev = len(revlog)
689
689
690 if not revlog._generaldelta:
690 if not revlog._generaldelta:
691 # before general delta, there is only one possible delta base
691 # before general delta, there is only one possible delta base
692 yield (target_rev - 1,)
692 yield (target_rev - 1,)
693 yield None
693 yield None
694 return
694 return
695
695
696 if (
696 if (
697 cachedelta is not None
697 cachedelta is not None
698 and nullrev == cachedelta[0]
698 and nullrev == cachedelta[0]
699 and cachedelta[2] == DELTA_BASE_REUSE_FORCE
699 and cachedelta[2] == DELTA_BASE_REUSE_FORCE
700 ):
700 ):
701 # instruction are to forcibly do a full snapshot
701 # instruction are to forcibly do a full snapshot
702 yield None
702 yield None
703 return
703 return
704
704
705 deltalength = revlog.length
705 deltalength = revlog.length
706 deltaparent = revlog.deltaparent
706 deltaparent = revlog.deltaparent
707 sparse = revlog._sparserevlog
707 sparse = revlog._sparserevlog
708 good = None
708 good = None
709
709
710 deltas_limit = textlen * LIMIT_DELTA2TEXT
710 deltas_limit = textlen * LIMIT_DELTA2TEXT
711 group_chunk_size = revlog._candidate_group_chunk_size
711 group_chunk_size = revlog._candidate_group_chunk_size
712
712
713 tested = {nullrev}
713 tested = {nullrev}
714 candidates = _refinedgroups(
714 candidates = _refinedgroups(
715 revlog,
715 revlog,
716 p1,
716 p1,
717 p2,
717 p2,
718 cachedelta,
718 cachedelta,
719 snapshot_cache=snapshot_cache,
719 snapshot_cache=snapshot_cache,
720 )
720 )
721 while True:
721 while True:
722 temptative = candidates.send(good)
722 temptative = candidates.send(good)
723 if temptative is None:
723 if temptative is None:
724 break
724 break
725 group = []
725 group = []
726 for rev in temptative:
726 for rev in temptative:
727 # skip over empty delta (no need to include them in a chain)
727 # skip over empty delta (no need to include them in a chain)
728 while not (rev == nullrev or rev in tested or deltalength(rev)):
728 while not (rev == nullrev or rev in tested or deltalength(rev)):
729 tested.add(rev)
729 tested.add(rev)
730 rev = deltaparent(rev)
730 rev = deltaparent(rev)
731 # no need to try a delta against nullrev, this will be done as a
731 # no need to try a delta against nullrev, this will be done as a
732 # last resort.
732 # last resort.
733 if rev == nullrev:
733 if rev == nullrev:
734 continue
734 continue
735 # filter out revision we tested already
735 # filter out revision we tested already
736 if rev in tested:
736 if rev in tested:
737 continue
737 continue
738
738
739 if (
739 if (
740 cachedelta is not None
740 cachedelta is not None
741 and rev == cachedelta[0]
741 and rev == cachedelta[0]
742 and cachedelta[2] == DELTA_BASE_REUSE_FORCE
742 and cachedelta[2] == DELTA_BASE_REUSE_FORCE
743 ):
743 ):
744 # instructions are to forcibly consider/use this delta base
744 # instructions are to forcibly consider/use this delta base
745 group.append(rev)
745 group.append(rev)
746 continue
746 continue
747
747
748 # an higher authority deamed the base unworthy (e.g. censored)
748 # an higher authority deamed the base unworthy (e.g. censored)
749 if excluded_bases is not None and rev in excluded_bases:
749 if excluded_bases is not None and rev in excluded_bases:
750 tested.add(rev)
750 tested.add(rev)
751 continue
751 continue
752 # We are in some recomputation cases and that rev is too high in
752 # We are in some recomputation cases and that rev is too high in
753 # the revlog
753 # the revlog
754 if target_rev is not None and rev >= target_rev:
754 if target_rev is not None and rev >= target_rev:
755 tested.add(rev)
755 tested.add(rev)
756 continue
756 continue
757 # filter out delta base that will never produce good delta
757 # filter out delta base that will never produce good delta
758 if deltas_limit < revlog.length(rev):
758 if deltas_limit < revlog.length(rev):
759 tested.add(rev)
759 tested.add(rev)
760 continue
760 continue
761 if sparse and revlog.rawsize(rev) < (textlen // LIMIT_BASE2TEXT):
761 if sparse and revlog.rawsize(rev) < (textlen // LIMIT_BASE2TEXT):
762 tested.add(rev)
762 tested.add(rev)
763 continue
763 continue
764 # no delta for rawtext-changing revs (see "candelta" for why)
764 # no delta for rawtext-changing revs (see "candelta" for why)
765 if revlog.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS:
765 if revlog.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS:
766 tested.add(rev)
766 tested.add(rev)
767 continue
767 continue
768
768
769 # If we reach here, we are about to build and test a delta.
769 # If we reach here, we are about to build and test a delta.
770 # The delta building process will compute the chaininfo in all
770 # The delta building process will compute the chaininfo in all
771 # case, since that computation is cached, it is fine to access it
771 # case, since that computation is cached, it is fine to access it
772 # here too.
772 # here too.
773 chainlen, chainsize = revlog._chaininfo(rev)
773 chainlen, chainsize = revlog._chaininfo(rev)
774 # if chain will be too long, skip base
774 # if chain will be too long, skip base
775 if revlog._maxchainlen and chainlen >= revlog._maxchainlen:
775 if revlog._maxchainlen and chainlen >= revlog._maxchainlen:
776 tested.add(rev)
776 tested.add(rev)
777 continue
777 continue
778 # if chain already have too much data, skip base
778 # if chain already have too much data, skip base
779 if deltas_limit < chainsize:
779 if deltas_limit < chainsize:
780 tested.add(rev)
780 tested.add(rev)
781 continue
781 continue
782 if sparse and revlog.upperboundcomp is not None:
782 if sparse and revlog.upperboundcomp is not None:
783 maxcomp = revlog.upperboundcomp
783 maxcomp = revlog.upperboundcomp
784 basenotsnap = (p1, p2, nullrev)
784 basenotsnap = (p1, p2, nullrev)
785 if rev not in basenotsnap and revlog.issnapshot(rev):
785 if rev not in basenotsnap and revlog.issnapshot(rev):
786 snapshotdepth = revlog.snapshotdepth(rev)
786 snapshotdepth = revlog.snapshotdepth(rev)
787 # If text is significantly larger than the base, we can
787 # If text is significantly larger than the base, we can
788 # expect the resulting delta to be proportional to the size
788 # expect the resulting delta to be proportional to the size
789 # difference
789 # difference
790 revsize = revlog.rawsize(rev)
790 revsize = revlog.rawsize(rev)
791 rawsizedistance = max(textlen - revsize, 0)
791 rawsizedistance = max(textlen - revsize, 0)
792 # use an estimate of the compression upper bound.
792 # use an estimate of the compression upper bound.
793 lowestrealisticdeltalen = rawsizedistance // maxcomp
793 lowestrealisticdeltalen = rawsizedistance // maxcomp
794
794
795 # check the absolute constraint on the delta size
795 # check the absolute constraint on the delta size
796 snapshotlimit = textlen >> snapshotdepth
796 snapshotlimit = textlen >> snapshotdepth
797 if snapshotlimit < lowestrealisticdeltalen:
797 if snapshotlimit < lowestrealisticdeltalen:
798 # delta lower bound is larger than accepted upper bound
798 # delta lower bound is larger than accepted upper bound
799 tested.add(rev)
799 tested.add(rev)
800 continue
800 continue
801
801
802 # check the relative constraint on the delta size
802 # check the relative constraint on the delta size
803 revlength = revlog.length(rev)
803 revlength = revlog.length(rev)
804 if revlength < lowestrealisticdeltalen:
804 if revlength < lowestrealisticdeltalen:
805 # delta probable lower bound is larger than target base
805 # delta probable lower bound is larger than target base
806 tested.add(rev)
806 tested.add(rev)
807 continue
807 continue
808
808
809 group.append(rev)
809 group.append(rev)
810 if group:
810 if group:
811 # When the size of the candidate group is big, it can result in a
811 # When the size of the candidate group is big, it can result in a
812 # quite significant performance impact. To reduce this, we can send
812 # quite significant performance impact. To reduce this, we can send
813 # them in smaller batches until the new batch does not provide any
813 # them in smaller batches until the new batch does not provide any
814 # improvements.
814 # improvements.
815 #
815 #
816 # This might reduce the overall efficiency of the compression in
816 # This might reduce the overall efficiency of the compression in
817 # some corner cases, but that should also prevent very pathological
817 # some corner cases, but that should also prevent very pathological
818 # cases from being an issue. (eg. 20 000 candidates).
818 # cases from being an issue. (eg. 20 000 candidates).
819 #
819 #
820 # XXX note that the ordering of the group becomes important as it
820 # XXX note that the ordering of the group becomes important as it
821 # now impacts the final result. The current order is unprocessed
821 # now impacts the final result. The current order is unprocessed
822 # and can be improved.
822 # and can be improved.
823 if group_chunk_size == 0:
823 if group_chunk_size == 0:
824 tested.update(group)
824 tested.update(group)
825 good = yield tuple(group)
825 good = yield tuple(group)
826 else:
826 else:
827 prev_good = good
827 prev_good = good
828 for start in range(0, len(group), group_chunk_size):
828 for start in range(0, len(group), group_chunk_size):
829 sub_group = group[start : start + group_chunk_size]
829 sub_group = group[start : start + group_chunk_size]
830 tested.update(sub_group)
830 tested.update(sub_group)
831 good = yield tuple(sub_group)
831 good = yield tuple(sub_group)
832 if prev_good == good:
832 if prev_good == good:
833 break
833 break
834
834
835 yield None
835 yield None
836
836
837
837
838 def _refinedgroups(revlog, p1, p2, cachedelta, snapshot_cache=None):
838 def _refinedgroups(revlog, p1, p2, cachedelta, snapshot_cache=None):
839 good = None
839 good = None
840 # First we try to reuse a the delta contained in the bundle.
840 # First we try to reuse a the delta contained in the bundle.
841 # (or from the source revlog)
841 # (or from the source revlog)
842 #
842 #
843 # This logic only applies to general delta repositories and can be disabled
843 # This logic only applies to general delta repositories and can be disabled
844 # through configuration. Disabling reuse source delta is useful when
844 # through configuration. Disabling reuse source delta is useful when
845 # we want to make sure we recomputed "optimal" deltas.
845 # we want to make sure we recomputed "optimal" deltas.
846 debug_info = None
846 debug_info = None
847 if cachedelta is not None and cachedelta[2] > DELTA_BASE_REUSE_NO:
847 if cachedelta is not None and cachedelta[2] > DELTA_BASE_REUSE_NO:
848 # Assume what we received from the server is a good choice
848 # Assume what we received from the server is a good choice
849 # build delta will reuse the cache
849 # build delta will reuse the cache
850 if debug_info is not None:
850 if debug_info is not None:
851 debug_info['cached-delta.tested'] += 1
851 debug_info['cached-delta.tested'] += 1
852 good = yield (cachedelta[0],)
852 good = yield (cachedelta[0],)
853 if good is not None:
853 if good is not None:
854 if debug_info is not None:
854 if debug_info is not None:
855 debug_info['cached-delta.accepted'] += 1
855 debug_info['cached-delta.accepted'] += 1
856 yield None
856 yield None
857 return
857 return
858 if snapshot_cache is None:
858 if snapshot_cache is None:
859 snapshot_cache = SnapshotCache()
859 snapshot_cache = SnapshotCache()
860 groups = _rawgroups(
860 groups = _rawgroups(
861 revlog,
861 revlog,
862 p1,
862 p1,
863 p2,
863 p2,
864 cachedelta,
864 cachedelta,
865 snapshot_cache,
865 snapshot_cache,
866 )
866 )
867 for candidates in groups:
867 for candidates in groups:
868 good = yield candidates
868 good = yield candidates
869 if good is not None:
869 if good is not None:
870 break
870 break
871
871
872 # If sparse revlog is enabled, we can try to refine the available deltas
872 # If sparse revlog is enabled, we can try to refine the available deltas
873 if not revlog._sparserevlog:
873 if not revlog._sparserevlog:
874 yield None
874 yield None
875 return
875 return
876
876
877 # if we have a refinable value, try to refine it
877 # if we have a refinable value, try to refine it
878 if good is not None and good not in (p1, p2) and revlog.issnapshot(good):
878 if good is not None and good not in (p1, p2) and revlog.issnapshot(good):
879 # refine snapshot down
879 # refine snapshot down
880 previous = None
880 previous = None
881 while previous != good:
881 while previous != good:
882 previous = good
882 previous = good
883 base = revlog.deltaparent(good)
883 base = revlog.deltaparent(good)
884 if base == nullrev:
884 if base == nullrev:
885 break
885 break
886 good = yield (base,)
886 good = yield (base,)
887 # refine snapshot up
887 # refine snapshot up
888 if not snapshot_cache.snapshots:
888 if not snapshot_cache.snapshots:
889 snapshot_cache.update(revlog, good + 1)
889 snapshot_cache.update(revlog, good + 1)
890 previous = None
890 previous = None
891 while good != previous:
891 while good != previous:
892 previous = good
892 previous = good
893 children = tuple(sorted(c for c in snapshot_cache.snapshots[good]))
893 children = tuple(sorted(c for c in snapshot_cache.snapshots[good]))
894 good = yield children
894 good = yield children
895
895
896 if debug_info is not None:
896 if debug_info is not None:
897 if good is None:
897 if good is None:
898 debug_info['no-solution'] += 1
898 debug_info['no-solution'] += 1
899
899
900 yield None
900 yield None
901
901
902
902
903 def _rawgroups(revlog, p1, p2, cachedelta, snapshot_cache=None):
903 def _rawgroups(revlog, p1, p2, cachedelta, snapshot_cache=None):
904 """Provides group of revision to be tested as delta base
904 """Provides group of revision to be tested as delta base
905
905
906 This lower level function focus on emitting delta theorically interresting
906 This lower level function focus on emitting delta theorically interresting
907 without looking it any practical details.
907 without looking it any practical details.
908
908
909 The group order aims at providing fast or small candidates first.
909 The group order aims at providing fast or small candidates first.
910 """
910 """
911 # Why search for delta base if we cannot use a delta base ?
911 # Why search for delta base if we cannot use a delta base ?
912 assert revlog._generaldelta
912 assert revlog._generaldelta
913 # also see issue6056
913 # also see issue6056
914 sparse = revlog._sparserevlog
914 sparse = revlog._sparserevlog
915 curr = len(revlog)
915 curr = len(revlog)
916 prev = curr - 1
916 prev = curr - 1
917 deltachain = lambda rev: revlog._deltachain(rev)[0]
917 deltachain = lambda rev: revlog._deltachain(rev)[0]
918
918
919 # exclude already lazy tested base if any
919 # exclude already lazy tested base if any
920 parents = [p for p in (p1, p2) if p != nullrev]
920 parents = [p for p in (p1, p2) if p != nullrev]
921
921
922 if not revlog._deltabothparents and len(parents) == 2:
922 if not revlog._deltabothparents and len(parents) == 2:
923 parents.sort()
923 parents.sort()
924 # To minimize the chance of having to build a fulltext,
924 # To minimize the chance of having to build a fulltext,
925 # pick first whichever parent is closest to us (max rev)
925 # pick first whichever parent is closest to us (max rev)
926 yield (parents[1],)
926 yield (parents[1],)
927 # then the other one (min rev) if the first did not fit
927 # then the other one (min rev) if the first did not fit
928 yield (parents[0],)
928 yield (parents[0],)
929 elif len(parents) > 0:
929 elif len(parents) > 0:
930 # Test all parents (1 or 2), and keep the best candidate
930 # Test all parents (1 or 2), and keep the best candidate
931 yield parents
931 yield parents
932
932
933 if sparse and parents:
933 if sparse and parents:
934 if snapshot_cache is None:
934 if snapshot_cache is None:
935 # map: base-rev: [snapshot-revs]
935 # map: base-rev: [snapshot-revs]
936 snapshot_cache = SnapshotCache()
936 snapshot_cache = SnapshotCache()
937 # See if we can use an existing snapshot in the parent chains to use as
937 # See if we can use an existing snapshot in the parent chains to use as
938 # a base for a new intermediate-snapshot
938 # a base for a new intermediate-snapshot
939 #
939 #
940 # search for snapshot in parents delta chain
940 # search for snapshot in parents delta chain
941 # map: snapshot-level: snapshot-rev
941 # map: snapshot-level: snapshot-rev
942 parents_snaps = collections.defaultdict(set)
942 parents_snaps = collections.defaultdict(set)
943 candidate_chains = [deltachain(p) for p in parents]
943 candidate_chains = [deltachain(p) for p in parents]
944 for chain in candidate_chains:
944 for chain in candidate_chains:
945 for idx, s in enumerate(chain):
945 for idx, s in enumerate(chain):
946 if not revlog.issnapshot(s):
946 if not revlog.issnapshot(s):
947 break
947 break
948 parents_snaps[idx].add(s)
948 parents_snaps[idx].add(s)
949 snapfloor = min(parents_snaps[0]) + 1
949 snapfloor = min(parents_snaps[0]) + 1
950 snapshot_cache.update(revlog, snapfloor)
950 snapshot_cache.update(revlog, snapfloor)
951 # search for the highest "unrelated" revision
951 # search for the highest "unrelated" revision
952 #
952 #
953 # Adding snapshots used by "unrelated" revision increase the odd we
953 # Adding snapshots used by "unrelated" revision increase the odd we
954 # reuse an independant, yet better snapshot chain.
954 # reuse an independant, yet better snapshot chain.
955 #
955 #
956 # XXX instead of building a set of revisions, we could lazily enumerate
956 # XXX instead of building a set of revisions, we could lazily enumerate
957 # over the chains. That would be more efficient, however we stick to
957 # over the chains. That would be more efficient, however we stick to
958 # simple code for now.
958 # simple code for now.
959 all_revs = set()
959 all_revs = set()
960 for chain in candidate_chains:
960 for chain in candidate_chains:
961 all_revs.update(chain)
961 all_revs.update(chain)
962 other = None
962 other = None
963 for r in revlog.revs(prev, snapfloor):
963 for r in revlog.revs(prev, snapfloor):
964 if r not in all_revs:
964 if r not in all_revs:
965 other = r
965 other = r
966 break
966 break
967 if other is not None:
967 if other is not None:
968 # To avoid unfair competition, we won't use unrelated intermediate
968 # To avoid unfair competition, we won't use unrelated intermediate
969 # snapshot that are deeper than the ones from the parent delta
969 # snapshot that are deeper than the ones from the parent delta
970 # chain.
970 # chain.
971 max_depth = max(parents_snaps.keys())
971 max_depth = max(parents_snaps.keys())
972 chain = deltachain(other)
972 chain = deltachain(other)
973 for depth, s in enumerate(chain):
973 for depth, s in enumerate(chain):
974 if s < snapfloor:
974 if s < snapfloor:
975 continue
975 continue
976 if max_depth < depth:
976 if max_depth < depth:
977 break
977 break
978 if not revlog.issnapshot(s):
978 if not revlog.issnapshot(s):
979 break
979 break
980 parents_snaps[depth].add(s)
980 parents_snaps[depth].add(s)
981 # Test them as possible intermediate snapshot base
981 # Test them as possible intermediate snapshot base
982 # We test them from highest to lowest level. High level one are more
982 # We test them from highest to lowest level. High level one are more
983 # likely to result in small delta
983 # likely to result in small delta
984 floor = None
984 floor = None
985 for idx, snaps in sorted(parents_snaps.items(), reverse=True):
985 for idx, snaps in sorted(parents_snaps.items(), reverse=True):
986 siblings = set()
986 siblings = set()
987 for s in snaps:
987 for s in snaps:
988 siblings.update(snapshot_cache.snapshots[s])
988 siblings.update(snapshot_cache.snapshots[s])
989 # Before considering making a new intermediate snapshot, we check
989 # Before considering making a new intermediate snapshot, we check
990 # if an existing snapshot, children of base we consider, would be
990 # if an existing snapshot, children of base we consider, would be
991 # suitable.
991 # suitable.
992 #
992 #
993 # It give a change to reuse a delta chain "unrelated" to the
993 # It give a change to reuse a delta chain "unrelated" to the
994 # current revision instead of starting our own. Without such
994 # current revision instead of starting our own. Without such
995 # re-use, topological branches would keep reopening new chains.
995 # re-use, topological branches would keep reopening new chains.
996 # Creating more and more snapshot as the repository grow.
996 # Creating more and more snapshot as the repository grow.
997
997
998 if floor is not None:
998 if floor is not None:
999 # We only do this for siblings created after the one in our
999 # We only do this for siblings created after the one in our
1000 # parent's delta chain. Those created before has less chances
1000 # parent's delta chain. Those created before has less chances
1001 # to be valid base since our ancestors had to create a new
1001 # to be valid base since our ancestors had to create a new
1002 # snapshot.
1002 # snapshot.
1003 siblings = [r for r in siblings if floor < r]
1003 siblings = [r for r in siblings if floor < r]
1004 yield tuple(sorted(siblings))
1004 yield tuple(sorted(siblings))
1005 # then test the base from our parent's delta chain.
1005 # then test the base from our parent's delta chain.
1006 yield tuple(sorted(snaps))
1006 yield tuple(sorted(snaps))
1007 floor = min(snaps)
1007 floor = min(snaps)
1008 # No suitable base found in the parent chain, search if any full
1008 # No suitable base found in the parent chain, search if any full
1009 # snapshots emitted since parent's base would be a suitable base for an
1009 # snapshots emitted since parent's base would be a suitable base for an
1010 # intermediate snapshot.
1010 # intermediate snapshot.
1011 #
1011 #
1012 # It give a chance to reuse a delta chain unrelated to the current
1012 # It give a chance to reuse a delta chain unrelated to the current
1013 # revisions instead of starting our own. Without such re-use,
1013 # revisions instead of starting our own. Without such re-use,
1014 # topological branches would keep reopening new full chains. Creating
1014 # topological branches would keep reopening new full chains. Creating
1015 # more and more snapshot as the repository grow.
1015 # more and more snapshot as the repository grow.
1016 full = [r for r in snapshot_cache.snapshots[nullrev] if snapfloor <= r]
1016 full = [r for r in snapshot_cache.snapshots[nullrev] if snapfloor <= r]
1017 yield tuple(sorted(full))
1017 yield tuple(sorted(full))
1018
1018
1019 if not sparse:
1019 if not sparse:
1020 # other approach failed try against prev to hopefully save us a
1020 # other approach failed try against prev to hopefully save us a
1021 # fulltext.
1021 # fulltext.
1022 yield (prev,)
1022 yield (prev,)
1023
1023
1024
1024
1025 class SnapshotCache:
1025 class SnapshotCache:
1026 __slots__ = ('snapshots', '_start_rev', '_end_rev')
1026 __slots__ = ('snapshots', '_start_rev', '_end_rev')
1027
1027
1028 def __init__(self):
1028 def __init__(self):
1029 self.snapshots = collections.defaultdict(set)
1029 self.snapshots = collections.defaultdict(set)
1030 self._start_rev = None
1030 self._start_rev = None
1031 self._end_rev = None
1031 self._end_rev = None
1032
1032
1033 def update(self, revlog, start_rev=0):
1033 def update(self, revlog, start_rev=0):
1034 """find snapshots from start_rev to tip"""
1034 """find snapshots from start_rev to tip"""
1035 nb_revs = len(revlog)
1035 nb_revs = len(revlog)
1036 end_rev = nb_revs - 1
1036 end_rev = nb_revs - 1
1037 if start_rev > end_rev:
1037 if start_rev > end_rev:
1038 return # range is empty
1038 return # range is empty
1039
1039
1040 if self._start_rev is None:
1040 if self._start_rev is None:
1041 assert self._end_rev is None
1041 assert self._end_rev is None
1042 self._update(revlog, start_rev, end_rev)
1042 self._update(revlog, start_rev, end_rev)
1043 elif not (self._start_rev <= start_rev and end_rev <= self._end_rev):
1043 elif not (self._start_rev <= start_rev and end_rev <= self._end_rev):
1044 if start_rev < self._start_rev:
1044 if start_rev < self._start_rev:
1045 self._update(revlog, start_rev, self._start_rev - 1)
1045 self._update(revlog, start_rev, self._start_rev - 1)
1046 if self._end_rev < end_rev:
1046 if self._end_rev < end_rev:
1047 self._update(revlog, self._end_rev + 1, end_rev)
1047 self._update(revlog, self._end_rev + 1, end_rev)
1048
1048
1049 if self._start_rev is None:
1049 if self._start_rev is None:
1050 assert self._end_rev is None
1050 assert self._end_rev is None
1051 self._end_rev = end_rev
1051 self._end_rev = end_rev
1052 self._start_rev = start_rev
1052 self._start_rev = start_rev
1053 else:
1053 else:
1054 self._start_rev = min(self._start_rev, start_rev)
1054 self._start_rev = min(self._start_rev, start_rev)
1055 self._end_rev = max(self._end_rev, end_rev)
1055 self._end_rev = max(self._end_rev, end_rev)
1056 assert self._start_rev <= self._end_rev, (
1056 assert self._start_rev <= self._end_rev, (
1057 self._start_rev,
1057 self._start_rev,
1058 self._end_rev,
1058 self._end_rev,
1059 )
1059 )
1060
1060
1061 def _update(self, revlog, start_rev, end_rev):
1061 def _update(self, revlog, start_rev, end_rev):
1062 """internal method that actually do update content"""
1062 """internal method that actually do update content"""
1063 assert self._start_rev is None or (
1063 assert self._start_rev is None or (
1064 start_rev < self._start_rev or start_rev > self._end_rev
1064 start_rev < self._start_rev or start_rev > self._end_rev
1065 ), (self._start_rev, self._end_rev, start_rev, end_rev)
1065 ), (self._start_rev, self._end_rev, start_rev, end_rev)
1066 assert self._start_rev is None or (
1066 assert self._start_rev is None or (
1067 end_rev < self._start_rev or end_rev > self._end_rev
1067 end_rev < self._start_rev or end_rev > self._end_rev
1068 ), (self._start_rev, self._end_rev, start_rev, end_rev)
1068 ), (self._start_rev, self._end_rev, start_rev, end_rev)
1069 cache = self.snapshots
1069 cache = self.snapshots
1070 if util.safehasattr(revlog.index, 'findsnapshots'):
1070 if util.safehasattr(revlog.index, 'findsnapshots'):
1071 revlog.index.findsnapshots(cache, start_rev, end_rev)
1071 revlog.index.findsnapshots(cache, start_rev, end_rev)
1072 else:
1072 else:
1073 deltaparent = revlog.deltaparent
1073 deltaparent = revlog.deltaparent
1074 issnapshot = revlog.issnapshot
1074 issnapshot = revlog.issnapshot
1075 for rev in revlog.revs(start_rev, end_rev):
1075 for rev in revlog.revs(start_rev, end_rev):
1076 if issnapshot(rev):
1076 if issnapshot(rev):
1077 cache[deltaparent(rev)].add(rev)
1077 cache[deltaparent(rev)].add(rev)
1078
1078
1079
1079
1080 class deltacomputer:
1080 class deltacomputer:
1081 def __init__(
1081 def __init__(
1082 self,
1082 self,
1083 revlog,
1083 revlog,
1084 write_debug=None,
1084 write_debug=None,
1085 debug_search=False,
1085 debug_search=False,
1086 debug_info=None,
1086 debug_info=None,
1087 ):
1087 ):
1088 self.revlog = revlog
1088 self.revlog = revlog
1089 self._write_debug = write_debug
1089 self._write_debug = write_debug
1090 self._debug_search = debug_search
1090 if write_debug is None:
1091 self._debug_search = False
1092 else:
1093 self._debug_search = debug_search
1091 self._debug_info = debug_info
1094 self._debug_info = debug_info
1092 self._snapshot_cache = SnapshotCache()
1095 self._snapshot_cache = SnapshotCache()
1093
1096
1097 @property
1098 def _gather_debug(self):
1099 return self._write_debug is not None or self._debug_info is not None
1100
1094 def buildtext(self, revinfo, fh):
1101 def buildtext(self, revinfo, fh):
1095 """Builds a fulltext version of a revision
1102 """Builds a fulltext version of a revision
1096
1103
1097 revinfo: revisioninfo instance that contains all needed info
1104 revinfo: revisioninfo instance that contains all needed info
1098 fh: file handle to either the .i or the .d revlog file,
1105 fh: file handle to either the .i or the .d revlog file,
1099 depending on whether it is inlined or not
1106 depending on whether it is inlined or not
1100 """
1107 """
1101 btext = revinfo.btext
1108 btext = revinfo.btext
1102 if btext[0] is not None:
1109 if btext[0] is not None:
1103 return btext[0]
1110 return btext[0]
1104
1111
1105 revlog = self.revlog
1112 revlog = self.revlog
1106 cachedelta = revinfo.cachedelta
1113 cachedelta = revinfo.cachedelta
1107 baserev = cachedelta[0]
1114 baserev = cachedelta[0]
1108 delta = cachedelta[1]
1115 delta = cachedelta[1]
1109
1116
1110 fulltext = btext[0] = _textfromdelta(
1117 fulltext = btext[0] = _textfromdelta(
1111 fh,
1118 fh,
1112 revlog,
1119 revlog,
1113 baserev,
1120 baserev,
1114 delta,
1121 delta,
1115 revinfo.p1,
1122 revinfo.p1,
1116 revinfo.p2,
1123 revinfo.p2,
1117 revinfo.flags,
1124 revinfo.flags,
1118 revinfo.node,
1125 revinfo.node,
1119 )
1126 )
1120 return fulltext
1127 return fulltext
1121
1128
1122 def _builddeltadiff(self, base, revinfo, fh):
1129 def _builddeltadiff(self, base, revinfo, fh):
1123 revlog = self.revlog
1130 revlog = self.revlog
1124 t = self.buildtext(revinfo, fh)
1131 t = self.buildtext(revinfo, fh)
1125 if revlog.iscensored(base):
1132 if revlog.iscensored(base):
1126 # deltas based on a censored revision must replace the
1133 # deltas based on a censored revision must replace the
1127 # full content in one patch, so delta works everywhere
1134 # full content in one patch, so delta works everywhere
1128 header = mdiff.replacediffheader(revlog.rawsize(base), len(t))
1135 header = mdiff.replacediffheader(revlog.rawsize(base), len(t))
1129 delta = header + t
1136 delta = header + t
1130 else:
1137 else:
1131 ptext = revlog.rawdata(base, _df=fh)
1138 ptext = revlog.rawdata(base, _df=fh)
1132 delta = mdiff.textdiff(ptext, t)
1139 delta = mdiff.textdiff(ptext, t)
1133
1140
1134 return delta
1141 return delta
1135
1142
1136 def _builddeltainfo(self, revinfo, base, fh, target_rev=None):
1143 def _builddeltainfo(self, revinfo, base, fh, target_rev=None):
1137 # can we use the cached delta?
1144 # can we use the cached delta?
1138 revlog = self.revlog
1145 revlog = self.revlog
1139 debug_search = self._write_debug is not None and self._debug_search
1140 chainbase = revlog.chainbase(base)
1146 chainbase = revlog.chainbase(base)
1141 if revlog._generaldelta:
1147 if revlog._generaldelta:
1142 deltabase = base
1148 deltabase = base
1143 else:
1149 else:
1144 if target_rev is not None and base != target_rev - 1:
1150 if target_rev is not None and base != target_rev - 1:
1145 msg = (
1151 msg = (
1146 b'general delta cannot use delta for something else '
1152 b'general delta cannot use delta for something else '
1147 b'than `prev`: %d<-%d'
1153 b'than `prev`: %d<-%d'
1148 )
1154 )
1149 msg %= (base, target_rev)
1155 msg %= (base, target_rev)
1150 raise error.ProgrammingError(msg)
1156 raise error.ProgrammingError(msg)
1151 deltabase = chainbase
1157 deltabase = chainbase
1152 snapshotdepth = None
1158 snapshotdepth = None
1153 if revlog._sparserevlog and deltabase == nullrev:
1159 if revlog._sparserevlog and deltabase == nullrev:
1154 snapshotdepth = 0
1160 snapshotdepth = 0
1155 elif revlog._sparserevlog and revlog.issnapshot(deltabase):
1161 elif revlog._sparserevlog and revlog.issnapshot(deltabase):
1156 # A delta chain should always be one full snapshot,
1162 # A delta chain should always be one full snapshot,
1157 # zero or more semi-snapshots, and zero or more deltas
1163 # zero or more semi-snapshots, and zero or more deltas
1158 p1, p2 = revlog.rev(revinfo.p1), revlog.rev(revinfo.p2)
1164 p1, p2 = revlog.rev(revinfo.p1), revlog.rev(revinfo.p2)
1159 if deltabase not in (p1, p2) and revlog.issnapshot(deltabase):
1165 if deltabase not in (p1, p2) and revlog.issnapshot(deltabase):
1160 snapshotdepth = len(revlog._deltachain(deltabase)[0])
1166 snapshotdepth = len(revlog._deltachain(deltabase)[0])
1161 delta = None
1167 delta = None
1162 if revinfo.cachedelta:
1168 if revinfo.cachedelta:
1163 cachebase = revinfo.cachedelta[0]
1169 cachebase = revinfo.cachedelta[0]
1164 # check if the diff still apply
1170 # check if the diff still apply
1165 currentbase = cachebase
1171 currentbase = cachebase
1166 while (
1172 while (
1167 currentbase != nullrev
1173 currentbase != nullrev
1168 and currentbase != base
1174 and currentbase != base
1169 and self.revlog.length(currentbase) == 0
1175 and self.revlog.length(currentbase) == 0
1170 ):
1176 ):
1171 currentbase = self.revlog.deltaparent(currentbase)
1177 currentbase = self.revlog.deltaparent(currentbase)
1172 if self.revlog._lazydelta and currentbase == base:
1178 if self.revlog._lazydelta and currentbase == base:
1173 delta = revinfo.cachedelta[1]
1179 delta = revinfo.cachedelta[1]
1174 if delta is None:
1180 if delta is None:
1175 delta = self._builddeltadiff(base, revinfo, fh)
1181 delta = self._builddeltadiff(base, revinfo, fh)
1176 if debug_search:
1182 if self._debug_search:
1177 msg = b"DBG-DELTAS-SEARCH: uncompressed-delta-size=%d\n"
1183 msg = b"DBG-DELTAS-SEARCH: uncompressed-delta-size=%d\n"
1178 msg %= len(delta)
1184 msg %= len(delta)
1179 self._write_debug(msg)
1185 self._write_debug(msg)
1180 # snapshotdept need to be neither None nor 0 level snapshot
1186 # snapshotdept need to be neither None nor 0 level snapshot
1181 if revlog.upperboundcomp is not None and snapshotdepth:
1187 if revlog.upperboundcomp is not None and snapshotdepth:
1182 lowestrealisticdeltalen = len(delta) // revlog.upperboundcomp
1188 lowestrealisticdeltalen = len(delta) // revlog.upperboundcomp
1183 snapshotlimit = revinfo.textlen >> snapshotdepth
1189 snapshotlimit = revinfo.textlen >> snapshotdepth
1184 if debug_search:
1190 if self._debug_search:
1185 msg = b"DBG-DELTAS-SEARCH: projected-lower-size=%d\n"
1191 msg = b"DBG-DELTAS-SEARCH: projected-lower-size=%d\n"
1186 msg %= lowestrealisticdeltalen
1192 msg %= lowestrealisticdeltalen
1187 self._write_debug(msg)
1193 self._write_debug(msg)
1188 if snapshotlimit < lowestrealisticdeltalen:
1194 if snapshotlimit < lowestrealisticdeltalen:
1189 if debug_search:
1195 if self._debug_search:
1190 msg = b"DBG-DELTAS-SEARCH: DISCARDED (snapshot limit)\n"
1196 msg = b"DBG-DELTAS-SEARCH: DISCARDED (snapshot limit)\n"
1191 self._write_debug(msg)
1197 self._write_debug(msg)
1192 return None
1198 return None
1193 if revlog.length(base) < lowestrealisticdeltalen:
1199 if revlog.length(base) < lowestrealisticdeltalen:
1194 if debug_search:
1200 if self._debug_search:
1195 msg = b"DBG-DELTAS-SEARCH: DISCARDED (prev size)\n"
1201 msg = b"DBG-DELTAS-SEARCH: DISCARDED (prev size)\n"
1196 self._write_debug(msg)
1202 self._write_debug(msg)
1197 return None
1203 return None
1198 header, data = revlog.compress(delta)
1204 header, data = revlog.compress(delta)
1199 deltalen = len(header) + len(data)
1205 deltalen = len(header) + len(data)
1200 offset = revlog.end(len(revlog) - 1)
1206 offset = revlog.end(len(revlog) - 1)
1201 dist = deltalen + offset - revlog.start(chainbase)
1207 dist = deltalen + offset - revlog.start(chainbase)
1202 chainlen, compresseddeltalen = revlog._chaininfo(base)
1208 chainlen, compresseddeltalen = revlog._chaininfo(base)
1203 chainlen += 1
1209 chainlen += 1
1204 compresseddeltalen += deltalen
1210 compresseddeltalen += deltalen
1205
1211
1206 return _deltainfo(
1212 return _deltainfo(
1207 dist,
1213 dist,
1208 deltalen,
1214 deltalen,
1209 (header, data),
1215 (header, data),
1210 deltabase,
1216 deltabase,
1211 chainbase,
1217 chainbase,
1212 chainlen,
1218 chainlen,
1213 compresseddeltalen,
1219 compresseddeltalen,
1214 snapshotdepth,
1220 snapshotdepth,
1215 )
1221 )
1216
1222
1217 def _fullsnapshotinfo(self, fh, revinfo, curr):
1223 def _fullsnapshotinfo(self, fh, revinfo, curr):
1218 rawtext = self.buildtext(revinfo, fh)
1224 rawtext = self.buildtext(revinfo, fh)
1219 data = self.revlog.compress(rawtext)
1225 data = self.revlog.compress(rawtext)
1220 compresseddeltalen = deltalen = dist = len(data[1]) + len(data[0])
1226 compresseddeltalen = deltalen = dist = len(data[1]) + len(data[0])
1221 deltabase = chainbase = curr
1227 deltabase = chainbase = curr
1222 snapshotdepth = 0
1228 snapshotdepth = 0
1223 chainlen = 1
1229 chainlen = 1
1224
1230
1225 return _deltainfo(
1231 return _deltainfo(
1226 dist,
1232 dist,
1227 deltalen,
1233 deltalen,
1228 data,
1234 data,
1229 deltabase,
1235 deltabase,
1230 chainbase,
1236 chainbase,
1231 chainlen,
1237 chainlen,
1232 compresseddeltalen,
1238 compresseddeltalen,
1233 snapshotdepth,
1239 snapshotdepth,
1234 )
1240 )
1235
1241
1236 def finddeltainfo(self, revinfo, fh, excluded_bases=None, target_rev=None):
1242 def finddeltainfo(self, revinfo, fh, excluded_bases=None, target_rev=None):
1237 """Find an acceptable delta against a candidate revision
1243 """Find an acceptable delta against a candidate revision
1238
1244
1239 revinfo: information about the revision (instance of _revisioninfo)
1245 revinfo: information about the revision (instance of _revisioninfo)
1240 fh: file handle to either the .i or the .d revlog file,
1246 fh: file handle to either the .i or the .d revlog file,
1241 depending on whether it is inlined or not
1247 depending on whether it is inlined or not
1242
1248
1243 Returns the first acceptable candidate revision, as ordered by
1249 Returns the first acceptable candidate revision, as ordered by
1244 _candidategroups
1250 _candidategroups
1245
1251
1246 If no suitable deltabase is found, we return delta info for a full
1252 If no suitable deltabase is found, we return delta info for a full
1247 snapshot.
1253 snapshot.
1248
1254
1249 `excluded_bases` is an optional set of revision that cannot be used as
1255 `excluded_bases` is an optional set of revision that cannot be used as
1250 a delta base. Use this to recompute delta suitable in censor or strip
1256 a delta base. Use this to recompute delta suitable in censor or strip
1251 context.
1257 context.
1252 """
1258 """
1253 if target_rev is None:
1259 if target_rev is None:
1254 target_rev = len(self.revlog)
1260 target_rev = len(self.revlog)
1255
1261
1256 if not revinfo.textlen:
1262 gather_debug = self._gather_debug
1257 return self._fullsnapshotinfo(fh, revinfo, target_rev)
1263 cachedelta = revinfo.cachedelta
1264 revlog = self.revlog
1265 p1r = p2r = None
1258
1266
1259 if excluded_bases is None:
1267 if excluded_bases is None:
1260 excluded_bases = set()
1268 excluded_bases = set()
1261
1269
1262 # no delta for flag processor revision (see "candelta" for why)
1263 # not calling candelta since only one revision needs test, also to
1264 # avoid overhead fetching flags again.
1265 if revinfo.flags & REVIDX_RAWTEXT_CHANGING_FLAGS:
1266 return self._fullsnapshotinfo(fh, revinfo, target_rev)
1267
1268 gather_debug = (
1269 self._write_debug is not None or self._debug_info is not None
1270 )
1271 debug_search = self._write_debug is not None and self._debug_search
1272
1273 if gather_debug:
1270 if gather_debug:
1274 start = util.timer()
1271 start = util.timer()
1275
1272 dbg = self._one_dbg_data()
1276 # count the number of different delta we tried (for debug purpose)
1273 dbg['revision'] = target_rev
1277 dbg_try_count = 0
1274 target_revlog = b"UNKNOWN"
1278 # count the number of "search round" we did. (for debug purpose)
1275 target_type = self.revlog.target[0]
1279 dbg_try_rounds = 0
1276 target_key = self.revlog.target[1]
1280 dbg_type = b'unknown'
1277 if target_type == KIND_CHANGELOG:
1281
1278 target_revlog = b'CHANGELOG:'
1282 cachedelta = revinfo.cachedelta
1279 elif target_type == KIND_MANIFESTLOG:
1283 p1 = revinfo.p1
1280 target_revlog = b'MANIFESTLOG:'
1284 p2 = revinfo.p2
1281 if target_key:
1285 revlog = self.revlog
1282 target_revlog += b'%s:' % target_key
1286
1283 elif target_type == KIND_FILELOG:
1287 deltainfo = None
1284 target_revlog = b'FILELOG:'
1288 p1r, p2r = revlog.rev(p1), revlog.rev(p2)
1285 if target_key:
1289
1286 target_revlog += b'%s:' % target_key
1290 if gather_debug:
1287 dbg['target-revlog'] = target_revlog
1288 p1r = revlog.rev(revinfo.p1)
1289 p2r = revlog.rev(revinfo.p2)
1291 if p1r != nullrev:
1290 if p1r != nullrev:
1292 p1_chain_len = revlog._chaininfo(p1r)[0]
1291 p1_chain_len = revlog._chaininfo(p1r)[0]
1293 else:
1292 else:
1294 p1_chain_len = -1
1293 p1_chain_len = -1
1295 if p2r != nullrev:
1294 if p2r != nullrev:
1296 p2_chain_len = revlog._chaininfo(p2r)[0]
1295 p2_chain_len = revlog._chaininfo(p2r)[0]
1297 else:
1296 else:
1298 p2_chain_len = -1
1297 p2_chain_len = -1
1299 if debug_search:
1298 dbg['p1-chain-len'] = p1_chain_len
1299 dbg['p2-chain-len'] = p2_chain_len
1300
1301 # 1) if the revision is empty, no amount of delta can beat it
1302 #
1303 # 2) no delta for flag processor revision (see "candelta" for why)
1304 # not calling candelta since only one revision needs test, also to
1305 # avoid overhead fetching flags again.
1306 if not revinfo.textlen or revinfo.flags & REVIDX_RAWTEXT_CHANGING_FLAGS:
1307 deltainfo = self._fullsnapshotinfo(fh, revinfo, target_rev)
1308 if gather_debug:
1309 end = util.timer()
1310 dbg['duration'] = end - start
1311 dbg[
1312 'delta-base'
1313 ] = deltainfo.base # pytype: disable=attribute-error
1314 dbg['search_round_count'] = 0
1315 dbg['using-cached-base'] = False
1316 dbg['delta_try_count'] = 0
1317 dbg['type'] = b"full"
1318 dbg['snapshot-depth'] = 0
1319 self._dbg_process_data(dbg)
1320 return deltainfo
1321
1322 deltainfo = None
1323
1324 # If this source delta are to be forcibly reuse, let us comply early.
1325 if (
1326 revlog._generaldelta
1327 and revinfo.cachedelta is not None
1328 and revinfo.cachedelta[2] == DELTA_BASE_REUSE_FORCE
1329 ):
1330 base = revinfo.cachedelta[0]
1331 if base == nullrev:
1332 dbg_type = b"full"
1333 deltainfo = self._fullsnapshotinfo(fh, revinfo, target_rev)
1334 if gather_debug:
1335 snapshotdepth = 0
1336 elif base not in excluded_bases:
1337 delta = revinfo.cachedelta[1]
1338 header, data = revlog.compress(delta)
1339 deltalen = len(header) + len(data)
1340 if gather_debug:
1341 offset = revlog.end(len(revlog) - 1)
1342 chainbase = revlog.chainbase(base)
1343 distance = deltalen + offset - revlog.start(chainbase)
1344 chainlen, compresseddeltalen = revlog._chaininfo(base)
1345 chainlen += 1
1346 compresseddeltalen += deltalen
1347 if base == p1r or base == p2r:
1348 dbg_type = b"delta"
1349 snapshotdepth = None
1350 elif not revlog.issnapshot(base):
1351 snapshotdepth = None
1352 else:
1353 dbg_type = b"snapshot"
1354 snapshotdepth = revlog.snapshotdepth(base) + 1
1355 else:
1356 distance = None
1357 chainbase = None
1358 chainlen = None
1359 compresseddeltalen = None
1360 snapshotdepth = None
1361 deltainfo = _deltainfo(
1362 distance=distance,
1363 deltalen=deltalen,
1364 data=(header, data),
1365 base=base,
1366 chainbase=chainbase,
1367 chainlen=chainlen,
1368 compresseddeltalen=compresseddeltalen,
1369 snapshotdepth=snapshotdepth,
1370 )
1371
1372 if deltainfo is not None:
1373 if gather_debug:
1374 end = util.timer()
1375 dbg['duration'] = end - start
1376 dbg[
1377 'delta-base'
1378 ] = deltainfo.base # pytype: disable=attribute-error
1379 dbg['search_round_count'] = 0
1380 dbg['using-cached-base'] = True
1381 dbg['delta_try_count'] = 0
1382 dbg['type'] = b"full"
1383 if snapshotdepth is None:
1384 dbg['snapshot-depth'] = 0
1385 else:
1386 dbg['snapshot-depth'] = snapshotdepth
1387 self._dbg_process_data(dbg)
1388 return deltainfo
1389
1390 # count the number of different delta we tried (for debug purpose)
1391 dbg_try_count = 0
1392 # count the number of "search round" we did. (for debug purpose)
1393 dbg_try_rounds = 0
1394 dbg_type = b'unknown'
1395
1396 if p1r is None:
1397 p1r = revlog.rev(revinfo.p1)
1398 p2r = revlog.rev(revinfo.p2)
1399
1400 if self._debug_search:
1300 msg = b"DBG-DELTAS-SEARCH: SEARCH rev=%d\n"
1401 msg = b"DBG-DELTAS-SEARCH: SEARCH rev=%d\n"
1301 msg %= target_rev
1402 msg %= target_rev
1302 self._write_debug(msg)
1403 self._write_debug(msg)
1303
1404
1304 groups = _candidategroups(
1405 groups = _candidategroups(
1305 self.revlog,
1406 self.revlog,
1306 revinfo.textlen,
1407 revinfo.textlen,
1307 p1r,
1408 p1r,
1308 p2r,
1409 p2r,
1309 cachedelta,
1410 cachedelta,
1310 excluded_bases,
1411 excluded_bases,
1311 target_rev,
1412 target_rev,
1312 snapshot_cache=self._snapshot_cache,
1413 snapshot_cache=self._snapshot_cache,
1313 )
1414 )
1314 candidaterevs = next(groups)
1415 candidaterevs = next(groups)
1315 while candidaterevs is not None:
1416 while candidaterevs is not None:
1316 dbg_try_rounds += 1
1417 dbg_try_rounds += 1
1317 if debug_search:
1418 if self._debug_search:
1318 prev = None
1419 prev = None
1319 if deltainfo is not None:
1420 if deltainfo is not None:
1320 prev = deltainfo.base
1421 prev = deltainfo.base
1321
1422
1322 if (
1423 if (
1323 cachedelta is not None
1424 cachedelta is not None
1324 and len(candidaterevs) == 1
1425 and len(candidaterevs) == 1
1325 and cachedelta[0] in candidaterevs
1426 and cachedelta[0] in candidaterevs
1326 ):
1427 ):
1327 round_type = b"cached-delta"
1428 round_type = b"cached-delta"
1328 elif p1 in candidaterevs or p2 in candidaterevs:
1429 elif p1r in candidaterevs or p2r in candidaterevs:
1329 round_type = b"parents"
1430 round_type = b"parents"
1330 elif prev is not None and all(c < prev for c in candidaterevs):
1431 elif prev is not None and all(c < prev for c in candidaterevs):
1331 round_type = b"refine-down"
1432 round_type = b"refine-down"
1332 elif prev is not None and all(c > prev for c in candidaterevs):
1433 elif prev is not None and all(c > prev for c in candidaterevs):
1333 round_type = b"refine-up"
1434 round_type = b"refine-up"
1334 else:
1435 else:
1335 round_type = b"search-down"
1436 round_type = b"search-down"
1336 msg = b"DBG-DELTAS-SEARCH: ROUND #%d - %d candidates - %s\n"
1437 msg = b"DBG-DELTAS-SEARCH: ROUND #%d - %d candidates - %s\n"
1337 msg %= (dbg_try_rounds, len(candidaterevs), round_type)
1438 msg %= (dbg_try_rounds, len(candidaterevs), round_type)
1338 self._write_debug(msg)
1439 self._write_debug(msg)
1339 nominateddeltas = []
1440 nominateddeltas = []
1340 if deltainfo is not None:
1441 if deltainfo is not None:
1341 if debug_search:
1442 if self._debug_search:
1342 msg = (
1443 msg = (
1343 b"DBG-DELTAS-SEARCH: CONTENDER: rev=%d - length=%d\n"
1444 b"DBG-DELTAS-SEARCH: CONTENDER: rev=%d - length=%d\n"
1344 )
1445 )
1345 msg %= (deltainfo.base, deltainfo.deltalen)
1446 msg %= (deltainfo.base, deltainfo.deltalen)
1346 self._write_debug(msg)
1447 self._write_debug(msg)
1347 # if we already found a good delta,
1448 # if we already found a good delta,
1348 # challenge it against refined candidates
1449 # challenge it against refined candidates
1349 nominateddeltas.append(deltainfo)
1450 nominateddeltas.append(deltainfo)
1350 for candidaterev in candidaterevs:
1451 for candidaterev in candidaterevs:
1351 if debug_search:
1452 if self._debug_search:
1352 msg = b"DBG-DELTAS-SEARCH: CANDIDATE: rev=%d\n"
1453 msg = b"DBG-DELTAS-SEARCH: CANDIDATE: rev=%d\n"
1353 msg %= candidaterev
1454 msg %= candidaterev
1354 self._write_debug(msg)
1455 self._write_debug(msg)
1355 candidate_type = None
1456 candidate_type = None
1356 if candidaterev == p1:
1457 if candidaterev == p1r:
1357 candidate_type = b"p1"
1458 candidate_type = b"p1"
1358 elif candidaterev == p2:
1459 elif candidaterev == p2r:
1359 candidate_type = b"p2"
1460 candidate_type = b"p2"
1360 elif self.revlog.issnapshot(candidaterev):
1461 elif self.revlog.issnapshot(candidaterev):
1361 candidate_type = b"snapshot-%d"
1462 candidate_type = b"snapshot-%d"
1362 candidate_type %= self.revlog.snapshotdepth(
1463 candidate_type %= self.revlog.snapshotdepth(
1363 candidaterev
1464 candidaterev
1364 )
1465 )
1365
1466
1366 if candidate_type is not None:
1467 if candidate_type is not None:
1367 msg = b"DBG-DELTAS-SEARCH: type=%s\n"
1468 msg = b"DBG-DELTAS-SEARCH: type=%s\n"
1368 msg %= candidate_type
1469 msg %= candidate_type
1369 self._write_debug(msg)
1470 self._write_debug(msg)
1370 msg = b"DBG-DELTAS-SEARCH: size=%d\n"
1471 msg = b"DBG-DELTAS-SEARCH: size=%d\n"
1371 msg %= self.revlog.length(candidaterev)
1472 msg %= self.revlog.length(candidaterev)
1372 self._write_debug(msg)
1473 self._write_debug(msg)
1373 msg = b"DBG-DELTAS-SEARCH: base=%d\n"
1474 msg = b"DBG-DELTAS-SEARCH: base=%d\n"
1374 msg %= self.revlog.deltaparent(candidaterev)
1475 msg %= self.revlog.deltaparent(candidaterev)
1375 self._write_debug(msg)
1476 self._write_debug(msg)
1376
1477
1377 dbg_try_count += 1
1478 dbg_try_count += 1
1378
1479
1379 if debug_search:
1480 if self._debug_search:
1380 delta_start = util.timer()
1481 delta_start = util.timer()
1381 candidatedelta = self._builddeltainfo(
1482 candidatedelta = self._builddeltainfo(
1382 revinfo,
1483 revinfo,
1383 candidaterev,
1484 candidaterev,
1384 fh,
1485 fh,
1385 target_rev=target_rev,
1486 target_rev=target_rev,
1386 )
1487 )
1387 if debug_search:
1488 if self._debug_search:
1388 delta_end = util.timer()
1489 delta_end = util.timer()
1389 msg = b"DBG-DELTAS-SEARCH: delta-search-time=%f\n"
1490 msg = b"DBG-DELTAS-SEARCH: delta-search-time=%f\n"
1390 msg %= delta_end - delta_start
1491 msg %= delta_end - delta_start
1391 self._write_debug(msg)
1492 self._write_debug(msg)
1392 if candidatedelta is not None:
1493 if candidatedelta is not None:
1393 if is_good_delta_info(self.revlog, candidatedelta, revinfo):
1494 if is_good_delta_info(self.revlog, candidatedelta, revinfo):
1394 if debug_search:
1495 if self._debug_search:
1395 msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (GOOD)\n"
1496 msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (GOOD)\n"
1396 msg %= candidatedelta.deltalen
1497 msg %= candidatedelta.deltalen
1397 self._write_debug(msg)
1498 self._write_debug(msg)
1398 nominateddeltas.append(candidatedelta)
1499 nominateddeltas.append(candidatedelta)
1399 elif debug_search:
1500 elif self._debug_search:
1400 msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (BAD)\n"
1501 msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (BAD)\n"
1401 msg %= candidatedelta.deltalen
1502 msg %= candidatedelta.deltalen
1402 self._write_debug(msg)
1503 self._write_debug(msg)
1403 elif debug_search:
1504 elif self._debug_search:
1404 msg = b"DBG-DELTAS-SEARCH: NO-DELTA\n"
1505 msg = b"DBG-DELTAS-SEARCH: NO-DELTA\n"
1405 self._write_debug(msg)
1506 self._write_debug(msg)
1406 if nominateddeltas:
1507 if nominateddeltas:
1407 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen)
1508 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen)
1408 if deltainfo is not None:
1509 if deltainfo is not None:
1409 candidaterevs = groups.send(deltainfo.base)
1510 candidaterevs = groups.send(deltainfo.base)
1410 else:
1511 else:
1411 candidaterevs = next(groups)
1512 candidaterevs = next(groups)
1412
1513
1413 if deltainfo is None:
1514 if deltainfo is None:
1414 dbg_type = b"full"
1515 dbg_type = b"full"
1415 deltainfo = self._fullsnapshotinfo(fh, revinfo, target_rev)
1516 deltainfo = self._fullsnapshotinfo(fh, revinfo, target_rev)
1416 elif deltainfo.snapshotdepth: # pytype: disable=attribute-error
1517 elif deltainfo.snapshotdepth: # pytype: disable=attribute-error
1417 dbg_type = b"snapshot"
1518 dbg_type = b"snapshot"
1418 else:
1519 else:
1419 dbg_type = b"delta"
1520 dbg_type = b"delta"
1420
1521
1421 if gather_debug:
1522 if gather_debug:
1422 end = util.timer()
1523 end = util.timer()
1423 if dbg_type == b'full':
1524 if dbg_type == b'full':
1424 used_cached = (
1525 used_cached = (
1425 cachedelta is not None
1526 cachedelta is not None
1426 and dbg_try_rounds == 0
1527 and dbg_try_rounds == 0
1427 and dbg_try_count == 0
1528 and dbg_try_count == 0
1428 and cachedelta[0] == nullrev
1529 and cachedelta[0] == nullrev
1429 )
1530 )
1430 else:
1531 else:
1431 used_cached = (
1532 used_cached = (
1432 cachedelta is not None
1533 cachedelta is not None
1433 and dbg_try_rounds == 1
1534 and dbg_try_rounds == 1
1434 and dbg_try_count == 1
1535 and dbg_try_count == 1
1435 and deltainfo.base == cachedelta[0]
1536 and deltainfo.base == cachedelta[0]
1436 )
1537 )
1437 dbg = {
1538 dbg['duration'] = end - start
1438 'duration': end - start,
1539 dbg[
1439 'revision': target_rev,
1540 'delta-base'
1440 'delta-base': deltainfo.base, # pytype: disable=attribute-error
1541 ] = deltainfo.base # pytype: disable=attribute-error
1441 'search_round_count': dbg_try_rounds,
1542 dbg['search_round_count'] = dbg_try_rounds
1442 'using-cached-base': used_cached,
1543 dbg['using-cached-base'] = used_cached
1443 'delta_try_count': dbg_try_count,
1544 dbg['delta_try_count'] = dbg_try_count
1444 'type': dbg_type,
1545 dbg['type'] = dbg_type
1445 'p1-chain-len': p1_chain_len,
1446 'p2-chain-len': p2_chain_len,
1447 }
1448 if (
1546 if (
1449 deltainfo.snapshotdepth # pytype: disable=attribute-error
1547 deltainfo.snapshotdepth # pytype: disable=attribute-error
1450 is not None
1548 is not None
1451 ):
1549 ):
1452 dbg[
1550 dbg[
1453 'snapshot-depth'
1551 'snapshot-depth'
1454 ] = deltainfo.snapshotdepth # pytype: disable=attribute-error
1552 ] = deltainfo.snapshotdepth # pytype: disable=attribute-error
1455 else:
1553 else:
1456 dbg['snapshot-depth'] = 0
1554 dbg['snapshot-depth'] = 0
1457 target_revlog = b"UNKNOWN"
1555 self._dbg_process_data(dbg)
1458 target_type = self.revlog.target[0]
1556 return deltainfo
1459 target_key = self.revlog.target[1]
1460 if target_type == KIND_CHANGELOG:
1461 target_revlog = b'CHANGELOG:'
1462 elif target_type == KIND_MANIFESTLOG:
1463 target_revlog = b'MANIFESTLOG:'
1464 if target_key:
1465 target_revlog += b'%s:' % target_key
1466 elif target_type == KIND_FILELOG:
1467 target_revlog = b'FILELOG:'
1468 if target_key:
1469 target_revlog += b'%s:' % target_key
1470 dbg['target-revlog'] = target_revlog
1471
1557
1472 if self._debug_info is not None:
1558 def _one_dbg_data(self):
1473 self._debug_info.append(dbg)
1559 return {
1560 'duration': None,
1561 'revision': None,
1562 'delta-base': None,
1563 'search_round_count': None,
1564 'using-cached-base': None,
1565 'delta_try_count': None,
1566 'type': None,
1567 'p1-chain-len': None,
1568 'p2-chain-len': None,
1569 'snapshot-depth': None,
1570 'target-revlog': None,
1571 }
1572
1573 def _dbg_process_data(self, dbg):
1574 if self._debug_info is not None:
1575 self._debug_info.append(dbg)
1474
1576
1475 if self._write_debug is not None:
1577 if self._write_debug is not None:
1476 msg = (
1578 msg = (
1477 b"DBG-DELTAS:"
1579 b"DBG-DELTAS:"
1478 b" %-12s"
1580 b" %-12s"
1479 b" rev=%d:"
1581 b" rev=%d:"
1480 b" delta-base=%d"
1582 b" delta-base=%d"
1481 b" is-cached=%d"
1583 b" is-cached=%d"
1482 b" - search-rounds=%d"
1584 b" - search-rounds=%d"
1483 b" try-count=%d"
1585 b" try-count=%d"
1484 b" - delta-type=%-6s"
1586 b" - delta-type=%-6s"
1485 b" snap-depth=%d"
1587 b" snap-depth=%d"
1486 b" - p1-chain-length=%d"
1588 b" - p1-chain-length=%d"
1487 b" p2-chain-length=%d"
1589 b" p2-chain-length=%d"
1488 b" - duration=%f"
1590 b" - duration=%f"
1489 b"\n"
1591 b"\n"
1490 )
1592 )
1491 msg %= (
1593 msg %= (
1492 dbg["target-revlog"],
1594 dbg["target-revlog"],
1493 dbg["revision"],
1595 dbg["revision"],
1494 dbg["delta-base"],
1596 dbg["delta-base"],
1495 dbg["using-cached-base"],
1597 dbg["using-cached-base"],
1496 dbg["search_round_count"],
1598 dbg["search_round_count"],
1497 dbg["delta_try_count"],
1599 dbg["delta_try_count"],
1498 dbg["type"],
1600 dbg["type"],
1499 dbg["snapshot-depth"],
1601 dbg["snapshot-depth"],
1500 dbg["p1-chain-len"],
1602 dbg["p1-chain-len"],
1501 dbg["p2-chain-len"],
1603 dbg["p2-chain-len"],
1502 dbg["duration"],
1604 dbg["duration"],
1503 )
1605 )
1504 self._write_debug(msg)
1606 self._write_debug(msg)
1505 return deltainfo
1506
1607
1507
1608
1508 def delta_compression(default_compression_header, deltainfo):
1609 def delta_compression(default_compression_header, deltainfo):
1509 """return (COMPRESSION_MODE, deltainfo)
1610 """return (COMPRESSION_MODE, deltainfo)
1510
1611
1511 used by revlog v2+ format to dispatch between PLAIN and DEFAULT
1612 used by revlog v2+ format to dispatch between PLAIN and DEFAULT
1512 compression.
1613 compression.
1513 """
1614 """
1514 h, d = deltainfo.data
1615 h, d = deltainfo.data
1515 compression_mode = COMP_MODE_INLINE
1616 compression_mode = COMP_MODE_INLINE
1516 if not h and not d:
1617 if not h and not d:
1517 # not data to store at all... declare them uncompressed
1618 # not data to store at all... declare them uncompressed
1518 compression_mode = COMP_MODE_PLAIN
1619 compression_mode = COMP_MODE_PLAIN
1519 elif not h:
1620 elif not h:
1520 t = d[0:1]
1621 t = d[0:1]
1521 if t == b'\0':
1622 if t == b'\0':
1522 compression_mode = COMP_MODE_PLAIN
1623 compression_mode = COMP_MODE_PLAIN
1523 elif t == default_compression_header:
1624 elif t == default_compression_header:
1524 compression_mode = COMP_MODE_DEFAULT
1625 compression_mode = COMP_MODE_DEFAULT
1525 elif h == b'u':
1626 elif h == b'u':
1526 # we have a more efficient way to declare uncompressed
1627 # we have a more efficient way to declare uncompressed
1527 h = b''
1628 h = b''
1528 compression_mode = COMP_MODE_PLAIN
1629 compression_mode = COMP_MODE_PLAIN
1529 deltainfo = drop_u_compression(deltainfo)
1630 deltainfo = drop_u_compression(deltainfo)
1530 return compression_mode, deltainfo
1631 return compression_mode, deltainfo
@@ -1,919 +1,919 b''
1 # templatefuncs.py - common template functions
1 # templatefuncs.py - common template functions
2 #
2 #
3 # Copyright 2005, 2006 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005, 2006 Olivia Mackall <olivia@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
8
9 import binascii
9 import binascii
10 import re
10 import re
11
11
12 from .i18n import _
12 from .i18n import _
13 from .node import bin
13 from .node import bin
14 from . import (
14 from . import (
15 color,
15 color,
16 dagop,
16 dagop,
17 diffutil,
17 diffutil,
18 encoding,
18 encoding,
19 error,
19 error,
20 minirst,
20 minirst,
21 obsutil,
21 obsutil,
22 pycompat,
22 pycompat,
23 registrar,
23 registrar,
24 revset as revsetmod,
24 revset as revsetmod,
25 revsetlang,
25 revsetlang,
26 scmutil,
26 scmutil,
27 templatefilters,
27 templatefilters,
28 templatekw,
28 templatekw,
29 templateutil,
29 templateutil,
30 util,
30 util,
31 )
31 )
32 from .utils import (
32 from .utils import (
33 dateutil,
33 dateutil,
34 stringutil,
34 stringutil,
35 )
35 )
36
36
37 evalrawexp = templateutil.evalrawexp
37 evalrawexp = templateutil.evalrawexp
38 evalwrapped = templateutil.evalwrapped
38 evalwrapped = templateutil.evalwrapped
39 evalfuncarg = templateutil.evalfuncarg
39 evalfuncarg = templateutil.evalfuncarg
40 evalboolean = templateutil.evalboolean
40 evalboolean = templateutil.evalboolean
41 evaldate = templateutil.evaldate
41 evaldate = templateutil.evaldate
42 evalinteger = templateutil.evalinteger
42 evalinteger = templateutil.evalinteger
43 evalstring = templateutil.evalstring
43 evalstring = templateutil.evalstring
44 evalstringliteral = templateutil.evalstringliteral
44 evalstringliteral = templateutil.evalstringliteral
45
45
46 # dict of template built-in functions
46 # dict of template built-in functions
47 funcs = {}
47 funcs = {}
48 templatefunc = registrar.templatefunc(funcs)
48 templatefunc = registrar.templatefunc(funcs)
49
49
50
50
51 @templatefunc(b'date(date[, fmt])')
51 @templatefunc(b'date(date[, fmt])')
52 def date(context, mapping, args):
52 def date(context, mapping, args):
53 """Format a date. See :hg:`help dates` for formatting
53 """Format a date. The format string uses the Python strftime format.
54 strings. The default is a Unix date format, including the timezone:
54 The default is a Unix date format, including the timezone:
55 "Mon Sep 04 15:13:13 2006 0700"."""
55 "Mon Sep 04 15:13:13 2006 0700"."""
56 if not (1 <= len(args) <= 2):
56 if not (1 <= len(args) <= 2):
57 # i18n: "date" is a keyword
57 # i18n: "date" is a keyword
58 raise error.ParseError(_(b"date expects one or two arguments"))
58 raise error.ParseError(_(b"date expects one or two arguments"))
59
59
60 date = evaldate(
60 date = evaldate(
61 context,
61 context,
62 mapping,
62 mapping,
63 args[0],
63 args[0],
64 # i18n: "date" is a keyword
64 # i18n: "date" is a keyword
65 _(b"date expects a date information"),
65 _(b"date expects a date information"),
66 )
66 )
67 fmt = None
67 fmt = None
68 if len(args) == 2:
68 if len(args) == 2:
69 fmt = evalstring(context, mapping, args[1])
69 fmt = evalstring(context, mapping, args[1])
70 if fmt is None:
70 if fmt is None:
71 return dateutil.datestr(date)
71 return dateutil.datestr(date)
72 else:
72 else:
73 return dateutil.datestr(date, fmt)
73 return dateutil.datestr(date, fmt)
74
74
75
75
76 @templatefunc(b'dict([[key=]value...])', argspec=b'*args **kwargs')
76 @templatefunc(b'dict([[key=]value...])', argspec=b'*args **kwargs')
77 def dict_(context, mapping, args):
77 def dict_(context, mapping, args):
78 """Construct a dict from key-value pairs. A key may be omitted if
78 """Construct a dict from key-value pairs. A key may be omitted if
79 a value expression can provide an unambiguous name."""
79 a value expression can provide an unambiguous name."""
80 data = util.sortdict()
80 data = util.sortdict()
81
81
82 for v in args[b'args']:
82 for v in args[b'args']:
83 k = templateutil.findsymbolicname(v)
83 k = templateutil.findsymbolicname(v)
84 if not k:
84 if not k:
85 raise error.ParseError(_(b'dict key cannot be inferred'))
85 raise error.ParseError(_(b'dict key cannot be inferred'))
86 if k in data or k in args[b'kwargs']:
86 if k in data or k in args[b'kwargs']:
87 raise error.ParseError(_(b"duplicated dict key '%s' inferred") % k)
87 raise error.ParseError(_(b"duplicated dict key '%s' inferred") % k)
88 data[k] = evalfuncarg(context, mapping, v)
88 data[k] = evalfuncarg(context, mapping, v)
89
89
90 data.update(
90 data.update(
91 (k, evalfuncarg(context, mapping, v))
91 (k, evalfuncarg(context, mapping, v))
92 for k, v in args[b'kwargs'].items()
92 for k, v in args[b'kwargs'].items()
93 )
93 )
94 return templateutil.hybriddict(data)
94 return templateutil.hybriddict(data)
95
95
96
96
97 @templatefunc(
97 @templatefunc(
98 b'diff([includepattern [, excludepattern]])', requires={b'ctx', b'ui'}
98 b'diff([includepattern [, excludepattern]])', requires={b'ctx', b'ui'}
99 )
99 )
100 def diff(context, mapping, args):
100 def diff(context, mapping, args):
101 """Show a diff, optionally
101 """Show a diff, optionally
102 specifying files to include or exclude."""
102 specifying files to include or exclude."""
103 if len(args) > 2:
103 if len(args) > 2:
104 # i18n: "diff" is a keyword
104 # i18n: "diff" is a keyword
105 raise error.ParseError(_(b"diff expects zero, one, or two arguments"))
105 raise error.ParseError(_(b"diff expects zero, one, or two arguments"))
106
106
107 def getpatterns(i):
107 def getpatterns(i):
108 if i < len(args):
108 if i < len(args):
109 s = evalstring(context, mapping, args[i]).strip()
109 s = evalstring(context, mapping, args[i]).strip()
110 if s:
110 if s:
111 return [s]
111 return [s]
112 return []
112 return []
113
113
114 ctx = context.resource(mapping, b'ctx')
114 ctx = context.resource(mapping, b'ctx')
115 ui = context.resource(mapping, b'ui')
115 ui = context.resource(mapping, b'ui')
116 diffopts = diffutil.diffallopts(ui)
116 diffopts = diffutil.diffallopts(ui)
117 chunks = ctx.diff(
117 chunks = ctx.diff(
118 match=ctx.match([], getpatterns(0), getpatterns(1)), opts=diffopts
118 match=ctx.match([], getpatterns(0), getpatterns(1)), opts=diffopts
119 )
119 )
120
120
121 return b''.join(chunks)
121 return b''.join(chunks)
122
122
123
123
124 @templatefunc(
124 @templatefunc(
125 b'extdata(source)', argspec=b'source', requires={b'ctx', b'cache'}
125 b'extdata(source)', argspec=b'source', requires={b'ctx', b'cache'}
126 )
126 )
127 def extdata(context, mapping, args):
127 def extdata(context, mapping, args):
128 """Show a text read from the specified extdata source. (EXPERIMENTAL)"""
128 """Show a text read from the specified extdata source. (EXPERIMENTAL)"""
129 if b'source' not in args:
129 if b'source' not in args:
130 # i18n: "extdata" is a keyword
130 # i18n: "extdata" is a keyword
131 raise error.ParseError(_(b'extdata expects one argument'))
131 raise error.ParseError(_(b'extdata expects one argument'))
132
132
133 source = evalstring(context, mapping, args[b'source'])
133 source = evalstring(context, mapping, args[b'source'])
134 if not source:
134 if not source:
135 sym = templateutil.findsymbolicname(args[b'source'])
135 sym = templateutil.findsymbolicname(args[b'source'])
136 if sym:
136 if sym:
137 raise error.ParseError(
137 raise error.ParseError(
138 _(b'empty data source specified'),
138 _(b'empty data source specified'),
139 hint=_(b"did you mean extdata('%s')?") % sym,
139 hint=_(b"did you mean extdata('%s')?") % sym,
140 )
140 )
141 else:
141 else:
142 raise error.ParseError(_(b'empty data source specified'))
142 raise error.ParseError(_(b'empty data source specified'))
143 cache = context.resource(mapping, b'cache').setdefault(b'extdata', {})
143 cache = context.resource(mapping, b'cache').setdefault(b'extdata', {})
144 ctx = context.resource(mapping, b'ctx')
144 ctx = context.resource(mapping, b'ctx')
145 if source in cache:
145 if source in cache:
146 data = cache[source]
146 data = cache[source]
147 else:
147 else:
148 data = cache[source] = scmutil.extdatasource(ctx.repo(), source)
148 data = cache[source] = scmutil.extdatasource(ctx.repo(), source)
149 return data.get(ctx.rev(), b'')
149 return data.get(ctx.rev(), b'')
150
150
151
151
152 @templatefunc(b'files(pattern)', requires={b'ctx'})
152 @templatefunc(b'files(pattern)', requires={b'ctx'})
153 def files(context, mapping, args):
153 def files(context, mapping, args):
154 """All files of the current changeset matching the pattern. See
154 """All files of the current changeset matching the pattern. See
155 :hg:`help patterns`."""
155 :hg:`help patterns`."""
156 if not len(args) == 1:
156 if not len(args) == 1:
157 # i18n: "files" is a keyword
157 # i18n: "files" is a keyword
158 raise error.ParseError(_(b"files expects one argument"))
158 raise error.ParseError(_(b"files expects one argument"))
159
159
160 raw = evalstring(context, mapping, args[0])
160 raw = evalstring(context, mapping, args[0])
161 ctx = context.resource(mapping, b'ctx')
161 ctx = context.resource(mapping, b'ctx')
162 m = ctx.match([raw])
162 m = ctx.match([raw])
163 files = list(ctx.matches(m))
163 files = list(ctx.matches(m))
164 return templateutil.compatfileslist(context, mapping, b"file", files)
164 return templateutil.compatfileslist(context, mapping, b"file", files)
165
165
166
166
167 @templatefunc(b'fill(text[, width[, initialident[, hangindent]]])')
167 @templatefunc(b'fill(text[, width[, initialident[, hangindent]]])')
168 def fill(context, mapping, args):
168 def fill(context, mapping, args):
169 """Fill many
169 """Fill many
170 paragraphs with optional indentation. See the "fill" filter."""
170 paragraphs with optional indentation. See the "fill" filter."""
171 if not (1 <= len(args) <= 4):
171 if not (1 <= len(args) <= 4):
172 # i18n: "fill" is a keyword
172 # i18n: "fill" is a keyword
173 raise error.ParseError(_(b"fill expects one to four arguments"))
173 raise error.ParseError(_(b"fill expects one to four arguments"))
174
174
175 text = evalstring(context, mapping, args[0])
175 text = evalstring(context, mapping, args[0])
176 width = 76
176 width = 76
177 initindent = b''
177 initindent = b''
178 hangindent = b''
178 hangindent = b''
179 if 2 <= len(args) <= 4:
179 if 2 <= len(args) <= 4:
180 width = evalinteger(
180 width = evalinteger(
181 context,
181 context,
182 mapping,
182 mapping,
183 args[1],
183 args[1],
184 # i18n: "fill" is a keyword
184 # i18n: "fill" is a keyword
185 _(b"fill expects an integer width"),
185 _(b"fill expects an integer width"),
186 )
186 )
187 try:
187 try:
188 initindent = evalstring(context, mapping, args[2])
188 initindent = evalstring(context, mapping, args[2])
189 hangindent = evalstring(context, mapping, args[3])
189 hangindent = evalstring(context, mapping, args[3])
190 except IndexError:
190 except IndexError:
191 pass
191 pass
192
192
193 return templatefilters.fill(text, width, initindent, hangindent)
193 return templatefilters.fill(text, width, initindent, hangindent)
194
194
195
195
196 @templatefunc(b'filter(iterable[, expr])')
196 @templatefunc(b'filter(iterable[, expr])')
197 def filter_(context, mapping, args):
197 def filter_(context, mapping, args):
198 """Remove empty elements from a list or a dict. If expr specified, it's
198 """Remove empty elements from a list or a dict. If expr specified, it's
199 applied to each element to test emptiness."""
199 applied to each element to test emptiness."""
200 if not (1 <= len(args) <= 2):
200 if not (1 <= len(args) <= 2):
201 # i18n: "filter" is a keyword
201 # i18n: "filter" is a keyword
202 raise error.ParseError(_(b"filter expects one or two arguments"))
202 raise error.ParseError(_(b"filter expects one or two arguments"))
203 iterable = evalwrapped(context, mapping, args[0])
203 iterable = evalwrapped(context, mapping, args[0])
204 if len(args) == 1:
204 if len(args) == 1:
205
205
206 def select(w):
206 def select(w):
207 return w.tobool(context, mapping)
207 return w.tobool(context, mapping)
208
208
209 else:
209 else:
210
210
211 def select(w):
211 def select(w):
212 if not isinstance(w, templateutil.mappable):
212 if not isinstance(w, templateutil.mappable):
213 raise error.ParseError(_(b"not filterable by expression"))
213 raise error.ParseError(_(b"not filterable by expression"))
214 lm = context.overlaymap(mapping, w.tomap(context))
214 lm = context.overlaymap(mapping, w.tomap(context))
215 return evalboolean(context, lm, args[1])
215 return evalboolean(context, lm, args[1])
216
216
217 return iterable.filter(context, mapping, select)
217 return iterable.filter(context, mapping, select)
218
218
219
219
220 @templatefunc(b'formatnode(node)', requires={b'ui'})
220 @templatefunc(b'formatnode(node)', requires={b'ui'})
221 def formatnode(context, mapping, args):
221 def formatnode(context, mapping, args):
222 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
222 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
223 if len(args) != 1:
223 if len(args) != 1:
224 # i18n: "formatnode" is a keyword
224 # i18n: "formatnode" is a keyword
225 raise error.ParseError(_(b"formatnode expects one argument"))
225 raise error.ParseError(_(b"formatnode expects one argument"))
226
226
227 ui = context.resource(mapping, b'ui')
227 ui = context.resource(mapping, b'ui')
228 node = evalstring(context, mapping, args[0])
228 node = evalstring(context, mapping, args[0])
229 if ui.debugflag:
229 if ui.debugflag:
230 return node
230 return node
231 return templatefilters.short(node)
231 return templatefilters.short(node)
232
232
233
233
234 @templatefunc(b'mailmap(author)', requires={b'repo', b'cache'})
234 @templatefunc(b'mailmap(author)', requires={b'repo', b'cache'})
235 def mailmap(context, mapping, args):
235 def mailmap(context, mapping, args):
236 """Return the author, updated according to the value
236 """Return the author, updated according to the value
237 set in the .mailmap file"""
237 set in the .mailmap file"""
238 if len(args) != 1:
238 if len(args) != 1:
239 raise error.ParseError(_(b"mailmap expects one argument"))
239 raise error.ParseError(_(b"mailmap expects one argument"))
240
240
241 author = evalstring(context, mapping, args[0])
241 author = evalstring(context, mapping, args[0])
242
242
243 cache = context.resource(mapping, b'cache')
243 cache = context.resource(mapping, b'cache')
244 repo = context.resource(mapping, b'repo')
244 repo = context.resource(mapping, b'repo')
245
245
246 if b'mailmap' not in cache:
246 if b'mailmap' not in cache:
247 data = repo.wvfs.tryread(b'.mailmap')
247 data = repo.wvfs.tryread(b'.mailmap')
248 cache[b'mailmap'] = stringutil.parsemailmap(data)
248 cache[b'mailmap'] = stringutil.parsemailmap(data)
249
249
250 return stringutil.mapname(cache[b'mailmap'], author)
250 return stringutil.mapname(cache[b'mailmap'], author)
251
251
252
252
253 @templatefunc(
253 @templatefunc(
254 b'pad(text, width[, fillchar=\' \'[, left=False[, truncate=False]]])',
254 b'pad(text, width[, fillchar=\' \'[, left=False[, truncate=False]]])',
255 argspec=b'text width fillchar left truncate',
255 argspec=b'text width fillchar left truncate',
256 )
256 )
257 def pad(context, mapping, args):
257 def pad(context, mapping, args):
258 """Pad text with a
258 """Pad text with a
259 fill character."""
259 fill character."""
260 if b'text' not in args or b'width' not in args:
260 if b'text' not in args or b'width' not in args:
261 # i18n: "pad" is a keyword
261 # i18n: "pad" is a keyword
262 raise error.ParseError(_(b"pad() expects two to four arguments"))
262 raise error.ParseError(_(b"pad() expects two to four arguments"))
263
263
264 width = evalinteger(
264 width = evalinteger(
265 context,
265 context,
266 mapping,
266 mapping,
267 args[b'width'],
267 args[b'width'],
268 # i18n: "pad" is a keyword
268 # i18n: "pad" is a keyword
269 _(b"pad() expects an integer width"),
269 _(b"pad() expects an integer width"),
270 )
270 )
271
271
272 text = evalstring(context, mapping, args[b'text'])
272 text = evalstring(context, mapping, args[b'text'])
273
273
274 truncate = False
274 truncate = False
275 left = False
275 left = False
276 fillchar = b' '
276 fillchar = b' '
277 if b'fillchar' in args:
277 if b'fillchar' in args:
278 fillchar = evalstring(context, mapping, args[b'fillchar'])
278 fillchar = evalstring(context, mapping, args[b'fillchar'])
279 if len(color.stripeffects(fillchar)) != 1:
279 if len(color.stripeffects(fillchar)) != 1:
280 # i18n: "pad" is a keyword
280 # i18n: "pad" is a keyword
281 raise error.ParseError(_(b"pad() expects a single fill character"))
281 raise error.ParseError(_(b"pad() expects a single fill character"))
282 if b'left' in args:
282 if b'left' in args:
283 left = evalboolean(context, mapping, args[b'left'])
283 left = evalboolean(context, mapping, args[b'left'])
284 if b'truncate' in args:
284 if b'truncate' in args:
285 truncate = evalboolean(context, mapping, args[b'truncate'])
285 truncate = evalboolean(context, mapping, args[b'truncate'])
286
286
287 fillwidth = width - encoding.colwidth(color.stripeffects(text))
287 fillwidth = width - encoding.colwidth(color.stripeffects(text))
288 if fillwidth < 0 and truncate:
288 if fillwidth < 0 and truncate:
289 return encoding.trim(color.stripeffects(text), width, leftside=left)
289 return encoding.trim(color.stripeffects(text), width, leftside=left)
290 if fillwidth <= 0:
290 if fillwidth <= 0:
291 return text
291 return text
292 if left:
292 if left:
293 return fillchar * fillwidth + text
293 return fillchar * fillwidth + text
294 else:
294 else:
295 return text + fillchar * fillwidth
295 return text + fillchar * fillwidth
296
296
297
297
298 @templatefunc(b'indent(text, indentchars[, firstline])')
298 @templatefunc(b'indent(text, indentchars[, firstline])')
299 def indent(context, mapping, args):
299 def indent(context, mapping, args):
300 """Indents all non-empty lines
300 """Indents all non-empty lines
301 with the characters given in the indentchars string. An optional
301 with the characters given in the indentchars string. An optional
302 third parameter will override the indent for the first line only
302 third parameter will override the indent for the first line only
303 if present."""
303 if present."""
304 if not (2 <= len(args) <= 3):
304 if not (2 <= len(args) <= 3):
305 # i18n: "indent" is a keyword
305 # i18n: "indent" is a keyword
306 raise error.ParseError(_(b"indent() expects two or three arguments"))
306 raise error.ParseError(_(b"indent() expects two or three arguments"))
307
307
308 text = evalstring(context, mapping, args[0])
308 text = evalstring(context, mapping, args[0])
309 indent = evalstring(context, mapping, args[1])
309 indent = evalstring(context, mapping, args[1])
310
310
311 firstline = indent
311 firstline = indent
312 if len(args) == 3:
312 if len(args) == 3:
313 firstline = evalstring(context, mapping, args[2])
313 firstline = evalstring(context, mapping, args[2])
314
314
315 return templatefilters.indent(text, indent, firstline=firstline)
315 return templatefilters.indent(text, indent, firstline=firstline)
316
316
317
317
318 @templatefunc(b'get(dict, key)')
318 @templatefunc(b'get(dict, key)')
319 def get(context, mapping, args):
319 def get(context, mapping, args):
320 """Get an attribute/key from an object. Some keywords
320 """Get an attribute/key from an object. Some keywords
321 are complex types. This function allows you to obtain the value of an
321 are complex types. This function allows you to obtain the value of an
322 attribute on these types."""
322 attribute on these types."""
323 if len(args) != 2:
323 if len(args) != 2:
324 # i18n: "get" is a keyword
324 # i18n: "get" is a keyword
325 raise error.ParseError(_(b"get() expects two arguments"))
325 raise error.ParseError(_(b"get() expects two arguments"))
326
326
327 dictarg = evalwrapped(context, mapping, args[0])
327 dictarg = evalwrapped(context, mapping, args[0])
328 key = evalrawexp(context, mapping, args[1])
328 key = evalrawexp(context, mapping, args[1])
329 try:
329 try:
330 return dictarg.getmember(context, mapping, key)
330 return dictarg.getmember(context, mapping, key)
331 except error.ParseError as err:
331 except error.ParseError as err:
332 # i18n: "get" is a keyword
332 # i18n: "get" is a keyword
333 hint = _(b"get() expects a dict as first argument")
333 hint = _(b"get() expects a dict as first argument")
334 raise error.ParseError(bytes(err), hint=hint)
334 raise error.ParseError(bytes(err), hint=hint)
335
335
336
336
337 @templatefunc(b'config(section, name[, default])', requires={b'ui'})
337 @templatefunc(b'config(section, name[, default])', requires={b'ui'})
338 def config(context, mapping, args):
338 def config(context, mapping, args):
339 """Returns the requested hgrc config option as a string."""
339 """Returns the requested hgrc config option as a string."""
340 fn = context.resource(mapping, b'ui').config
340 fn = context.resource(mapping, b'ui').config
341 return _config(context, mapping, args, fn, evalstring)
341 return _config(context, mapping, args, fn, evalstring)
342
342
343
343
344 @templatefunc(b'configbool(section, name[, default])', requires={b'ui'})
344 @templatefunc(b'configbool(section, name[, default])', requires={b'ui'})
345 def configbool(context, mapping, args):
345 def configbool(context, mapping, args):
346 """Returns the requested hgrc config option as a boolean."""
346 """Returns the requested hgrc config option as a boolean."""
347 fn = context.resource(mapping, b'ui').configbool
347 fn = context.resource(mapping, b'ui').configbool
348 return _config(context, mapping, args, fn, evalboolean)
348 return _config(context, mapping, args, fn, evalboolean)
349
349
350
350
351 @templatefunc(b'configint(section, name[, default])', requires={b'ui'})
351 @templatefunc(b'configint(section, name[, default])', requires={b'ui'})
352 def configint(context, mapping, args):
352 def configint(context, mapping, args):
353 """Returns the requested hgrc config option as an integer."""
353 """Returns the requested hgrc config option as an integer."""
354 fn = context.resource(mapping, b'ui').configint
354 fn = context.resource(mapping, b'ui').configint
355 return _config(context, mapping, args, fn, evalinteger)
355 return _config(context, mapping, args, fn, evalinteger)
356
356
357
357
358 def _config(context, mapping, args, configfn, defaultfn):
358 def _config(context, mapping, args, configfn, defaultfn):
359 if not (2 <= len(args) <= 3):
359 if not (2 <= len(args) <= 3):
360 raise error.ParseError(_(b"config expects two or three arguments"))
360 raise error.ParseError(_(b"config expects two or three arguments"))
361
361
362 # The config option can come from any section, though we specifically
362 # The config option can come from any section, though we specifically
363 # reserve the [templateconfig] section for dynamically defining options
363 # reserve the [templateconfig] section for dynamically defining options
364 # for this function without also requiring an extension.
364 # for this function without also requiring an extension.
365 section = evalstringliteral(context, mapping, args[0])
365 section = evalstringliteral(context, mapping, args[0])
366 name = evalstringliteral(context, mapping, args[1])
366 name = evalstringliteral(context, mapping, args[1])
367 if len(args) == 3:
367 if len(args) == 3:
368 default = defaultfn(context, mapping, args[2])
368 default = defaultfn(context, mapping, args[2])
369 return configfn(section, name, default)
369 return configfn(section, name, default)
370 else:
370 else:
371 return configfn(section, name)
371 return configfn(section, name)
372
372
373
373
374 @templatefunc(b'if(expr, then[, else])')
374 @templatefunc(b'if(expr, then[, else])')
375 def if_(context, mapping, args):
375 def if_(context, mapping, args):
376 """Conditionally execute based on the result of
376 """Conditionally execute based on the result of
377 an expression."""
377 an expression."""
378 if not (2 <= len(args) <= 3):
378 if not (2 <= len(args) <= 3):
379 # i18n: "if" is a keyword
379 # i18n: "if" is a keyword
380 raise error.ParseError(_(b"if expects two or three arguments"))
380 raise error.ParseError(_(b"if expects two or three arguments"))
381
381
382 test = evalboolean(context, mapping, args[0])
382 test = evalboolean(context, mapping, args[0])
383 if test:
383 if test:
384 return evalrawexp(context, mapping, args[1])
384 return evalrawexp(context, mapping, args[1])
385 elif len(args) == 3:
385 elif len(args) == 3:
386 return evalrawexp(context, mapping, args[2])
386 return evalrawexp(context, mapping, args[2])
387
387
388
388
389 @templatefunc(b'ifcontains(needle, haystack, then[, else])')
389 @templatefunc(b'ifcontains(needle, haystack, then[, else])')
390 def ifcontains(context, mapping, args):
390 def ifcontains(context, mapping, args):
391 """Conditionally execute based
391 """Conditionally execute based
392 on whether the item "needle" is in "haystack"."""
392 on whether the item "needle" is in "haystack"."""
393 if not (3 <= len(args) <= 4):
393 if not (3 <= len(args) <= 4):
394 # i18n: "ifcontains" is a keyword
394 # i18n: "ifcontains" is a keyword
395 raise error.ParseError(_(b"ifcontains expects three or four arguments"))
395 raise error.ParseError(_(b"ifcontains expects three or four arguments"))
396
396
397 haystack = evalwrapped(context, mapping, args[1])
397 haystack = evalwrapped(context, mapping, args[1])
398 try:
398 try:
399 needle = evalrawexp(context, mapping, args[0])
399 needle = evalrawexp(context, mapping, args[0])
400 found = haystack.contains(context, mapping, needle)
400 found = haystack.contains(context, mapping, needle)
401 except error.ParseError:
401 except error.ParseError:
402 found = False
402 found = False
403
403
404 if found:
404 if found:
405 return evalrawexp(context, mapping, args[2])
405 return evalrawexp(context, mapping, args[2])
406 elif len(args) == 4:
406 elif len(args) == 4:
407 return evalrawexp(context, mapping, args[3])
407 return evalrawexp(context, mapping, args[3])
408
408
409
409
410 @templatefunc(b'ifeq(expr1, expr2, then[, else])')
410 @templatefunc(b'ifeq(expr1, expr2, then[, else])')
411 def ifeq(context, mapping, args):
411 def ifeq(context, mapping, args):
412 """Conditionally execute based on
412 """Conditionally execute based on
413 whether 2 items are equivalent."""
413 whether 2 items are equivalent."""
414 if not (3 <= len(args) <= 4):
414 if not (3 <= len(args) <= 4):
415 # i18n: "ifeq" is a keyword
415 # i18n: "ifeq" is a keyword
416 raise error.ParseError(_(b"ifeq expects three or four arguments"))
416 raise error.ParseError(_(b"ifeq expects three or four arguments"))
417
417
418 test = evalstring(context, mapping, args[0])
418 test = evalstring(context, mapping, args[0])
419 match = evalstring(context, mapping, args[1])
419 match = evalstring(context, mapping, args[1])
420 if test == match:
420 if test == match:
421 return evalrawexp(context, mapping, args[2])
421 return evalrawexp(context, mapping, args[2])
422 elif len(args) == 4:
422 elif len(args) == 4:
423 return evalrawexp(context, mapping, args[3])
423 return evalrawexp(context, mapping, args[3])
424
424
425
425
426 @templatefunc(b'join(list, sep)')
426 @templatefunc(b'join(list, sep)')
427 def join(context, mapping, args):
427 def join(context, mapping, args):
428 """Join items in a list with a delimiter."""
428 """Join items in a list with a delimiter."""
429 if not (1 <= len(args) <= 2):
429 if not (1 <= len(args) <= 2):
430 # i18n: "join" is a keyword
430 # i18n: "join" is a keyword
431 raise error.ParseError(_(b"join expects one or two arguments"))
431 raise error.ParseError(_(b"join expects one or two arguments"))
432
432
433 joinset = evalwrapped(context, mapping, args[0])
433 joinset = evalwrapped(context, mapping, args[0])
434 joiner = b" "
434 joiner = b" "
435 if len(args) > 1:
435 if len(args) > 1:
436 joiner = evalstring(context, mapping, args[1])
436 joiner = evalstring(context, mapping, args[1])
437 return joinset.join(context, mapping, joiner)
437 return joinset.join(context, mapping, joiner)
438
438
439
439
440 @templatefunc(b'label(label, expr)', requires={b'ui'})
440 @templatefunc(b'label(label, expr)', requires={b'ui'})
441 def label(context, mapping, args):
441 def label(context, mapping, args):
442 """Apply a label to generated content. Content with
442 """Apply a label to generated content. Content with
443 a label applied can result in additional post-processing, such as
443 a label applied can result in additional post-processing, such as
444 automatic colorization."""
444 automatic colorization."""
445 if len(args) != 2:
445 if len(args) != 2:
446 # i18n: "label" is a keyword
446 # i18n: "label" is a keyword
447 raise error.ParseError(_(b"label expects two arguments"))
447 raise error.ParseError(_(b"label expects two arguments"))
448
448
449 ui = context.resource(mapping, b'ui')
449 ui = context.resource(mapping, b'ui')
450 thing = evalstring(context, mapping, args[1])
450 thing = evalstring(context, mapping, args[1])
451 # preserve unknown symbol as literal so effects like 'red', 'bold',
451 # preserve unknown symbol as literal so effects like 'red', 'bold',
452 # etc. don't need to be quoted
452 # etc. don't need to be quoted
453 label = evalstringliteral(context, mapping, args[0])
453 label = evalstringliteral(context, mapping, args[0])
454
454
455 return ui.label(thing, label)
455 return ui.label(thing, label)
456
456
457
457
458 @templatefunc(b'latesttag([pattern])')
458 @templatefunc(b'latesttag([pattern])')
459 def latesttag(context, mapping, args):
459 def latesttag(context, mapping, args):
460 """The global tags matching the given pattern on the
460 """The global tags matching the given pattern on the
461 most recent globally tagged ancestor of this changeset.
461 most recent globally tagged ancestor of this changeset.
462 If no such tags exist, the "{tag}" template resolves to
462 If no such tags exist, the "{tag}" template resolves to
463 the string "null". See :hg:`help revisions.patterns` for the pattern
463 the string "null". See :hg:`help revisions.patterns` for the pattern
464 syntax.
464 syntax.
465 """
465 """
466 if len(args) > 1:
466 if len(args) > 1:
467 # i18n: "latesttag" is a keyword
467 # i18n: "latesttag" is a keyword
468 raise error.ParseError(_(b"latesttag expects at most one argument"))
468 raise error.ParseError(_(b"latesttag expects at most one argument"))
469
469
470 pattern = None
470 pattern = None
471 if len(args) == 1:
471 if len(args) == 1:
472 pattern = evalstring(context, mapping, args[0])
472 pattern = evalstring(context, mapping, args[0])
473 return templatekw.showlatesttags(context, mapping, pattern)
473 return templatekw.showlatesttags(context, mapping, pattern)
474
474
475
475
476 @templatefunc(b'localdate(date[, tz])')
476 @templatefunc(b'localdate(date[, tz])')
477 def localdate(context, mapping, args):
477 def localdate(context, mapping, args):
478 """Converts a date to the specified timezone.
478 """Converts a date to the specified timezone.
479 The default is local date."""
479 The default is local date."""
480 if not (1 <= len(args) <= 2):
480 if not (1 <= len(args) <= 2):
481 # i18n: "localdate" is a keyword
481 # i18n: "localdate" is a keyword
482 raise error.ParseError(_(b"localdate expects one or two arguments"))
482 raise error.ParseError(_(b"localdate expects one or two arguments"))
483
483
484 date = evaldate(
484 date = evaldate(
485 context,
485 context,
486 mapping,
486 mapping,
487 args[0],
487 args[0],
488 # i18n: "localdate" is a keyword
488 # i18n: "localdate" is a keyword
489 _(b"localdate expects a date information"),
489 _(b"localdate expects a date information"),
490 )
490 )
491 if len(args) >= 2:
491 if len(args) >= 2:
492 tzoffset = None
492 tzoffset = None
493 tz = evalfuncarg(context, mapping, args[1])
493 tz = evalfuncarg(context, mapping, args[1])
494 if isinstance(tz, bytes):
494 if isinstance(tz, bytes):
495 tzoffset, remainder = dateutil.parsetimezone(tz)
495 tzoffset, remainder = dateutil.parsetimezone(tz)
496 if remainder:
496 if remainder:
497 tzoffset = None
497 tzoffset = None
498 if tzoffset is None:
498 if tzoffset is None:
499 try:
499 try:
500 tzoffset = int(tz)
500 tzoffset = int(tz)
501 except (TypeError, ValueError):
501 except (TypeError, ValueError):
502 # i18n: "localdate" is a keyword
502 # i18n: "localdate" is a keyword
503 raise error.ParseError(_(b"localdate expects a timezone"))
503 raise error.ParseError(_(b"localdate expects a timezone"))
504 else:
504 else:
505 tzoffset = dateutil.makedate()[1]
505 tzoffset = dateutil.makedate()[1]
506 return templateutil.date((date[0], tzoffset))
506 return templateutil.date((date[0], tzoffset))
507
507
508
508
509 @templatefunc(b'max(iterable)')
509 @templatefunc(b'max(iterable)')
510 def max_(context, mapping, args, **kwargs):
510 def max_(context, mapping, args, **kwargs):
511 """Return the max of an iterable"""
511 """Return the max of an iterable"""
512 if len(args) != 1:
512 if len(args) != 1:
513 # i18n: "max" is a keyword
513 # i18n: "max" is a keyword
514 raise error.ParseError(_(b"max expects one argument"))
514 raise error.ParseError(_(b"max expects one argument"))
515
515
516 iterable = evalwrapped(context, mapping, args[0])
516 iterable = evalwrapped(context, mapping, args[0])
517 try:
517 try:
518 return iterable.getmax(context, mapping)
518 return iterable.getmax(context, mapping)
519 except error.ParseError as err:
519 except error.ParseError as err:
520 # i18n: "max" is a keyword
520 # i18n: "max" is a keyword
521 hint = _(b"max first argument should be an iterable")
521 hint = _(b"max first argument should be an iterable")
522 raise error.ParseError(bytes(err), hint=hint)
522 raise error.ParseError(bytes(err), hint=hint)
523
523
524
524
525 @templatefunc(b'min(iterable)')
525 @templatefunc(b'min(iterable)')
526 def min_(context, mapping, args, **kwargs):
526 def min_(context, mapping, args, **kwargs):
527 """Return the min of an iterable"""
527 """Return the min of an iterable"""
528 if len(args) != 1:
528 if len(args) != 1:
529 # i18n: "min" is a keyword
529 # i18n: "min" is a keyword
530 raise error.ParseError(_(b"min expects one argument"))
530 raise error.ParseError(_(b"min expects one argument"))
531
531
532 iterable = evalwrapped(context, mapping, args[0])
532 iterable = evalwrapped(context, mapping, args[0])
533 try:
533 try:
534 return iterable.getmin(context, mapping)
534 return iterable.getmin(context, mapping)
535 except error.ParseError as err:
535 except error.ParseError as err:
536 # i18n: "min" is a keyword
536 # i18n: "min" is a keyword
537 hint = _(b"min first argument should be an iterable")
537 hint = _(b"min first argument should be an iterable")
538 raise error.ParseError(bytes(err), hint=hint)
538 raise error.ParseError(bytes(err), hint=hint)
539
539
540
540
541 @templatefunc(b'mod(a, b)')
541 @templatefunc(b'mod(a, b)')
542 def mod(context, mapping, args):
542 def mod(context, mapping, args):
543 """Calculate a mod b such that a / b + a mod b == a"""
543 """Calculate a mod b such that a / b + a mod b == a"""
544 if not len(args) == 2:
544 if not len(args) == 2:
545 # i18n: "mod" is a keyword
545 # i18n: "mod" is a keyword
546 raise error.ParseError(_(b"mod expects two arguments"))
546 raise error.ParseError(_(b"mod expects two arguments"))
547
547
548 func = lambda a, b: a % b
548 func = lambda a, b: a % b
549 return templateutil.runarithmetic(
549 return templateutil.runarithmetic(
550 context, mapping, (func, args[0], args[1])
550 context, mapping, (func, args[0], args[1])
551 )
551 )
552
552
553
553
554 @templatefunc(b'obsfateoperations(markers)')
554 @templatefunc(b'obsfateoperations(markers)')
555 def obsfateoperations(context, mapping, args):
555 def obsfateoperations(context, mapping, args):
556 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
556 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
557 if len(args) != 1:
557 if len(args) != 1:
558 # i18n: "obsfateoperations" is a keyword
558 # i18n: "obsfateoperations" is a keyword
559 raise error.ParseError(_(b"obsfateoperations expects one argument"))
559 raise error.ParseError(_(b"obsfateoperations expects one argument"))
560
560
561 markers = evalfuncarg(context, mapping, args[0])
561 markers = evalfuncarg(context, mapping, args[0])
562
562
563 try:
563 try:
564 data = obsutil.markersoperations(markers)
564 data = obsutil.markersoperations(markers)
565 return templateutil.hybridlist(data, name=b'operation')
565 return templateutil.hybridlist(data, name=b'operation')
566 except (TypeError, KeyError):
566 except (TypeError, KeyError):
567 # i18n: "obsfateoperations" is a keyword
567 # i18n: "obsfateoperations" is a keyword
568 errmsg = _(b"obsfateoperations first argument should be an iterable")
568 errmsg = _(b"obsfateoperations first argument should be an iterable")
569 raise error.ParseError(errmsg)
569 raise error.ParseError(errmsg)
570
570
571
571
572 @templatefunc(b'obsfatedate(markers)')
572 @templatefunc(b'obsfatedate(markers)')
573 def obsfatedate(context, mapping, args):
573 def obsfatedate(context, mapping, args):
574 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
574 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
575 if len(args) != 1:
575 if len(args) != 1:
576 # i18n: "obsfatedate" is a keyword
576 # i18n: "obsfatedate" is a keyword
577 raise error.ParseError(_(b"obsfatedate expects one argument"))
577 raise error.ParseError(_(b"obsfatedate expects one argument"))
578
578
579 markers = evalfuncarg(context, mapping, args[0])
579 markers = evalfuncarg(context, mapping, args[0])
580
580
581 try:
581 try:
582 # TODO: maybe this has to be a wrapped list of date wrappers?
582 # TODO: maybe this has to be a wrapped list of date wrappers?
583 data = obsutil.markersdates(markers)
583 data = obsutil.markersdates(markers)
584 return templateutil.hybridlist(data, name=b'date', fmt=b'%d %d')
584 return templateutil.hybridlist(data, name=b'date', fmt=b'%d %d')
585 except (TypeError, KeyError):
585 except (TypeError, KeyError):
586 # i18n: "obsfatedate" is a keyword
586 # i18n: "obsfatedate" is a keyword
587 errmsg = _(b"obsfatedate first argument should be an iterable")
587 errmsg = _(b"obsfatedate first argument should be an iterable")
588 raise error.ParseError(errmsg)
588 raise error.ParseError(errmsg)
589
589
590
590
591 @templatefunc(b'obsfateusers(markers)')
591 @templatefunc(b'obsfateusers(markers)')
592 def obsfateusers(context, mapping, args):
592 def obsfateusers(context, mapping, args):
593 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
593 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
594 if len(args) != 1:
594 if len(args) != 1:
595 # i18n: "obsfateusers" is a keyword
595 # i18n: "obsfateusers" is a keyword
596 raise error.ParseError(_(b"obsfateusers expects one argument"))
596 raise error.ParseError(_(b"obsfateusers expects one argument"))
597
597
598 markers = evalfuncarg(context, mapping, args[0])
598 markers = evalfuncarg(context, mapping, args[0])
599
599
600 try:
600 try:
601 data = obsutil.markersusers(markers)
601 data = obsutil.markersusers(markers)
602 return templateutil.hybridlist(data, name=b'user')
602 return templateutil.hybridlist(data, name=b'user')
603 except (TypeError, KeyError, ValueError):
603 except (TypeError, KeyError, ValueError):
604 # i18n: "obsfateusers" is a keyword
604 # i18n: "obsfateusers" is a keyword
605 msg = _(
605 msg = _(
606 b"obsfateusers first argument should be an iterable of "
606 b"obsfateusers first argument should be an iterable of "
607 b"obsmakers"
607 b"obsmakers"
608 )
608 )
609 raise error.ParseError(msg)
609 raise error.ParseError(msg)
610
610
611
611
612 @templatefunc(b'obsfateverb(successors, markers)')
612 @templatefunc(b'obsfateverb(successors, markers)')
613 def obsfateverb(context, mapping, args):
613 def obsfateverb(context, mapping, args):
614 """Compute obsfate related information based on successors (EXPERIMENTAL)"""
614 """Compute obsfate related information based on successors (EXPERIMENTAL)"""
615 if len(args) != 2:
615 if len(args) != 2:
616 # i18n: "obsfateverb" is a keyword
616 # i18n: "obsfateverb" is a keyword
617 raise error.ParseError(_(b"obsfateverb expects two arguments"))
617 raise error.ParseError(_(b"obsfateverb expects two arguments"))
618
618
619 successors = evalfuncarg(context, mapping, args[0])
619 successors = evalfuncarg(context, mapping, args[0])
620 markers = evalfuncarg(context, mapping, args[1])
620 markers = evalfuncarg(context, mapping, args[1])
621
621
622 try:
622 try:
623 return obsutil.obsfateverb(successors, markers)
623 return obsutil.obsfateverb(successors, markers)
624 except TypeError:
624 except TypeError:
625 # i18n: "obsfateverb" is a keyword
625 # i18n: "obsfateverb" is a keyword
626 errmsg = _(b"obsfateverb first argument should be countable")
626 errmsg = _(b"obsfateverb first argument should be countable")
627 raise error.ParseError(errmsg)
627 raise error.ParseError(errmsg)
628
628
629
629
630 @templatefunc(b'relpath(path)', requires={b'repo'})
630 @templatefunc(b'relpath(path)', requires={b'repo'})
631 def relpath(context, mapping, args):
631 def relpath(context, mapping, args):
632 """Convert a repository-absolute path into a filesystem path relative to
632 """Convert a repository-absolute path into a filesystem path relative to
633 the current working directory."""
633 the current working directory."""
634 if len(args) != 1:
634 if len(args) != 1:
635 # i18n: "relpath" is a keyword
635 # i18n: "relpath" is a keyword
636 raise error.ParseError(_(b"relpath expects one argument"))
636 raise error.ParseError(_(b"relpath expects one argument"))
637
637
638 repo = context.resource(mapping, b'repo')
638 repo = context.resource(mapping, b'repo')
639 path = evalstring(context, mapping, args[0])
639 path = evalstring(context, mapping, args[0])
640 return repo.pathto(path)
640 return repo.pathto(path)
641
641
642
642
643 @templatefunc(b'revset(query[, formatargs...])', requires={b'repo', b'cache'})
643 @templatefunc(b'revset(query[, formatargs...])', requires={b'repo', b'cache'})
644 def revset(context, mapping, args):
644 def revset(context, mapping, args):
645 """Execute a revision set query. See
645 """Execute a revision set query. See
646 :hg:`help revset`."""
646 :hg:`help revset`."""
647 if not len(args) > 0:
647 if not len(args) > 0:
648 # i18n: "revset" is a keyword
648 # i18n: "revset" is a keyword
649 raise error.ParseError(_(b"revset expects one or more arguments"))
649 raise error.ParseError(_(b"revset expects one or more arguments"))
650
650
651 raw = evalstring(context, mapping, args[0])
651 raw = evalstring(context, mapping, args[0])
652 repo = context.resource(mapping, b'repo')
652 repo = context.resource(mapping, b'repo')
653
653
654 def query(expr):
654 def query(expr):
655 m = revsetmod.match(repo.ui, expr, lookup=revsetmod.lookupfn(repo))
655 m = revsetmod.match(repo.ui, expr, lookup=revsetmod.lookupfn(repo))
656 return m(repo)
656 return m(repo)
657
657
658 if len(args) > 1:
658 if len(args) > 1:
659 key = None # dynamically-created revs shouldn't be cached
659 key = None # dynamically-created revs shouldn't be cached
660 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
660 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
661 revs = query(revsetlang.formatspec(raw, *formatargs))
661 revs = query(revsetlang.formatspec(raw, *formatargs))
662 else:
662 else:
663 cache = context.resource(mapping, b'cache')
663 cache = context.resource(mapping, b'cache')
664 revsetcache = cache.setdefault(b"revsetcache", {})
664 revsetcache = cache.setdefault(b"revsetcache", {})
665 key = raw
665 key = raw
666 if key in revsetcache:
666 if key in revsetcache:
667 revs = revsetcache[key]
667 revs = revsetcache[key]
668 else:
668 else:
669 revs = query(raw)
669 revs = query(raw)
670 revsetcache[key] = revs
670 revsetcache[key] = revs
671 return templateutil.revslist(repo, revs, name=b'revision', cachekey=key)
671 return templateutil.revslist(repo, revs, name=b'revision', cachekey=key)
672
672
673
673
674 @templatefunc(b'rstdoc(text, style)')
674 @templatefunc(b'rstdoc(text, style)')
675 def rstdoc(context, mapping, args):
675 def rstdoc(context, mapping, args):
676 """Format reStructuredText."""
676 """Format reStructuredText."""
677 if len(args) != 2:
677 if len(args) != 2:
678 # i18n: "rstdoc" is a keyword
678 # i18n: "rstdoc" is a keyword
679 raise error.ParseError(_(b"rstdoc expects two arguments"))
679 raise error.ParseError(_(b"rstdoc expects two arguments"))
680
680
681 text = evalstring(context, mapping, args[0])
681 text = evalstring(context, mapping, args[0])
682 style = evalstring(context, mapping, args[1])
682 style = evalstring(context, mapping, args[1])
683
683
684 return minirst.format(text, style=style, keep=[b'verbose'])
684 return minirst.format(text, style=style, keep=[b'verbose'])
685
685
686
686
687 @templatefunc(b'search(pattern, text)')
687 @templatefunc(b'search(pattern, text)')
688 def search(context, mapping, args):
688 def search(context, mapping, args):
689 """Look for the first text matching the regular expression pattern.
689 """Look for the first text matching the regular expression pattern.
690 Groups are accessible as ``{1}``, ``{2}``, ... in %-mapped template."""
690 Groups are accessible as ``{1}``, ``{2}``, ... in %-mapped template."""
691 if len(args) != 2:
691 if len(args) != 2:
692 # i18n: "search" is a keyword
692 # i18n: "search" is a keyword
693 raise error.ParseError(_(b'search expects two arguments'))
693 raise error.ParseError(_(b'search expects two arguments'))
694
694
695 pat = evalstring(context, mapping, args[0])
695 pat = evalstring(context, mapping, args[0])
696 src = evalstring(context, mapping, args[1])
696 src = evalstring(context, mapping, args[1])
697 try:
697 try:
698 patre = re.compile(pat)
698 patre = re.compile(pat)
699 except re.error:
699 except re.error:
700 # i18n: "search" is a keyword
700 # i18n: "search" is a keyword
701 raise error.ParseError(_(b'search got an invalid pattern: %s') % pat)
701 raise error.ParseError(_(b'search got an invalid pattern: %s') % pat)
702 # named groups shouldn't shadow *reserved* resource keywords
702 # named groups shouldn't shadow *reserved* resource keywords
703 badgroups = context.knownresourcekeys() & set(
703 badgroups = context.knownresourcekeys() & set(
704 pycompat.byteskwargs(patre.groupindex)
704 pycompat.byteskwargs(patre.groupindex)
705 )
705 )
706 if badgroups:
706 if badgroups:
707 raise error.ParseError(
707 raise error.ParseError(
708 # i18n: "search" is a keyword
708 # i18n: "search" is a keyword
709 _(b'invalid group %(group)s in search pattern: %(pat)s')
709 _(b'invalid group %(group)s in search pattern: %(pat)s')
710 % {
710 % {
711 b'group': b', '.join(b"'%s'" % g for g in sorted(badgroups)),
711 b'group': b', '.join(b"'%s'" % g for g in sorted(badgroups)),
712 b'pat': pat,
712 b'pat': pat,
713 }
713 }
714 )
714 )
715
715
716 match = patre.search(src)
716 match = patre.search(src)
717 if not match:
717 if not match:
718 return templateutil.mappingnone()
718 return templateutil.mappingnone()
719
719
720 lm = {b'0': match.group(0)}
720 lm = {b'0': match.group(0)}
721 lm.update((b'%d' % i, v) for i, v in enumerate(match.groups(), 1))
721 lm.update((b'%d' % i, v) for i, v in enumerate(match.groups(), 1))
722 lm.update(pycompat.byteskwargs(match.groupdict()))
722 lm.update(pycompat.byteskwargs(match.groupdict()))
723 return templateutil.mappingdict(lm, tmpl=b'{0}')
723 return templateutil.mappingdict(lm, tmpl=b'{0}')
724
724
725
725
726 @templatefunc(b'separate(sep, args...)', argspec=b'sep *args')
726 @templatefunc(b'separate(sep, args...)', argspec=b'sep *args')
727 def separate(context, mapping, args):
727 def separate(context, mapping, args):
728 """Add a separator between non-empty arguments."""
728 """Add a separator between non-empty arguments."""
729 if b'sep' not in args:
729 if b'sep' not in args:
730 # i18n: "separate" is a keyword
730 # i18n: "separate" is a keyword
731 raise error.ParseError(_(b"separate expects at least one argument"))
731 raise error.ParseError(_(b"separate expects at least one argument"))
732
732
733 sep = evalstring(context, mapping, args[b'sep'])
733 sep = evalstring(context, mapping, args[b'sep'])
734 first = True
734 first = True
735 for arg in args[b'args']:
735 for arg in args[b'args']:
736 argstr = evalstring(context, mapping, arg)
736 argstr = evalstring(context, mapping, arg)
737 if not argstr:
737 if not argstr:
738 continue
738 continue
739 if first:
739 if first:
740 first = False
740 first = False
741 else:
741 else:
742 yield sep
742 yield sep
743 yield argstr
743 yield argstr
744
744
745
745
746 @templatefunc(b'shortest(node, minlength=4)', requires={b'repo', b'cache'})
746 @templatefunc(b'shortest(node, minlength=4)', requires={b'repo', b'cache'})
747 def shortest(context, mapping, args):
747 def shortest(context, mapping, args):
748 """Obtain the shortest representation of
748 """Obtain the shortest representation of
749 a node."""
749 a node."""
750 if not (1 <= len(args) <= 2):
750 if not (1 <= len(args) <= 2):
751 # i18n: "shortest" is a keyword
751 # i18n: "shortest" is a keyword
752 raise error.ParseError(_(b"shortest() expects one or two arguments"))
752 raise error.ParseError(_(b"shortest() expects one or two arguments"))
753
753
754 hexnode = evalstring(context, mapping, args[0])
754 hexnode = evalstring(context, mapping, args[0])
755
755
756 minlength = 4
756 minlength = 4
757 if len(args) > 1:
757 if len(args) > 1:
758 minlength = evalinteger(
758 minlength = evalinteger(
759 context,
759 context,
760 mapping,
760 mapping,
761 args[1],
761 args[1],
762 # i18n: "shortest" is a keyword
762 # i18n: "shortest" is a keyword
763 _(b"shortest() expects an integer minlength"),
763 _(b"shortest() expects an integer minlength"),
764 )
764 )
765
765
766 repo = context.resource(mapping, b'repo')
766 repo = context.resource(mapping, b'repo')
767 hexnodelen = 2 * repo.nodeconstants.nodelen
767 hexnodelen = 2 * repo.nodeconstants.nodelen
768 if len(hexnode) > hexnodelen:
768 if len(hexnode) > hexnodelen:
769 return hexnode
769 return hexnode
770 elif len(hexnode) == hexnodelen:
770 elif len(hexnode) == hexnodelen:
771 try:
771 try:
772 node = bin(hexnode)
772 node = bin(hexnode)
773 except binascii.Error:
773 except binascii.Error:
774 return hexnode
774 return hexnode
775 else:
775 else:
776 try:
776 try:
777 node = scmutil.resolvehexnodeidprefix(repo, hexnode)
777 node = scmutil.resolvehexnodeidprefix(repo, hexnode)
778 except error.WdirUnsupported:
778 except error.WdirUnsupported:
779 node = repo.nodeconstants.wdirid
779 node = repo.nodeconstants.wdirid
780 except error.LookupError:
780 except error.LookupError:
781 return hexnode
781 return hexnode
782 if not node:
782 if not node:
783 return hexnode
783 return hexnode
784 cache = context.resource(mapping, b'cache')
784 cache = context.resource(mapping, b'cache')
785 try:
785 try:
786 return scmutil.shortesthexnodeidprefix(repo, node, minlength, cache)
786 return scmutil.shortesthexnodeidprefix(repo, node, minlength, cache)
787 except error.RepoLookupError:
787 except error.RepoLookupError:
788 return hexnode
788 return hexnode
789
789
790
790
791 @templatefunc(b'strip(text[, chars])')
791 @templatefunc(b'strip(text[, chars])')
792 def strip(context, mapping, args):
792 def strip(context, mapping, args):
793 """Strip characters from a string. By default,
793 """Strip characters from a string. By default,
794 strips all leading and trailing whitespace."""
794 strips all leading and trailing whitespace."""
795 if not (1 <= len(args) <= 2):
795 if not (1 <= len(args) <= 2):
796 # i18n: "strip" is a keyword
796 # i18n: "strip" is a keyword
797 raise error.ParseError(_(b"strip expects one or two arguments"))
797 raise error.ParseError(_(b"strip expects one or two arguments"))
798
798
799 text = evalstring(context, mapping, args[0])
799 text = evalstring(context, mapping, args[0])
800 if len(args) == 2:
800 if len(args) == 2:
801 chars = evalstring(context, mapping, args[1])
801 chars = evalstring(context, mapping, args[1])
802 return text.strip(chars)
802 return text.strip(chars)
803 return text.strip()
803 return text.strip()
804
804
805
805
806 @templatefunc(b'sub(pattern, replacement, expression)')
806 @templatefunc(b'sub(pattern, replacement, expression)')
807 def sub(context, mapping, args):
807 def sub(context, mapping, args):
808 """Perform text substitution
808 """Perform text substitution
809 using regular expressions."""
809 using regular expressions."""
810 if len(args) != 3:
810 if len(args) != 3:
811 # i18n: "sub" is a keyword
811 # i18n: "sub" is a keyword
812 raise error.ParseError(_(b"sub expects three arguments"))
812 raise error.ParseError(_(b"sub expects three arguments"))
813
813
814 pat = evalstring(context, mapping, args[0])
814 pat = evalstring(context, mapping, args[0])
815 rpl = evalstring(context, mapping, args[1])
815 rpl = evalstring(context, mapping, args[1])
816 src = evalstring(context, mapping, args[2])
816 src = evalstring(context, mapping, args[2])
817 try:
817 try:
818 patre = re.compile(pat)
818 patre = re.compile(pat)
819 except re.error:
819 except re.error:
820 # i18n: "sub" is a keyword
820 # i18n: "sub" is a keyword
821 raise error.ParseError(_(b"sub got an invalid pattern: %s") % pat)
821 raise error.ParseError(_(b"sub got an invalid pattern: %s") % pat)
822 try:
822 try:
823 yield patre.sub(rpl, src)
823 yield patre.sub(rpl, src)
824 except re.error:
824 except re.error:
825 # i18n: "sub" is a keyword
825 # i18n: "sub" is a keyword
826 raise error.ParseError(_(b"sub got an invalid replacement: %s") % rpl)
826 raise error.ParseError(_(b"sub got an invalid replacement: %s") % rpl)
827
827
828
828
829 @templatefunc(b'startswith(pattern, text)')
829 @templatefunc(b'startswith(pattern, text)')
830 def startswith(context, mapping, args):
830 def startswith(context, mapping, args):
831 """Returns the value from the "text" argument
831 """Returns the value from the "text" argument
832 if it begins with the content from the "pattern" argument."""
832 if it begins with the content from the "pattern" argument."""
833 if len(args) != 2:
833 if len(args) != 2:
834 # i18n: "startswith" is a keyword
834 # i18n: "startswith" is a keyword
835 raise error.ParseError(_(b"startswith expects two arguments"))
835 raise error.ParseError(_(b"startswith expects two arguments"))
836
836
837 patn = evalstring(context, mapping, args[0])
837 patn = evalstring(context, mapping, args[0])
838 text = evalstring(context, mapping, args[1])
838 text = evalstring(context, mapping, args[1])
839 if text.startswith(patn):
839 if text.startswith(patn):
840 return text
840 return text
841 return b''
841 return b''
842
842
843
843
844 @templatefunc(
844 @templatefunc(
845 b'subsetparents(rev, revset)',
845 b'subsetparents(rev, revset)',
846 argspec=b'rev revset',
846 argspec=b'rev revset',
847 requires={b'repo', b'cache'},
847 requires={b'repo', b'cache'},
848 )
848 )
849 def subsetparents(context, mapping, args):
849 def subsetparents(context, mapping, args):
850 """Look up parents of the rev in the sub graph given by the revset."""
850 """Look up parents of the rev in the sub graph given by the revset."""
851 if b'rev' not in args or b'revset' not in args:
851 if b'rev' not in args or b'revset' not in args:
852 # i18n: "subsetparents" is a keyword
852 # i18n: "subsetparents" is a keyword
853 raise error.ParseError(_(b"subsetparents expects two arguments"))
853 raise error.ParseError(_(b"subsetparents expects two arguments"))
854
854
855 repo = context.resource(mapping, b'repo')
855 repo = context.resource(mapping, b'repo')
856
856
857 rev = templateutil.evalinteger(context, mapping, args[b'rev'])
857 rev = templateutil.evalinteger(context, mapping, args[b'rev'])
858
858
859 # TODO: maybe subsetparents(rev) should be allowed. the default revset
859 # TODO: maybe subsetparents(rev) should be allowed. the default revset
860 # will be the revisions specified by -rREV argument.
860 # will be the revisions specified by -rREV argument.
861 q = templateutil.evalwrapped(context, mapping, args[b'revset'])
861 q = templateutil.evalwrapped(context, mapping, args[b'revset'])
862 if not isinstance(q, templateutil.revslist):
862 if not isinstance(q, templateutil.revslist):
863 # i18n: "subsetparents" is a keyword
863 # i18n: "subsetparents" is a keyword
864 raise error.ParseError(_(b"subsetparents expects a queried revset"))
864 raise error.ParseError(_(b"subsetparents expects a queried revset"))
865 subset = q.tovalue(context, mapping)
865 subset = q.tovalue(context, mapping)
866 key = q.cachekey
866 key = q.cachekey
867
867
868 if key:
868 if key:
869 # cache only if revset query isn't dynamic
869 # cache only if revset query isn't dynamic
870 cache = context.resource(mapping, b'cache')
870 cache = context.resource(mapping, b'cache')
871 walkercache = cache.setdefault(b'subsetparentswalker', {})
871 walkercache = cache.setdefault(b'subsetparentswalker', {})
872 if key in walkercache:
872 if key in walkercache:
873 walker = walkercache[key]
873 walker = walkercache[key]
874 else:
874 else:
875 walker = dagop.subsetparentswalker(repo, subset)
875 walker = dagop.subsetparentswalker(repo, subset)
876 walkercache[key] = walker
876 walkercache[key] = walker
877 else:
877 else:
878 # for one-shot use, specify startrev to limit the search space
878 # for one-shot use, specify startrev to limit the search space
879 walker = dagop.subsetparentswalker(repo, subset, startrev=rev)
879 walker = dagop.subsetparentswalker(repo, subset, startrev=rev)
880 return templateutil.revslist(repo, walker.parentsset(rev))
880 return templateutil.revslist(repo, walker.parentsset(rev))
881
881
882
882
883 @templatefunc(b'word(number, text[, separator])')
883 @templatefunc(b'word(number, text[, separator])')
884 def word(context, mapping, args):
884 def word(context, mapping, args):
885 """Return the nth word from a string."""
885 """Return the nth word from a string."""
886 if not (2 <= len(args) <= 3):
886 if not (2 <= len(args) <= 3):
887 # i18n: "word" is a keyword
887 # i18n: "word" is a keyword
888 raise error.ParseError(
888 raise error.ParseError(
889 _(b"word expects two or three arguments, got %d") % len(args)
889 _(b"word expects two or three arguments, got %d") % len(args)
890 )
890 )
891
891
892 num = evalinteger(
892 num = evalinteger(
893 context,
893 context,
894 mapping,
894 mapping,
895 args[0],
895 args[0],
896 # i18n: "word" is a keyword
896 # i18n: "word" is a keyword
897 _(b"word expects an integer index"),
897 _(b"word expects an integer index"),
898 )
898 )
899 text = evalstring(context, mapping, args[1])
899 text = evalstring(context, mapping, args[1])
900 if len(args) == 3:
900 if len(args) == 3:
901 splitter = evalstring(context, mapping, args[2])
901 splitter = evalstring(context, mapping, args[2])
902 else:
902 else:
903 splitter = None
903 splitter = None
904
904
905 tokens = text.split(splitter)
905 tokens = text.split(splitter)
906 if num >= len(tokens) or num < -len(tokens):
906 if num >= len(tokens) or num < -len(tokens):
907 return b''
907 return b''
908 else:
908 else:
909 return tokens[num]
909 return tokens[num]
910
910
911
911
912 def loadfunction(ui, extname, registrarobj):
912 def loadfunction(ui, extname, registrarobj):
913 """Load template function from specified registrarobj"""
913 """Load template function from specified registrarobj"""
914 for name, func in registrarobj._table.items():
914 for name, func in registrarobj._table.items():
915 funcs[name] = func
915 funcs[name] = func
916
916
917
917
918 # tell hggettext to extract docstrings from these functions:
918 # tell hggettext to extract docstrings from these functions:
919 i18nfunctions = funcs.values()
919 i18nfunctions = funcs.values()
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now