##// END OF EJS Templates
merge with stable
Matt Mackall -
r16576:eab32ab5 merge default
parent child Browse files
Show More
@@ -1,55 +1,56 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=
@@ -1,67 +1,68 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
@@ -1,466 +1,462 b''
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
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 '''setup for largefiles repositories: reposetup'''
9 '''setup for largefiles repositories: reposetup'''
10 import copy
10 import copy
11 import types
11 import types
12 import os
12 import os
13
13
14 from mercurial import context, error, manifest, match as match_, util
14 from mercurial import context, error, manifest, match as match_, util
15 from mercurial import node as node_
15 from mercurial import node as node_
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17
17
18 import lfcommands
18 import lfcommands
19 import proto
19 import proto
20 import lfutil
20 import lfutil
21
21
22 def reposetup(ui, repo):
22 def reposetup(ui, repo):
23 # wire repositories should be given new wireproto functions but not the
23 # wire repositories should be given new wireproto functions but not the
24 # other largefiles modifications
24 # other largefiles modifications
25 if not repo.local():
25 if not repo.local():
26 return proto.wirereposetup(ui, repo)
26 return proto.wirereposetup(ui, repo)
27
27
28 for name in ('status', 'commitctx', 'commit', 'push'):
28 for name in ('status', 'commitctx', 'commit', 'push'):
29 method = getattr(repo, name)
29 method = getattr(repo, name)
30 if (isinstance(method, types.FunctionType) and
30 if (isinstance(method, types.FunctionType) and
31 method.func_name == 'wrap'):
31 method.func_name == 'wrap'):
32 ui.warn(_('largefiles: repo method %r appears to have already been'
32 ui.warn(_('largefiles: repo method %r appears to have already been'
33 ' wrapped by another extension: '
33 ' wrapped by another extension: '
34 'largefiles may behave incorrectly\n')
34 'largefiles may behave incorrectly\n')
35 % name)
35 % name)
36
36
37 class lfilesrepo(repo.__class__):
37 class lfilesrepo(repo.__class__):
38 lfstatus = False
38 lfstatus = False
39 def status_nolfiles(self, *args, **kwargs):
39 def status_nolfiles(self, *args, **kwargs):
40 return super(lfilesrepo, self).status(*args, **kwargs)
40 return super(lfilesrepo, self).status(*args, **kwargs)
41
41
42 # When lfstatus is set, return a context that gives the names
42 # When lfstatus is set, return a context that gives the names
43 # of largefiles instead of their corresponding standins and
43 # of largefiles instead of their corresponding standins and
44 # identifies the largefiles as always binary, regardless of
44 # identifies the largefiles as always binary, regardless of
45 # their actual contents.
45 # their actual contents.
46 def __getitem__(self, changeid):
46 def __getitem__(self, changeid):
47 ctx = super(lfilesrepo, self).__getitem__(changeid)
47 ctx = super(lfilesrepo, self).__getitem__(changeid)
48 if self.lfstatus:
48 if self.lfstatus:
49 class lfilesmanifestdict(manifest.manifestdict):
49 class lfilesmanifestdict(manifest.manifestdict):
50 def __contains__(self, filename):
50 def __contains__(self, filename):
51 if super(lfilesmanifestdict,
51 if super(lfilesmanifestdict,
52 self).__contains__(filename):
52 self).__contains__(filename):
53 return True
53 return True
54 return super(lfilesmanifestdict,
54 return super(lfilesmanifestdict,
55 self).__contains__(lfutil.standin(filename))
55 self).__contains__(lfutil.standin(filename))
56 class lfilesctx(ctx.__class__):
56 class lfilesctx(ctx.__class__):
57 def files(self):
57 def files(self):
58 filenames = super(lfilesctx, self).files()
58 filenames = super(lfilesctx, self).files()
59 return [lfutil.splitstandin(f) or f for f in filenames]
59 return [lfutil.splitstandin(f) or f for f in filenames]
60 def manifest(self):
60 def manifest(self):
61 man1 = super(lfilesctx, self).manifest()
61 man1 = super(lfilesctx, self).manifest()
62 man1.__class__ = lfilesmanifestdict
62 man1.__class__ = lfilesmanifestdict
63 return man1
63 return man1
64 def filectx(self, path, fileid=None, filelog=None):
64 def filectx(self, path, fileid=None, filelog=None):
65 try:
65 try:
66 if filelog is not None:
66 if filelog is not None:
67 result = super(lfilesctx, self).filectx(
67 result = super(lfilesctx, self).filectx(
68 path, fileid, filelog)
68 path, fileid, filelog)
69 else:
69 else:
70 result = super(lfilesctx, self).filectx(
70 result = super(lfilesctx, self).filectx(
71 path, fileid)
71 path, fileid)
72 except error.LookupError:
72 except error.LookupError:
73 # Adding a null character will cause Mercurial to
73 # Adding a null character will cause Mercurial to
74 # identify this as a binary file.
74 # identify this as a binary file.
75 if filelog is not None:
75 if filelog is not None:
76 result = super(lfilesctx, self).filectx(
76 result = super(lfilesctx, self).filectx(
77 lfutil.standin(path), fileid, filelog)
77 lfutil.standin(path), fileid, filelog)
78 else:
78 else:
79 result = super(lfilesctx, self).filectx(
79 result = super(lfilesctx, self).filectx(
80 lfutil.standin(path), fileid)
80 lfutil.standin(path), fileid)
81 olddata = result.data
81 olddata = result.data
82 result.data = lambda: olddata() + '\0'
82 result.data = lambda: olddata() + '\0'
83 return result
83 return result
84 ctx.__class__ = lfilesctx
84 ctx.__class__ = lfilesctx
85 return ctx
85 return ctx
86
86
87 # Figure out the status of big files and insert them into the
87 # Figure out the status of big files and insert them into the
88 # appropriate list in the result. Also removes standin files
88 # appropriate list in the result. Also removes standin files
89 # from the listing. Revert to the original status if
89 # from the listing. Revert to the original status if
90 # self.lfstatus is False.
90 # self.lfstatus is False.
91 def status(self, node1='.', node2=None, match=None, ignored=False,
91 def status(self, node1='.', node2=None, match=None, ignored=False,
92 clean=False, unknown=False, listsubrepos=False):
92 clean=False, unknown=False, listsubrepos=False):
93 listignored, listclean, listunknown = ignored, clean, unknown
93 listignored, listclean, listunknown = ignored, clean, unknown
94 if not self.lfstatus:
94 if not self.lfstatus:
95 return super(lfilesrepo, self).status(node1, node2, match,
95 return super(lfilesrepo, self).status(node1, node2, match,
96 listignored, listclean, listunknown, listsubrepos)
96 listignored, listclean, listunknown, listsubrepos)
97 else:
97 else:
98 # some calls in this function rely on the old version of status
98 # some calls in this function rely on the old version of status
99 self.lfstatus = False
99 self.lfstatus = False
100 if isinstance(node1, context.changectx):
100 if isinstance(node1, context.changectx):
101 ctx1 = node1
101 ctx1 = node1
102 else:
102 else:
103 ctx1 = repo[node1]
103 ctx1 = repo[node1]
104 if isinstance(node2, context.changectx):
104 if isinstance(node2, context.changectx):
105 ctx2 = node2
105 ctx2 = node2
106 else:
106 else:
107 ctx2 = repo[node2]
107 ctx2 = repo[node2]
108 working = ctx2.rev() is None
108 working = ctx2.rev() is None
109 parentworking = working and ctx1 == self['.']
109 parentworking = working and ctx1 == self['.']
110
110
111 def inctx(file, ctx):
111 def inctx(file, ctx):
112 try:
112 try:
113 if ctx.rev() is None:
113 if ctx.rev() is None:
114 return file in ctx.manifest()
114 return file in ctx.manifest()
115 ctx[file]
115 ctx[file]
116 return True
116 return True
117 except KeyError:
117 except KeyError:
118 return False
118 return False
119
119
120 if match is None:
120 if match is None:
121 match = match_.always(self.root, self.getcwd())
121 match = match_.always(self.root, self.getcwd())
122
122
123 # First check if there were files specified on the
123 # First check if there were files specified on the
124 # command line. If there were, and none of them were
124 # command line. If there were, and none of them were
125 # largefiles, we should just bail here and let super
125 # largefiles, we should just bail here and let super
126 # handle it -- thus gaining a big performance boost.
126 # handle it -- thus gaining a big performance boost.
127 lfdirstate = lfutil.openlfdirstate(ui, self)
127 lfdirstate = lfutil.openlfdirstate(ui, self)
128 if match.files() and not match.anypats():
128 if match.files() and not match.anypats():
129 for f in lfdirstate:
129 for f in lfdirstate:
130 if match(f):
130 if match(f):
131 break
131 break
132 else:
132 else:
133 return super(lfilesrepo, self).status(node1, node2,
133 return super(lfilesrepo, self).status(node1, node2,
134 match, listignored, listclean,
134 match, listignored, listclean,
135 listunknown, listsubrepos)
135 listunknown, listsubrepos)
136
136
137 # Create a copy of match that matches standins instead
137 # Create a copy of match that matches standins instead
138 # of largefiles.
138 # of largefiles.
139 def tostandin(file):
139 def tostandin(file):
140 if working:
140 if working:
141 sf = lfutil.standin(file)
141 sf = lfutil.standin(file)
142 dirstate = repo.dirstate
142 dirstate = repo.dirstate
143 if sf in dirstate or sf in dirstate.dirs():
143 if sf in dirstate or sf in dirstate.dirs():
144 return sf
144 return sf
145 return file
145 return file
146
146
147 # Create a function that we can use to override what is
147 # Create a function that we can use to override what is
148 # normally the ignore matcher. We've already checked
148 # normally the ignore matcher. We've already checked
149 # for ignored files on the first dirstate walk, and
149 # for ignored files on the first dirstate walk, and
150 # unecessarily re-checking here causes a huge performance
150 # unecessarily re-checking here causes a huge performance
151 # hit because lfdirstate only knows about largefiles
151 # hit because lfdirstate only knows about largefiles
152 def _ignoreoverride(self):
152 def _ignoreoverride(self):
153 return False
153 return False
154
154
155 m = copy.copy(match)
155 m = copy.copy(match)
156 m._files = [tostandin(f) for f in m._files]
156 m._files = [tostandin(f) for f in m._files]
157
157
158 # Get ignored files here even if we weren't asked for them; we
158 # Get ignored files here even if we weren't asked for them; we
159 # must use the result here for filtering later
159 # must use the result here for filtering later
160 result = super(lfilesrepo, self).status(node1, node2, m,
160 result = super(lfilesrepo, self).status(node1, node2, m,
161 True, clean, unknown, listsubrepos)
161 True, clean, unknown, listsubrepos)
162 if working:
162 if working:
163 try:
163 try:
164 # Any non-largefiles that were explicitly listed must be
164 # Any non-largefiles that were explicitly listed must be
165 # taken out or lfdirstate.status will report an error.
165 # taken out or lfdirstate.status will report an error.
166 # The status of these files was already computed using
166 # The status of these files was already computed using
167 # super's status.
167 # super's status.
168 # Override lfdirstate's ignore matcher to not do
168 # Override lfdirstate's ignore matcher to not do
169 # anything
169 # anything
170 origignore = lfdirstate._ignore
170 origignore = lfdirstate._ignore
171 lfdirstate._ignore = _ignoreoverride
171 lfdirstate._ignore = _ignoreoverride
172
172
173 def sfindirstate(f):
173 def sfindirstate(f):
174 sf = lfutil.standin(f)
174 sf = lfutil.standin(f)
175 dirstate = repo.dirstate
175 dirstate = repo.dirstate
176 return sf in dirstate or sf in dirstate.dirs()
176 return sf in dirstate or sf in dirstate.dirs()
177 match._files = [f for f in match._files
177 match._files = [f for f in match._files
178 if sfindirstate(f)]
178 if sfindirstate(f)]
179 # Don't waste time getting the ignored and unknown
179 # Don't waste time getting the ignored and unknown
180 # files again; we already have them
180 # files again; we already have them
181 s = lfdirstate.status(match, [], False,
181 s = lfdirstate.status(match, [], False,
182 listclean, False)
182 listclean, False)
183 (unsure, modified, added, removed, missing, unknown,
183 (unsure, modified, added, removed, missing, unknown,
184 ignored, clean) = s
184 ignored, clean) = s
185 # Replace the list of ignored and unknown files with
185 # Replace the list of ignored and unknown files with
186 # the previously caclulated lists, and strip out the
186 # the previously caclulated lists, and strip out the
187 # largefiles
187 # largefiles
188 lfiles = set(lfdirstate._map)
188 lfiles = set(lfdirstate._map)
189 ignored = set(result[5]).difference(lfiles)
189 ignored = set(result[5]).difference(lfiles)
190 unknown = set(result[4]).difference(lfiles)
190 unknown = set(result[4]).difference(lfiles)
191 if parentworking:
191 if parentworking:
192 for lfile in unsure:
192 for lfile in unsure:
193 standin = lfutil.standin(lfile)
193 standin = lfutil.standin(lfile)
194 if standin not in ctx1:
194 if standin not in ctx1:
195 # from second parent
195 # from second parent
196 modified.append(lfile)
196 modified.append(lfile)
197 elif ctx1[standin].data().strip() \
197 elif ctx1[standin].data().strip() \
198 != lfutil.hashfile(self.wjoin(lfile)):
198 != lfutil.hashfile(self.wjoin(lfile)):
199 modified.append(lfile)
199 modified.append(lfile)
200 else:
200 else:
201 clean.append(lfile)
201 clean.append(lfile)
202 lfdirstate.normal(lfile)
202 lfdirstate.normal(lfile)
203 else:
203 else:
204 tocheck = unsure + modified + added + clean
204 tocheck = unsure + modified + added + clean
205 modified, added, clean = [], [], []
205 modified, added, clean = [], [], []
206
206
207 for lfile in tocheck:
207 for lfile in tocheck:
208 standin = lfutil.standin(lfile)
208 standin = lfutil.standin(lfile)
209 if inctx(standin, ctx1):
209 if inctx(standin, ctx1):
210 if ctx1[standin].data().strip() != \
210 if ctx1[standin].data().strip() != \
211 lfutil.hashfile(self.wjoin(lfile)):
211 lfutil.hashfile(self.wjoin(lfile)):
212 modified.append(lfile)
212 modified.append(lfile)
213 else:
213 else:
214 clean.append(lfile)
214 clean.append(lfile)
215 else:
215 else:
216 added.append(lfile)
216 added.append(lfile)
217 finally:
217 finally:
218 # Replace the original ignore function
218 # Replace the original ignore function
219 lfdirstate._ignore = origignore
219 lfdirstate._ignore = origignore
220
220
221 for standin in ctx1.manifest():
221 for standin in ctx1.manifest():
222 if not lfutil.isstandin(standin):
222 if not lfutil.isstandin(standin):
223 continue
223 continue
224 lfile = lfutil.splitstandin(standin)
224 lfile = lfutil.splitstandin(standin)
225 if not match(lfile):
225 if not match(lfile):
226 continue
226 continue
227 if lfile not in lfdirstate:
227 if lfile not in lfdirstate:
228 removed.append(lfile)
228 removed.append(lfile)
229
229
230 # Filter result lists
230 # Filter result lists
231 result = list(result)
231 result = list(result)
232
232
233 # Largefiles are not really removed when they're
233 # Largefiles are not really removed when they're
234 # still in the normal dirstate. Likewise, normal
234 # still in the normal dirstate. Likewise, normal
235 # files are not really removed if it's still in
235 # files are not really removed if it's still in
236 # lfdirstate. This happens in merges where files
236 # lfdirstate. This happens in merges where files
237 # change type.
237 # change type.
238 removed = [f for f in removed if f not in repo.dirstate]
238 removed = [f for f in removed if f not in repo.dirstate]
239 result[2] = [f for f in result[2] if f not in lfdirstate]
239 result[2] = [f for f in result[2] if f not in lfdirstate]
240
240
241 # Unknown files
241 # Unknown files
242 unknown = set(unknown).difference(ignored)
242 unknown = set(unknown).difference(ignored)
243 result[4] = [f for f in unknown
243 result[4] = [f for f in unknown
244 if (repo.dirstate[f] == '?' and
244 if (repo.dirstate[f] == '?' and
245 not lfutil.isstandin(f))]
245 not lfutil.isstandin(f))]
246 # Ignored files were calculated earlier by the dirstate,
246 # Ignored files were calculated earlier by the dirstate,
247 # and we already stripped out the largefiles from the list
247 # and we already stripped out the largefiles from the list
248 result[5] = ignored
248 result[5] = ignored
249 # combine normal files and largefiles
249 # combine normal files and largefiles
250 normals = [[fn for fn in filelist
250 normals = [[fn for fn in filelist
251 if not lfutil.isstandin(fn)]
251 if not lfutil.isstandin(fn)]
252 for filelist in result]
252 for filelist in result]
253 lfiles = (modified, added, removed, missing, [], [], clean)
253 lfiles = (modified, added, removed, missing, [], [], clean)
254 result = [sorted(list1 + list2)
254 result = [sorted(list1 + list2)
255 for (list1, list2) in zip(normals, lfiles)]
255 for (list1, list2) in zip(normals, lfiles)]
256 else:
256 else:
257 def toname(f):
257 def toname(f):
258 if lfutil.isstandin(f):
258 if lfutil.isstandin(f):
259 return lfutil.splitstandin(f)
259 return lfutil.splitstandin(f)
260 return f
260 return f
261 result = [[toname(f) for f in items] for items in result]
261 result = [[toname(f) for f in items] for items in result]
262
262
263 if not listunknown:
263 if not listunknown:
264 result[4] = []
264 result[4] = []
265 if not listignored:
265 if not listignored:
266 result[5] = []
266 result[5] = []
267 if not listclean:
267 if not listclean:
268 result[6] = []
268 result[6] = []
269 self.lfstatus = True
269 self.lfstatus = True
270 return result
270 return result
271
271
272 # As part of committing, copy all of the largefiles into the
272 # As part of committing, copy all of the largefiles into the
273 # cache.
273 # cache.
274 def commitctx(self, *args, **kwargs):
274 def commitctx(self, *args, **kwargs):
275 node = super(lfilesrepo, self).commitctx(*args, **kwargs)
275 node = super(lfilesrepo, self).commitctx(*args, **kwargs)
276 lfutil.copyalltostore(self, node)
276 lfutil.copyalltostore(self, node)
277 return node
277 return node
278
278
279 # Before commit, largefile standins have not had their
279 # Before commit, largefile standins have not had their
280 # contents updated to reflect the hash of their largefile.
280 # contents updated to reflect the hash of their largefile.
281 # Do that here.
281 # Do that here.
282 def commit(self, text="", user=None, date=None, match=None,
282 def commit(self, text="", user=None, date=None, match=None,
283 force=False, editor=False, extra={}):
283 force=False, editor=False, extra={}):
284 orig = super(lfilesrepo, self).commit
284 orig = super(lfilesrepo, self).commit
285
285
286 wlock = repo.wlock()
286 wlock = repo.wlock()
287 try:
287 try:
288 # Case 0: Rebase or Transplant
288 # Case 0: Rebase or Transplant
289 # We have to take the time to pull down the new largefiles now.
289 # We have to take the time to pull down the new largefiles now.
290 # Otherwise, any largefiles that were modified in the
290 # Otherwise, any largefiles that were modified in the
291 # destination changesets get overwritten, either by the rebase
291 # destination changesets get overwritten, either by the rebase
292 # or in the first commit after the rebase or transplant.
292 # or in the first commit after the rebase or transplant.
293 # updatelfiles will update the dirstate to mark any pulled
293 # updatelfiles will update the dirstate to mark any pulled
294 # largefiles as modified
294 # largefiles as modified
295 if getattr(repo, "_isrebasing", False) or \
295 if getattr(repo, "_isrebasing", False) or \
296 getattr(repo, "_istransplanting", False):
296 getattr(repo, "_istransplanting", False):
297 lfcommands.updatelfiles(repo.ui, repo, filelist=None,
297 lfcommands.updatelfiles(repo.ui, repo, filelist=None,
298 printmessage=False)
298 printmessage=False)
299 result = orig(text=text, user=user, date=date, match=match,
299 result = orig(text=text, user=user, date=date, match=match,
300 force=force, editor=editor, extra=extra)
300 force=force, editor=editor, extra=extra)
301 return result
301 return result
302 # Case 1: user calls commit with no specific files or
302 # Case 1: user calls commit with no specific files or
303 # include/exclude patterns: refresh and commit all files that
303 # include/exclude patterns: refresh and commit all files that
304 # are "dirty".
304 # are "dirty".
305 if ((match is None) or
305 if ((match is None) or
306 (not match.anypats() and not match.files())):
306 (not match.anypats() and not match.files())):
307 # Spend a bit of time here to get a list of files we know
307 # Spend a bit of time here to get a list of files we know
308 # are modified so we can compare only against those.
308 # are modified so we can compare only against those.
309 # It can cost a lot of time (several seconds)
309 # It can cost a lot of time (several seconds)
310 # otherwise to update all standins if the largefiles are
310 # otherwise to update all standins if the largefiles are
311 # large.
311 # large.
312 lfdirstate = lfutil.openlfdirstate(ui, self)
312 lfdirstate = lfutil.openlfdirstate(ui, self)
313 dirtymatch = match_.always(repo.root, repo.getcwd())
313 dirtymatch = match_.always(repo.root, repo.getcwd())
314 s = lfdirstate.status(dirtymatch, [], False, False, False)
314 s = lfdirstate.status(dirtymatch, [], False, False, False)
315 modifiedfiles = []
315 modifiedfiles = []
316 for i in s:
316 for i in s:
317 modifiedfiles.extend(i)
317 modifiedfiles.extend(i)
318 lfiles = lfutil.listlfiles(self)
318 lfiles = lfutil.listlfiles(self)
319 # this only loops through largefiles that exist (not
319 # this only loops through largefiles that exist (not
320 # removed/renamed)
320 # removed/renamed)
321 for lfile in lfiles:
321 for lfile in lfiles:
322 if lfile in modifiedfiles:
322 if lfile in modifiedfiles:
323 if os.path.exists(
323 if os.path.exists(
324 self.wjoin(lfutil.standin(lfile))):
324 self.wjoin(lfutil.standin(lfile))):
325 # this handles the case where a rebase is being
325 # this handles the case where a rebase is being
326 # performed and the working copy is not updated
326 # performed and the working copy is not updated
327 # yet.
327 # yet.
328 if os.path.exists(self.wjoin(lfile)):
328 if os.path.exists(self.wjoin(lfile)):
329 lfutil.updatestandin(self,
329 lfutil.updatestandin(self,
330 lfutil.standin(lfile))
330 lfutil.standin(lfile))
331 lfdirstate.normal(lfile)
331 lfdirstate.normal(lfile)
332 for lfile in lfdirstate:
332 for lfile in lfdirstate:
333 if lfile in modifiedfiles:
333 if lfile in modifiedfiles:
334 if not os.path.exists(
334 if not os.path.exists(
335 repo.wjoin(lfutil.standin(lfile))):
335 repo.wjoin(lfutil.standin(lfile))):
336 lfdirstate.drop(lfile)
336 lfdirstate.drop(lfile)
337
337
338 result = orig(text=text, user=user, date=date, match=match,
338 result = orig(text=text, user=user, date=date, match=match,
339 force=force, editor=editor, extra=extra)
339 force=force, editor=editor, extra=extra)
340 # This needs to be after commit; otherwise precommit hooks
340 # This needs to be after commit; otherwise precommit hooks
341 # get the wrong status
341 # get the wrong status
342 lfdirstate.write()
342 lfdirstate.write()
343 return result
343 return result
344
344
345 for f in match.files():
345 for f in match.files():
346 if lfutil.isstandin(f):
346 if lfutil.isstandin(f):
347 raise util.Abort(
347 raise util.Abort(
348 _('file "%s" is a largefile standin') % f,
348 _('file "%s" is a largefile standin') % f,
349 hint=('commit the largefile itself instead'))
349 hint=('commit the largefile itself instead'))
350
350
351 # Case 2: user calls commit with specified patterns: refresh
351 # Case 2: user calls commit with specified patterns: refresh
352 # any matching big files.
352 # any matching big files.
353 smatcher = lfutil.composestandinmatcher(self, match)
353 smatcher = lfutil.composestandinmatcher(self, match)
354 standins = lfutil.dirstatewalk(self.dirstate, smatcher)
354 standins = lfutil.dirstatewalk(self.dirstate, smatcher)
355
355
356 # No matching big files: get out of the way and pass control to
356 # No matching big files: get out of the way and pass control to
357 # the usual commit() method.
357 # the usual commit() method.
358 if not standins:
358 if not standins:
359 return orig(text=text, user=user, date=date, match=match,
359 return orig(text=text, user=user, date=date, match=match,
360 force=force, editor=editor, extra=extra)
360 force=force, editor=editor, extra=extra)
361
361
362 # Refresh all matching big files. It's possible that the
362 # Refresh all matching big files. It's possible that the
363 # commit will end up failing, in which case the big files will
363 # commit will end up failing, in which case the big files will
364 # stay refreshed. No harm done: the user modified them and
364 # stay refreshed. No harm done: the user modified them and
365 # asked to commit them, so sooner or later we're going to
365 # asked to commit them, so sooner or later we're going to
366 # refresh the standins. Might as well leave them refreshed.
366 # refresh the standins. Might as well leave them refreshed.
367 lfdirstate = lfutil.openlfdirstate(ui, self)
367 lfdirstate = lfutil.openlfdirstate(ui, self)
368 for standin in standins:
368 for standin in standins:
369 lfile = lfutil.splitstandin(standin)
369 lfile = lfutil.splitstandin(standin)
370 if lfdirstate[lfile] <> 'r':
370 if lfdirstate[lfile] <> 'r':
371 lfutil.updatestandin(self, standin)
371 lfutil.updatestandin(self, standin)
372 lfdirstate.normal(lfile)
372 lfdirstate.normal(lfile)
373 else:
373 else:
374 lfdirstate.drop(lfile)
374 lfdirstate.drop(lfile)
375
375
376 # Cook up a new matcher that only matches regular files or
376 # Cook up a new matcher that only matches regular files or
377 # standins corresponding to the big files requested by the
377 # standins corresponding to the big files requested by the
378 # user. Have to modify _files to prevent commit() from
378 # user. Have to modify _files to prevent commit() from
379 # complaining "not tracked" for big files.
379 # complaining "not tracked" for big files.
380 lfiles = lfutil.listlfiles(repo)
380 lfiles = lfutil.listlfiles(repo)
381 match = copy.copy(match)
381 match = copy.copy(match)
382 origmatchfn = match.matchfn
382 origmatchfn = match.matchfn
383
383
384 # Check both the list of largefiles and the list of
384 # Check both the list of largefiles and the list of
385 # standins because if a largefile was removed, it
385 # standins because if a largefile was removed, it
386 # won't be in the list of largefiles at this point
386 # won't be in the list of largefiles at this point
387 match._files += sorted(standins)
387 match._files += sorted(standins)
388
388
389 actualfiles = []
389 actualfiles = []
390 for f in match._files:
390 for f in match._files:
391 fstandin = lfutil.standin(f)
391 fstandin = lfutil.standin(f)
392
392
393 # ignore known largefiles and standins
393 # ignore known largefiles and standins
394 if f in lfiles or fstandin in standins:
394 if f in lfiles or fstandin in standins:
395 continue
395 continue
396
396
397 # append directory separator to avoid collisions
397 # append directory separator to avoid collisions
398 if not fstandin.endswith(os.sep):
398 if not fstandin.endswith(os.sep):
399 fstandin += os.sep
399 fstandin += os.sep
400
400
401 # prevalidate matching standin directories
402 if util.any(st for st in match._files
403 if st.startswith(fstandin)):
404 continue
405 actualfiles.append(f)
401 actualfiles.append(f)
406 match._files = actualfiles
402 match._files = actualfiles
407
403
408 def matchfn(f):
404 def matchfn(f):
409 if origmatchfn(f):
405 if origmatchfn(f):
410 return f not in lfiles
406 return f not in lfiles
411 else:
407 else:
412 return f in standins
408 return f in standins
413
409
414 match.matchfn = matchfn
410 match.matchfn = matchfn
415 result = orig(text=text, user=user, date=date, match=match,
411 result = orig(text=text, user=user, date=date, match=match,
416 force=force, editor=editor, extra=extra)
412 force=force, editor=editor, extra=extra)
417 # This needs to be after commit; otherwise precommit hooks
413 # This needs to be after commit; otherwise precommit hooks
418 # get the wrong status
414 # get the wrong status
419 lfdirstate.write()
415 lfdirstate.write()
420 return result
416 return result
421 finally:
417 finally:
422 wlock.release()
418 wlock.release()
423
419
424 def push(self, remote, force=False, revs=None, newbranch=False):
420 def push(self, remote, force=False, revs=None, newbranch=False):
425 o = lfutil.findoutgoing(repo, remote, force)
421 o = lfutil.findoutgoing(repo, remote, force)
426 if o:
422 if o:
427 toupload = set()
423 toupload = set()
428 o = repo.changelog.nodesbetween(o, revs)[0]
424 o = repo.changelog.nodesbetween(o, revs)[0]
429 for n in o:
425 for n in o:
430 parents = [p for p in repo.changelog.parents(n)
426 parents = [p for p in repo.changelog.parents(n)
431 if p != node_.nullid]
427 if p != node_.nullid]
432 ctx = repo[n]
428 ctx = repo[n]
433 files = set(ctx.files())
429 files = set(ctx.files())
434 if len(parents) == 2:
430 if len(parents) == 2:
435 mc = ctx.manifest()
431 mc = ctx.manifest()
436 mp1 = ctx.parents()[0].manifest()
432 mp1 = ctx.parents()[0].manifest()
437 mp2 = ctx.parents()[1].manifest()
433 mp2 = ctx.parents()[1].manifest()
438 for f in mp1:
434 for f in mp1:
439 if f not in mc:
435 if f not in mc:
440 files.add(f)
436 files.add(f)
441 for f in mp2:
437 for f in mp2:
442 if f not in mc:
438 if f not in mc:
443 files.add(f)
439 files.add(f)
444 for f in mc:
440 for f in mc:
445 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f,
441 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f,
446 None):
442 None):
447 files.add(f)
443 files.add(f)
448
444
449 toupload = toupload.union(
445 toupload = toupload.union(
450 set([ctx[f].data().strip()
446 set([ctx[f].data().strip()
451 for f in files
447 for f in files
452 if lfutil.isstandin(f) and f in ctx]))
448 if lfutil.isstandin(f) and f in ctx]))
453 lfcommands.uploadlfiles(ui, self, remote, toupload)
449 lfcommands.uploadlfiles(ui, self, remote, toupload)
454 return super(lfilesrepo, self).push(remote, force, revs,
450 return super(lfilesrepo, self).push(remote, force, revs,
455 newbranch)
451 newbranch)
456
452
457 repo.__class__ = lfilesrepo
453 repo.__class__ = lfilesrepo
458
454
459 def checkrequireslfiles(ui, repo, **kwargs):
455 def checkrequireslfiles(ui, repo, **kwargs):
460 if 'largefiles' not in repo.requirements and util.any(
456 if 'largefiles' not in repo.requirements and util.any(
461 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
457 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
462 repo.requirements.add('largefiles')
458 repo.requirements.add('largefiles')
463 repo._writerequirements()
459 repo._writerequirements()
464
460
465 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles)
461 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles)
466 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles)
462 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles)
@@ -1,242 +1,242 b''
1 # Mercurial bookmark support code
1 # Mercurial bookmark support code
2 #
2 #
3 # Copyright 2008 David Soria Parra <dsp@php.net>
3 # Copyright 2008 David Soria Parra <dsp@php.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from mercurial.i18n import _
8 from mercurial.i18n import _
9 from mercurial.node import hex
9 from mercurial.node import hex
10 from mercurial import encoding, error, util
10 from mercurial import encoding, util
11 import errno, os
11 import errno, os
12
12
13 def valid(mark):
13 def valid(mark):
14 for c in (':', '\0', '\n', '\r'):
14 for c in (':', '\0', '\n', '\r'):
15 if c in mark:
15 if c in mark:
16 return False
16 return False
17 return True
17 return True
18
18
19 def read(repo):
19 def read(repo):
20 '''Parse .hg/bookmarks file and return a dictionary
20 '''Parse .hg/bookmarks file and return a dictionary
21
21
22 Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
22 Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
23 in the .hg/bookmarks file.
23 in the .hg/bookmarks file.
24 Read the file and return a (name=>nodeid) dictionary
24 Read the file and return a (name=>nodeid) dictionary
25 '''
25 '''
26 bookmarks = {}
26 bookmarks = {}
27 try:
27 try:
28 for line in repo.opener('bookmarks'):
28 for line in repo.opener('bookmarks'):
29 line = line.strip()
29 line = line.strip()
30 if not line:
30 if not line:
31 continue
31 continue
32 if ' ' not in line:
32 if ' ' not in line:
33 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n') % line)
33 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n') % line)
34 continue
34 continue
35 sha, refspec = line.split(' ', 1)
35 sha, refspec = line.split(' ', 1)
36 refspec = encoding.tolocal(refspec)
36 refspec = encoding.tolocal(refspec)
37 try:
37 try:
38 bookmarks[refspec] = repo.changelog.lookup(sha)
38 bookmarks[refspec] = repo.changelog.lookup(sha)
39 except error.RepoLookupError:
39 except LookupError:
40 pass
40 pass
41 except IOError, inst:
41 except IOError, inst:
42 if inst.errno != errno.ENOENT:
42 if inst.errno != errno.ENOENT:
43 raise
43 raise
44 return bookmarks
44 return bookmarks
45
45
46 def readcurrent(repo):
46 def readcurrent(repo):
47 '''Get the current bookmark
47 '''Get the current bookmark
48
48
49 If we use gittishsh branches we have a current bookmark that
49 If we use gittishsh branches we have a current bookmark that
50 we are on. This function returns the name of the bookmark. It
50 we are on. This function returns the name of the bookmark. It
51 is stored in .hg/bookmarks.current
51 is stored in .hg/bookmarks.current
52 '''
52 '''
53 mark = None
53 mark = None
54 try:
54 try:
55 file = repo.opener('bookmarks.current')
55 file = repo.opener('bookmarks.current')
56 except IOError, inst:
56 except IOError, inst:
57 if inst.errno != errno.ENOENT:
57 if inst.errno != errno.ENOENT:
58 raise
58 raise
59 return None
59 return None
60 try:
60 try:
61 # No readline() in posixfile_nt, reading everything is cheap
61 # No readline() in posixfile_nt, reading everything is cheap
62 mark = encoding.tolocal((file.readlines() or [''])[0])
62 mark = encoding.tolocal((file.readlines() or [''])[0])
63 if mark == '' or mark not in repo._bookmarks:
63 if mark == '' or mark not in repo._bookmarks:
64 mark = None
64 mark = None
65 finally:
65 finally:
66 file.close()
66 file.close()
67 return mark
67 return mark
68
68
69 def write(repo):
69 def write(repo):
70 '''Write bookmarks
70 '''Write bookmarks
71
71
72 Write the given bookmark => hash dictionary to the .hg/bookmarks file
72 Write the given bookmark => hash dictionary to the .hg/bookmarks file
73 in a format equal to those of localtags.
73 in a format equal to those of localtags.
74
74
75 We also store a backup of the previous state in undo.bookmarks that
75 We also store a backup of the previous state in undo.bookmarks that
76 can be copied back on rollback.
76 can be copied back on rollback.
77 '''
77 '''
78 refs = repo._bookmarks
78 refs = repo._bookmarks
79
79
80 if repo._bookmarkcurrent not in refs:
80 if repo._bookmarkcurrent not in refs:
81 setcurrent(repo, None)
81 setcurrent(repo, None)
82 for mark in refs.keys():
82 for mark in refs.keys():
83 if not valid(mark):
83 if not valid(mark):
84 raise util.Abort(_("bookmark '%s' contains illegal "
84 raise util.Abort(_("bookmark '%s' contains illegal "
85 "character" % mark))
85 "character" % mark))
86
86
87 wlock = repo.wlock()
87 wlock = repo.wlock()
88 try:
88 try:
89
89
90 file = repo.opener('bookmarks', 'w', atomictemp=True)
90 file = repo.opener('bookmarks', 'w', atomictemp=True)
91 for refspec, node in refs.iteritems():
91 for refspec, node in refs.iteritems():
92 file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec)))
92 file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec)))
93 file.close()
93 file.close()
94
94
95 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
95 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
96 try:
96 try:
97 os.utime(repo.sjoin('00changelog.i'), None)
97 os.utime(repo.sjoin('00changelog.i'), None)
98 except OSError:
98 except OSError:
99 pass
99 pass
100
100
101 finally:
101 finally:
102 wlock.release()
102 wlock.release()
103
103
104 def setcurrent(repo, mark):
104 def setcurrent(repo, mark):
105 '''Set the name of the bookmark that we are currently on
105 '''Set the name of the bookmark that we are currently on
106
106
107 Set the name of the bookmark that we are on (hg update <bookmark>).
107 Set the name of the bookmark that we are on (hg update <bookmark>).
108 The name is recorded in .hg/bookmarks.current
108 The name is recorded in .hg/bookmarks.current
109 '''
109 '''
110 current = repo._bookmarkcurrent
110 current = repo._bookmarkcurrent
111 if current == mark:
111 if current == mark:
112 return
112 return
113
113
114 if mark not in repo._bookmarks:
114 if mark not in repo._bookmarks:
115 mark = ''
115 mark = ''
116 if not valid(mark):
116 if not valid(mark):
117 raise util.Abort(_("bookmark '%s' contains illegal "
117 raise util.Abort(_("bookmark '%s' contains illegal "
118 "character" % mark))
118 "character" % mark))
119
119
120 wlock = repo.wlock()
120 wlock = repo.wlock()
121 try:
121 try:
122 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
122 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
123 file.write(encoding.fromlocal(mark))
123 file.write(encoding.fromlocal(mark))
124 file.close()
124 file.close()
125 finally:
125 finally:
126 wlock.release()
126 wlock.release()
127 repo._bookmarkcurrent = mark
127 repo._bookmarkcurrent = mark
128
128
129 def unsetcurrent(repo):
129 def unsetcurrent(repo):
130 wlock = repo.wlock()
130 wlock = repo.wlock()
131 try:
131 try:
132 try:
132 try:
133 util.unlink(repo.join('bookmarks.current'))
133 util.unlink(repo.join('bookmarks.current'))
134 repo._bookmarkcurrent = None
134 repo._bookmarkcurrent = None
135 except OSError, inst:
135 except OSError, inst:
136 if inst.errno != errno.ENOENT:
136 if inst.errno != errno.ENOENT:
137 raise
137 raise
138 finally:
138 finally:
139 wlock.release()
139 wlock.release()
140
140
141 def updatecurrentbookmark(repo, oldnode, curbranch):
141 def updatecurrentbookmark(repo, oldnode, curbranch):
142 try:
142 try:
143 return update(repo, oldnode, repo.branchtags()[curbranch])
143 return update(repo, oldnode, repo.branchtags()[curbranch])
144 except KeyError:
144 except KeyError:
145 if curbranch == "default": # no default branch!
145 if curbranch == "default": # no default branch!
146 return update(repo, oldnode, repo.lookup("tip"))
146 return update(repo, oldnode, repo.lookup("tip"))
147 else:
147 else:
148 raise util.Abort(_("branch %s not found") % curbranch)
148 raise util.Abort(_("branch %s not found") % curbranch)
149
149
150 def update(repo, parents, node):
150 def update(repo, parents, node):
151 marks = repo._bookmarks
151 marks = repo._bookmarks
152 update = False
152 update = False
153 mark = repo._bookmarkcurrent
153 mark = repo._bookmarkcurrent
154 if mark and marks[mark] in parents:
154 if mark and marks[mark] in parents:
155 old = repo[marks[mark]]
155 old = repo[marks[mark]]
156 new = repo[node]
156 new = repo[node]
157 if new in old.descendants():
157 if new in old.descendants():
158 marks[mark] = new.node()
158 marks[mark] = new.node()
159 update = True
159 update = True
160 if update:
160 if update:
161 repo._writebookmarks(marks)
161 repo._writebookmarks(marks)
162 return update
162 return update
163
163
164 def listbookmarks(repo):
164 def listbookmarks(repo):
165 # We may try to list bookmarks on a repo type that does not
165 # We may try to list bookmarks on a repo type that does not
166 # support it (e.g., statichttprepository).
166 # support it (e.g., statichttprepository).
167 marks = getattr(repo, '_bookmarks', {})
167 marks = getattr(repo, '_bookmarks', {})
168
168
169 d = {}
169 d = {}
170 for k, v in marks.iteritems():
170 for k, v in marks.iteritems():
171 # don't expose local divergent bookmarks
171 # don't expose local divergent bookmarks
172 if '@' not in k or k.endswith('@'):
172 if '@' not in k or k.endswith('@'):
173 d[k] = hex(v)
173 d[k] = hex(v)
174 return d
174 return d
175
175
176 def pushbookmark(repo, key, old, new):
176 def pushbookmark(repo, key, old, new):
177 w = repo.wlock()
177 w = repo.wlock()
178 try:
178 try:
179 marks = repo._bookmarks
179 marks = repo._bookmarks
180 if hex(marks.get(key, '')) != old:
180 if hex(marks.get(key, '')) != old:
181 return False
181 return False
182 if new == '':
182 if new == '':
183 del marks[key]
183 del marks[key]
184 else:
184 else:
185 if new not in repo:
185 if new not in repo:
186 return False
186 return False
187 marks[key] = repo[new].node()
187 marks[key] = repo[new].node()
188 write(repo)
188 write(repo)
189 return True
189 return True
190 finally:
190 finally:
191 w.release()
191 w.release()
192
192
193 def updatefromremote(ui, repo, remote, path):
193 def updatefromremote(ui, repo, remote, path):
194 ui.debug("checking for updated bookmarks\n")
194 ui.debug("checking for updated bookmarks\n")
195 rb = remote.listkeys('bookmarks')
195 rb = remote.listkeys('bookmarks')
196 changed = False
196 changed = False
197 for k in rb.keys():
197 for k in rb.keys():
198 if k in repo._bookmarks:
198 if k in repo._bookmarks:
199 nr, nl = rb[k], repo._bookmarks[k]
199 nr, nl = rb[k], repo._bookmarks[k]
200 if nr in repo:
200 if nr in repo:
201 cr = repo[nr]
201 cr = repo[nr]
202 cl = repo[nl]
202 cl = repo[nl]
203 if cl.rev() >= cr.rev():
203 if cl.rev() >= cr.rev():
204 continue
204 continue
205 if cr in cl.descendants():
205 if cr in cl.descendants():
206 repo._bookmarks[k] = cr.node()
206 repo._bookmarks[k] = cr.node()
207 changed = True
207 changed = True
208 ui.status(_("updating bookmark %s\n") % k)
208 ui.status(_("updating bookmark %s\n") % k)
209 else:
209 else:
210 # find a unique @ suffix
210 # find a unique @ suffix
211 for x in range(1, 100):
211 for x in range(1, 100):
212 n = '%s@%d' % (k, x)
212 n = '%s@%d' % (k, x)
213 if n not in repo._bookmarks:
213 if n not in repo._bookmarks:
214 break
214 break
215 # try to use an @pathalias suffix
215 # try to use an @pathalias suffix
216 # if an @pathalias already exists, we overwrite (update) it
216 # if an @pathalias already exists, we overwrite (update) it
217 for p, u in ui.configitems("paths"):
217 for p, u in ui.configitems("paths"):
218 if path == u:
218 if path == u:
219 n = '%s@%s' % (k, p)
219 n = '%s@%s' % (k, p)
220
220
221 repo._bookmarks[n] = cr.node()
221 repo._bookmarks[n] = cr.node()
222 changed = True
222 changed = True
223 ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
223 ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
224
224
225 if changed:
225 if changed:
226 write(repo)
226 write(repo)
227
227
228 def diff(ui, repo, remote):
228 def diff(ui, repo, remote):
229 ui.status(_("searching for changed bookmarks\n"))
229 ui.status(_("searching for changed bookmarks\n"))
230
230
231 lmarks = repo.listkeys('bookmarks')
231 lmarks = repo.listkeys('bookmarks')
232 rmarks = remote.listkeys('bookmarks')
232 rmarks = remote.listkeys('bookmarks')
233
233
234 diff = sorted(set(rmarks) - set(lmarks))
234 diff = sorted(set(rmarks) - set(lmarks))
235 for k in diff:
235 for k in diff:
236 mark = ui.debugflag and rmarks[k] or rmarks[k][:12]
236 mark = ui.debugflag and rmarks[k] or rmarks[k][:12]
237 ui.write(" %-25s %s\n" % (k, mark))
237 ui.write(" %-25s %s\n" % (k, mark))
238
238
239 if len(diff) <= 0:
239 if len(diff) <= 0:
240 ui.status(_("no changed bookmarks found\n"))
240 ui.status(_("no changed bookmarks found\n"))
241 return 1
241 return 1
242 return 0
242 return 0
@@ -1,1424 +1,1433 b''
1 The Mercurial system uses a set of configuration files to control
1 The Mercurial system uses a set of configuration files to control
2 aspects of its behavior.
2 aspects of its behavior.
3
3
4 The configuration files use a simple ini-file format. A configuration
4 The configuration files use a simple ini-file format. A configuration
5 file consists of sections, led by a ``[section]`` header and followed
5 file consists of sections, led by a ``[section]`` header and followed
6 by ``name = value`` entries::
6 by ``name = value`` entries::
7
7
8 [ui]
8 [ui]
9 username = Firstname Lastname <firstname.lastname@example.net>
9 username = Firstname Lastname <firstname.lastname@example.net>
10 verbose = True
10 verbose = True
11
11
12 The above entries will be referred to as ``ui.username`` and
12 The above entries will be referred to as ``ui.username`` and
13 ``ui.verbose``, respectively. See the Syntax section below.
13 ``ui.verbose``, respectively. See the Syntax section below.
14
14
15 Files
15 Files
16 -----
16 -----
17
17
18 Mercurial reads configuration data from several files, if they exist.
18 Mercurial reads configuration data from several files, if they exist.
19 These files do not exist by default and you will have to create the
19 These files do not exist by default and you will have to create the
20 appropriate configuration files yourself: global configuration like
20 appropriate configuration files yourself: global configuration like
21 the username setting is typically put into
21 the username setting is typically put into
22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
24
24
25 The names of these files depend on the system on which Mercurial is
25 The names of these files depend on the system on which Mercurial is
26 installed. ``*.rc`` files from a single directory are read in
26 installed. ``*.rc`` files from a single directory are read in
27 alphabetical order, later ones overriding earlier ones. Where multiple
27 alphabetical order, later ones overriding earlier ones. Where multiple
28 paths are given below, settings from earlier paths override later
28 paths are given below, settings from earlier paths override later
29 ones.
29 ones.
30
30
31 | (All) ``<repo>/.hg/hgrc``
31 | (All) ``<repo>/.hg/hgrc``
32
32
33 Per-repository configuration options that only apply in a
33 Per-repository configuration options that only apply in a
34 particular repository. This file is not version-controlled, and
34 particular repository. This file is not version-controlled, and
35 will not get transferred during a "clone" operation. Options in
35 will not get transferred during a "clone" operation. Options in
36 this file override options in all other configuration files. On
36 this file override options in all other configuration files. On
37 Plan 9 and Unix, most of this file will be ignored if it doesn't
37 Plan 9 and Unix, most of this file will be ignored if it doesn't
38 belong to a trusted user or to a trusted group. See the documentation
38 belong to a trusted user or to a trusted group. See the documentation
39 for the ``[trusted]`` section below for more details.
39 for the ``[trusted]`` section below for more details.
40
40
41 | (Plan 9) ``$home/lib/hgrc``
41 | (Plan 9) ``$home/lib/hgrc``
42 | (Unix) ``$HOME/.hgrc``
42 | (Unix) ``$HOME/.hgrc``
43 | (Windows) ``%USERPROFILE%\.hgrc``
43 | (Windows) ``%USERPROFILE%\.hgrc``
44 | (Windows) ``%USERPROFILE%\Mercurial.ini``
44 | (Windows) ``%USERPROFILE%\Mercurial.ini``
45 | (Windows) ``%HOME%\.hgrc``
45 | (Windows) ``%HOME%\.hgrc``
46 | (Windows) ``%HOME%\Mercurial.ini``
46 | (Windows) ``%HOME%\Mercurial.ini``
47
47
48 Per-user configuration file(s), for the user running Mercurial. On
48 Per-user configuration file(s), for the user running Mercurial. On
49 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
49 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
50 files apply to all Mercurial commands executed by this user in any
50 files apply to all Mercurial commands executed by this user in any
51 directory. Options in these files override per-system and per-installation
51 directory. Options in these files override per-system and per-installation
52 options.
52 options.
53
53
54 | (Plan 9) ``/lib/mercurial/hgrc``
54 | (Plan 9) ``/lib/mercurial/hgrc``
55 | (Plan 9) ``/lib/mercurial/hgrc.d/*.rc``
55 | (Plan 9) ``/lib/mercurial/hgrc.d/*.rc``
56 | (Unix) ``/etc/mercurial/hgrc``
56 | (Unix) ``/etc/mercurial/hgrc``
57 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
57 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
58
58
59 Per-system configuration files, for the system on which Mercurial
59 Per-system configuration files, for the system on which Mercurial
60 is running. Options in these files apply to all Mercurial commands
60 is running. Options in these files apply to all Mercurial commands
61 executed by any user in any directory. Options in these files
61 executed by any user in any directory. Options in these files
62 override per-installation options.
62 override per-installation options.
63
63
64 | (Plan 9) ``<install-root>/lib/mercurial/hgrc``
64 | (Plan 9) ``<install-root>/lib/mercurial/hgrc``
65 | (Plan 9) ``<install-root>/lib/mercurial/hgrc.d/*.rc``
65 | (Plan 9) ``<install-root>/lib/mercurial/hgrc.d/*.rc``
66 | (Unix) ``<install-root>/etc/mercurial/hgrc``
66 | (Unix) ``<install-root>/etc/mercurial/hgrc``
67 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
67 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
68
68
69 Per-installation configuration files, searched for in the
69 Per-installation configuration files, searched for in the
70 directory where Mercurial is installed. ``<install-root>`` is the
70 directory where Mercurial is installed. ``<install-root>`` is the
71 parent directory of the **hg** executable (or symlink) being run. For
71 parent directory of the **hg** executable (or symlink) being run. For
72 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
72 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
73 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
73 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
74 to all Mercurial commands executed by any user in any directory.
74 to all Mercurial commands executed by any user in any directory.
75
75
76 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
76 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
77 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
77 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
78 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
78 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
79
79
80 Per-installation/system configuration files, for the system on
80 Per-installation/system configuration files, for the system on
81 which Mercurial is running. Options in these files apply to all
81 which Mercurial is running. Options in these files apply to all
82 Mercurial commands executed by any user in any directory. Registry
82 Mercurial commands executed by any user in any directory. Registry
83 keys contain PATH-like strings, every part of which must reference
83 keys contain PATH-like strings, every part of which must reference
84 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
84 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
85 be read. Mercurial checks each of these locations in the specified
85 be read. Mercurial checks each of these locations in the specified
86 order until one or more configuration files are detected. If the
86 order until one or more configuration files are detected. If the
87 pywin32 extensions are not installed, Mercurial will only look for
87 pywin32 extensions are not installed, Mercurial will only look for
88 site-wide configuration in ``C:\Mercurial\Mercurial.ini``.
88 site-wide configuration in ``C:\Mercurial\Mercurial.ini``.
89
89
90 Syntax
90 Syntax
91 ------
91 ------
92
92
93 A configuration file consists of sections, led by a ``[section]`` header
93 A configuration file consists of sections, led by a ``[section]`` header
94 and followed by ``name = value`` entries (sometimes called
94 and followed by ``name = value`` entries (sometimes called
95 ``configuration keys``)::
95 ``configuration keys``)::
96
96
97 [spam]
97 [spam]
98 eggs=ham
98 eggs=ham
99 green=
99 green=
100 eggs
100 eggs
101
101
102 Each line contains one entry. If the lines that follow are indented,
102 Each line contains one entry. If the lines that follow are indented,
103 they are treated as continuations of that entry. Leading whitespace is
103 they are treated as continuations of that entry. Leading whitespace is
104 removed from values. Empty lines are skipped. Lines beginning with
104 removed from values. Empty lines are skipped. Lines beginning with
105 ``#`` or ``;`` are ignored and may be used to provide comments.
105 ``#`` or ``;`` are ignored and may be used to provide comments.
106
106
107 Configuration keys can be set multiple times, in which case Mercurial
107 Configuration keys can be set multiple times, in which case Mercurial
108 will use the value that was configured last. As an example::
108 will use the value that was configured last. As an example::
109
109
110 [spam]
110 [spam]
111 eggs=large
111 eggs=large
112 ham=serrano
112 ham=serrano
113 eggs=small
113 eggs=small
114
114
115 This would set the configuration key named ``eggs`` to ``small``.
115 This would set the configuration key named ``eggs`` to ``small``.
116
116
117 It is also possible to define a section multiple times. A section can
117 It is also possible to define a section multiple times. A section can
118 be redefined on the same and/or on different configuration files. For
118 be redefined on the same and/or on different configuration files. For
119 example::
119 example::
120
120
121 [foo]
121 [foo]
122 eggs=large
122 eggs=large
123 ham=serrano
123 ham=serrano
124 eggs=small
124 eggs=small
125
125
126 [bar]
126 [bar]
127 eggs=ham
127 eggs=ham
128 green=
128 green=
129 eggs
129 eggs
130
130
131 [foo]
131 [foo]
132 ham=prosciutto
132 ham=prosciutto
133 eggs=medium
133 eggs=medium
134 bread=toasted
134 bread=toasted
135
135
136 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
136 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
137 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
137 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
138 respectively. As you can see there only thing that matters is the last
138 respectively. As you can see there only thing that matters is the last
139 value that was set for each of the configuration keys.
139 value that was set for each of the configuration keys.
140
140
141 If a configuration key is set multiple times in different
141 If a configuration key is set multiple times in different
142 configuration files the final value will depend on the order in which
142 configuration files the final value will depend on the order in which
143 the different configuration files are read, with settings from earlier
143 the different configuration files are read, with settings from earlier
144 paths overriding later ones as described on the ``Files`` section
144 paths overriding later ones as described on the ``Files`` section
145 above.
145 above.
146
146
147 A line of the form ``%include file`` will include ``file`` into the
147 A line of the form ``%include file`` will include ``file`` into the
148 current configuration file. The inclusion is recursive, which means
148 current configuration file. The inclusion is recursive, which means
149 that included files can include other files. Filenames are relative to
149 that included files can include other files. Filenames are relative to
150 the configuration file in which the ``%include`` directive is found.
150 the configuration file in which the ``%include`` directive is found.
151 Environment variables and ``~user`` constructs are expanded in
151 Environment variables and ``~user`` constructs are expanded in
152 ``file``. This lets you do something like::
152 ``file``. This lets you do something like::
153
153
154 %include ~/.hgrc.d/$HOST.rc
154 %include ~/.hgrc.d/$HOST.rc
155
155
156 to include a different configuration file on each computer you use.
156 to include a different configuration file on each computer you use.
157
157
158 A line with ``%unset name`` will remove ``name`` from the current
158 A line with ``%unset name`` will remove ``name`` from the current
159 section, if it has been set previously.
159 section, if it has been set previously.
160
160
161 The values are either free-form text strings, lists of text strings,
161 The values are either free-form text strings, lists of text strings,
162 or Boolean values. Boolean values can be set to true using any of "1",
162 or Boolean values. Boolean values can be set to true using any of "1",
163 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
163 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
164 (all case insensitive).
164 (all case insensitive).
165
165
166 List values are separated by whitespace or comma, except when values are
166 List values are separated by whitespace or comma, except when values are
167 placed in double quotation marks::
167 placed in double quotation marks::
168
168
169 allow_read = "John Doe, PhD", brian, betty
169 allow_read = "John Doe, PhD", brian, betty
170
170
171 Quotation marks can be escaped by prefixing them with a backslash. Only
171 Quotation marks can be escaped by prefixing them with a backslash. Only
172 quotation marks at the beginning of a word is counted as a quotation
172 quotation marks at the beginning of a word is counted as a quotation
173 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
173 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
174
174
175 Sections
175 Sections
176 --------
176 --------
177
177
178 This section describes the different sections that may appear in a
178 This section describes the different sections that may appear in a
179 Mercurial configuration file, the purpose of each section, its possible
179 Mercurial configuration file, the purpose of each section, its possible
180 keys, and their possible values.
180 keys, and their possible values.
181
181
182 ``alias``
182 ``alias``
183 """""""""
183 """""""""
184
184
185 Defines command aliases.
185 Defines command aliases.
186 Aliases allow you to define your own commands in terms of other
186 Aliases allow you to define your own commands in terms of other
187 commands (or aliases), optionally including arguments. Positional
187 commands (or aliases), optionally including arguments. Positional
188 arguments in the form of ``$1``, ``$2``, etc in the alias definition
188 arguments in the form of ``$1``, ``$2``, etc in the alias definition
189 are expanded by Mercurial before execution. Positional arguments not
189 are expanded by Mercurial before execution. Positional arguments not
190 already used by ``$N`` in the definition are put at the end of the
190 already used by ``$N`` in the definition are put at the end of the
191 command to be executed.
191 command to be executed.
192
192
193 Alias definitions consist of lines of the form::
193 Alias definitions consist of lines of the form::
194
194
195 <alias> = <command> [<argument>]...
195 <alias> = <command> [<argument>]...
196
196
197 For example, this definition::
197 For example, this definition::
198
198
199 latest = log --limit 5
199 latest = log --limit 5
200
200
201 creates a new command ``latest`` that shows only the five most recent
201 creates a new command ``latest`` that shows only the five most recent
202 changesets. You can define subsequent aliases using earlier ones::
202 changesets. You can define subsequent aliases using earlier ones::
203
203
204 stable5 = latest -b stable
204 stable5 = latest -b stable
205
205
206 .. note:: It is possible to create aliases with the same names as
206 .. note:: It is possible to create aliases with the same names as
207 existing commands, which will then override the original
207 existing commands, which will then override the original
208 definitions. This is almost always a bad idea!
208 definitions. This is almost always a bad idea!
209
209
210 An alias can start with an exclamation point (``!``) to make it a
210 An alias can start with an exclamation point (``!``) to make it a
211 shell alias. A shell alias is executed with the shell and will let you
211 shell alias. A shell alias is executed with the shell and will let you
212 run arbitrary commands. As an example, ::
212 run arbitrary commands. As an example, ::
213
213
214 echo = !echo $@
214 echo = !echo $@
215
215
216 will let you do ``hg echo foo`` to have ``foo`` printed in your
216 will let you do ``hg echo foo`` to have ``foo`` printed in your
217 terminal. A better example might be::
217 terminal. A better example might be::
218
218
219 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
219 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
220
220
221 which will make ``hg purge`` delete all unknown files in the
221 which will make ``hg purge`` delete all unknown files in the
222 repository in the same manner as the purge extension.
222 repository in the same manner as the purge extension.
223
223
224 Positional arguments like ``$1``, ``$2``, etc. in the alias definition
224 Positional arguments like ``$1``, ``$2``, etc. in the alias definition
225 expand to the command arguments. Unmatched arguments are
225 expand to the command arguments. Unmatched arguments are
226 removed. ``$0`` expands to the alias name and ``$@`` expands to all
226 removed. ``$0`` expands to the alias name and ``$@`` expands to all
227 arguments separated by a space. These expansions happen before the
227 arguments separated by a space. These expansions happen before the
228 command is passed to the shell.
228 command is passed to the shell.
229
229
230 Shell aliases are executed in an environment where ``$HG`` expands to
230 Shell aliases are executed in an environment where ``$HG`` expands to
231 the path of the Mercurial that was used to execute the alias. This is
231 the path of the Mercurial that was used to execute the alias. This is
232 useful when you want to call further Mercurial commands in a shell
232 useful when you want to call further Mercurial commands in a shell
233 alias, as was done above for the purge alias. In addition,
233 alias, as was done above for the purge alias. In addition,
234 ``$HG_ARGS`` expands to the arguments given to Mercurial. In the ``hg
234 ``$HG_ARGS`` expands to the arguments given to Mercurial. In the ``hg
235 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
235 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
236
236
237 .. note:: Some global configuration options such as ``-R`` are
237 .. note:: Some global configuration options such as ``-R`` are
238 processed before shell aliases and will thus not be passed to
238 processed before shell aliases and will thus not be passed to
239 aliases.
239 aliases.
240
240
241
241
242 ``annotate``
242 ``annotate``
243 """"""""""""
243 """"""""""""
244
244
245 Settings used when displaying file annotations. All values are
245 Settings used when displaying file annotations. All values are
246 Booleans and default to False. See ``diff`` section for related
246 Booleans and default to False. See ``diff`` section for related
247 options for the diff command.
247 options for the diff command.
248
248
249 ``ignorews``
249 ``ignorews``
250 Ignore white space when comparing lines.
250 Ignore white space when comparing lines.
251
251
252 ``ignorewsamount``
252 ``ignorewsamount``
253 Ignore changes in the amount of white space.
253 Ignore changes in the amount of white space.
254
254
255 ``ignoreblanklines``
255 ``ignoreblanklines``
256 Ignore changes whose lines are all blank.
256 Ignore changes whose lines are all blank.
257
257
258
258
259 ``auth``
259 ``auth``
260 """"""""
260 """"""""
261
261
262 Authentication credentials for HTTP authentication. This section
262 Authentication credentials for HTTP authentication. This section
263 allows you to store usernames and passwords for use when logging
263 allows you to store usernames and passwords for use when logging
264 *into* HTTP servers. See the ``[web]`` configuration section if
264 *into* HTTP servers. See the ``[web]`` configuration section if
265 you want to configure *who* can login to your HTTP server.
265 you want to configure *who* can login to your HTTP server.
266
266
267 Each line has the following format::
267 Each line has the following format::
268
268
269 <name>.<argument> = <value>
269 <name>.<argument> = <value>
270
270
271 where ``<name>`` is used to group arguments into authentication
271 where ``<name>`` is used to group arguments into authentication
272 entries. Example::
272 entries. Example::
273
273
274 foo.prefix = hg.intevation.org/mercurial
274 foo.prefix = hg.intevation.org/mercurial
275 foo.username = foo
275 foo.username = foo
276 foo.password = bar
276 foo.password = bar
277 foo.schemes = http https
277 foo.schemes = http https
278
278
279 bar.prefix = secure.example.org
279 bar.prefix = secure.example.org
280 bar.key = path/to/file.key
280 bar.key = path/to/file.key
281 bar.cert = path/to/file.cert
281 bar.cert = path/to/file.cert
282 bar.schemes = https
282 bar.schemes = https
283
283
284 Supported arguments:
284 Supported arguments:
285
285
286 ``prefix``
286 ``prefix``
287 Either ``*`` or a URI prefix with or without the scheme part.
287 Either ``*`` or a URI prefix with or without the scheme part.
288 The authentication entry with the longest matching prefix is used
288 The authentication entry with the longest matching prefix is used
289 (where ``*`` matches everything and counts as a match of length
289 (where ``*`` matches everything and counts as a match of length
290 1). If the prefix doesn't include a scheme, the match is performed
290 1). If the prefix doesn't include a scheme, the match is performed
291 against the URI with its scheme stripped as well, and the schemes
291 against the URI with its scheme stripped as well, and the schemes
292 argument, q.v., is then subsequently consulted.
292 argument, q.v., is then subsequently consulted.
293
293
294 ``username``
294 ``username``
295 Optional. Username to authenticate with. If not given, and the
295 Optional. Username to authenticate with. If not given, and the
296 remote site requires basic or digest authentication, the user will
296 remote site requires basic or digest authentication, the user will
297 be prompted for it. Environment variables are expanded in the
297 be prompted for it. Environment variables are expanded in the
298 username letting you do ``foo.username = $USER``. If the URI
298 username letting you do ``foo.username = $USER``. If the URI
299 includes a username, only ``[auth]`` entries with a matching
299 includes a username, only ``[auth]`` entries with a matching
300 username or without a username will be considered.
300 username or without a username will be considered.
301
301
302 ``password``
302 ``password``
303 Optional. Password to authenticate with. If not given, and the
303 Optional. Password to authenticate with. If not given, and the
304 remote site requires basic or digest authentication, the user
304 remote site requires basic or digest authentication, the user
305 will be prompted for it.
305 will be prompted for it.
306
306
307 ``key``
307 ``key``
308 Optional. PEM encoded client certificate key file. Environment
308 Optional. PEM encoded client certificate key file. Environment
309 variables are expanded in the filename.
309 variables are expanded in the filename.
310
310
311 ``cert``
311 ``cert``
312 Optional. PEM encoded client certificate chain file. Environment
312 Optional. PEM encoded client certificate chain file. Environment
313 variables are expanded in the filename.
313 variables are expanded in the filename.
314
314
315 ``schemes``
315 ``schemes``
316 Optional. Space separated list of URI schemes to use this
316 Optional. Space separated list of URI schemes to use this
317 authentication entry with. Only used if the prefix doesn't include
317 authentication entry with. Only used if the prefix doesn't include
318 a scheme. Supported schemes are http and https. They will match
318 a scheme. Supported schemes are http and https. They will match
319 static-http and static-https respectively, as well.
319 static-http and static-https respectively, as well.
320 Default: https.
320 Default: https.
321
321
322 If no suitable authentication entry is found, the user is prompted
322 If no suitable authentication entry is found, the user is prompted
323 for credentials as usual if required by the remote.
323 for credentials as usual if required by the remote.
324
324
325
325
326 ``decode/encode``
326 ``decode/encode``
327 """""""""""""""""
327 """""""""""""""""
328
328
329 Filters for transforming files on checkout/checkin. This would
329 Filters for transforming files on checkout/checkin. This would
330 typically be used for newline processing or other
330 typically be used for newline processing or other
331 localization/canonicalization of files.
331 localization/canonicalization of files.
332
332
333 Filters consist of a filter pattern followed by a filter command.
333 Filters consist of a filter pattern followed by a filter command.
334 Filter patterns are globs by default, rooted at the repository root.
334 Filter patterns are globs by default, rooted at the repository root.
335 For example, to match any file ending in ``.txt`` in the root
335 For example, to match any file ending in ``.txt`` in the root
336 directory only, use the pattern ``*.txt``. To match any file ending
336 directory only, use the pattern ``*.txt``. To match any file ending
337 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
337 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
338 For each file only the first matching filter applies.
338 For each file only the first matching filter applies.
339
339
340 The filter command can start with a specifier, either ``pipe:`` or
340 The filter command can start with a specifier, either ``pipe:`` or
341 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
341 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
342
342
343 A ``pipe:`` command must accept data on stdin and return the transformed
343 A ``pipe:`` command must accept data on stdin and return the transformed
344 data on stdout.
344 data on stdout.
345
345
346 Pipe example::
346 Pipe example::
347
347
348 [encode]
348 [encode]
349 # uncompress gzip files on checkin to improve delta compression
349 # uncompress gzip files on checkin to improve delta compression
350 # note: not necessarily a good idea, just an example
350 # note: not necessarily a good idea, just an example
351 *.gz = pipe: gunzip
351 *.gz = pipe: gunzip
352
352
353 [decode]
353 [decode]
354 # recompress gzip files when writing them to the working dir (we
354 # recompress gzip files when writing them to the working dir (we
355 # can safely omit "pipe:", because it's the default)
355 # can safely omit "pipe:", because it's the default)
356 *.gz = gzip
356 *.gz = gzip
357
357
358 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
358 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
359 with the name of a temporary file that contains the data to be
359 with the name of a temporary file that contains the data to be
360 filtered by the command. The string ``OUTFILE`` is replaced with the name
360 filtered by the command. The string ``OUTFILE`` is replaced with the name
361 of an empty temporary file, where the filtered data must be written by
361 of an empty temporary file, where the filtered data must be written by
362 the command.
362 the command.
363
363
364 .. note:: The tempfile mechanism is recommended for Windows systems,
364 .. note:: The tempfile mechanism is recommended for Windows systems,
365 where the standard shell I/O redirection operators often have
365 where the standard shell I/O redirection operators often have
366 strange effects and may corrupt the contents of your files.
366 strange effects and may corrupt the contents of your files.
367
367
368 This filter mechanism is used internally by the ``eol`` extension to
368 This filter mechanism is used internally by the ``eol`` extension to
369 translate line ending characters between Windows (CRLF) and Unix (LF)
369 translate line ending characters between Windows (CRLF) and Unix (LF)
370 format. We suggest you use the ``eol`` extension for convenience.
370 format. We suggest you use the ``eol`` extension for convenience.
371
371
372
372
373 ``defaults``
373 ``defaults``
374 """"""""""""
374 """"""""""""
375
375
376 (defaults are deprecated. Don't use them. Use aliases instead)
376 (defaults are deprecated. Don't use them. Use aliases instead)
377
377
378 Use the ``[defaults]`` section to define command defaults, i.e. the
378 Use the ``[defaults]`` section to define command defaults, i.e. the
379 default options/arguments to pass to the specified commands.
379 default options/arguments to pass to the specified commands.
380
380
381 The following example makes :hg:`log` run in verbose mode, and
381 The following example makes :hg:`log` run in verbose mode, and
382 :hg:`status` show only the modified files, by default::
382 :hg:`status` show only the modified files, by default::
383
383
384 [defaults]
384 [defaults]
385 log = -v
385 log = -v
386 status = -m
386 status = -m
387
387
388 The actual commands, instead of their aliases, must be used when
388 The actual commands, instead of their aliases, must be used when
389 defining command defaults. The command defaults will also be applied
389 defining command defaults. The command defaults will also be applied
390 to the aliases of the commands defined.
390 to the aliases of the commands defined.
391
391
392
392
393 ``diff``
393 ``diff``
394 """"""""
394 """"""""
395
395
396 Settings used when displaying diffs. Everything except for ``unified``
396 Settings used when displaying diffs. Everything except for ``unified``
397 is a Boolean and defaults to False. See ``annotate`` section for
397 is a Boolean and defaults to False. See ``annotate`` section for
398 related options for the annotate command.
398 related options for the annotate command.
399
399
400 ``git``
400 ``git``
401 Use git extended diff format.
401 Use git extended diff format.
402
402
403 ``nodates``
403 ``nodates``
404 Don't include dates in diff headers.
404 Don't include dates in diff headers.
405
405
406 ``showfunc``
406 ``showfunc``
407 Show which function each change is in.
407 Show which function each change is in.
408
408
409 ``ignorews``
409 ``ignorews``
410 Ignore white space when comparing lines.
410 Ignore white space when comparing lines.
411
411
412 ``ignorewsamount``
412 ``ignorewsamount``
413 Ignore changes in the amount of white space.
413 Ignore changes in the amount of white space.
414
414
415 ``ignoreblanklines``
415 ``ignoreblanklines``
416 Ignore changes whose lines are all blank.
416 Ignore changes whose lines are all blank.
417
417
418 ``unified``
418 ``unified``
419 Number of lines of context to show.
419 Number of lines of context to show.
420
420
421 ``email``
421 ``email``
422 """""""""
422 """""""""
423
423
424 Settings for extensions that send email messages.
424 Settings for extensions that send email messages.
425
425
426 ``from``
426 ``from``
427 Optional. Email address to use in "From" header and SMTP envelope
427 Optional. Email address to use in "From" header and SMTP envelope
428 of outgoing messages.
428 of outgoing messages.
429
429
430 ``to``
430 ``to``
431 Optional. Comma-separated list of recipients' email addresses.
431 Optional. Comma-separated list of recipients' email addresses.
432
432
433 ``cc``
433 ``cc``
434 Optional. Comma-separated list of carbon copy recipients'
434 Optional. Comma-separated list of carbon copy recipients'
435 email addresses.
435 email addresses.
436
436
437 ``bcc``
437 ``bcc``
438 Optional. Comma-separated list of blind carbon copy recipients'
438 Optional. Comma-separated list of blind carbon copy recipients'
439 email addresses.
439 email addresses.
440
440
441 ``method``
441 ``method``
442 Optional. Method to use to send email messages. If value is ``smtp``
442 Optional. Method to use to send email messages. If value is ``smtp``
443 (default), use SMTP (see the ``[smtp]`` section for configuration).
443 (default), use SMTP (see the ``[smtp]`` section for configuration).
444 Otherwise, use as name of program to run that acts like sendmail
444 Otherwise, use as name of program to run that acts like sendmail
445 (takes ``-f`` option for sender, list of recipients on command line,
445 (takes ``-f`` option for sender, list of recipients on command line,
446 message on stdin). Normally, setting this to ``sendmail`` or
446 message on stdin). Normally, setting this to ``sendmail`` or
447 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
447 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
448
448
449 ``charsets``
449 ``charsets``
450 Optional. Comma-separated list of character sets considered
450 Optional. Comma-separated list of character sets considered
451 convenient for recipients. Addresses, headers, and parts not
451 convenient for recipients. Addresses, headers, and parts not
452 containing patches of outgoing messages will be encoded in the
452 containing patches of outgoing messages will be encoded in the
453 first character set to which conversion from local encoding
453 first character set to which conversion from local encoding
454 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
454 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
455 conversion fails, the text in question is sent as is. Defaults to
455 conversion fails, the text in question is sent as is. Defaults to
456 empty (explicit) list.
456 empty (explicit) list.
457
457
458 Order of outgoing email character sets:
458 Order of outgoing email character sets:
459
459
460 1. ``us-ascii``: always first, regardless of settings
460 1. ``us-ascii``: always first, regardless of settings
461 2. ``email.charsets``: in order given by user
461 2. ``email.charsets``: in order given by user
462 3. ``ui.fallbackencoding``: if not in email.charsets
462 3. ``ui.fallbackencoding``: if not in email.charsets
463 4. ``$HGENCODING``: if not in email.charsets
463 4. ``$HGENCODING``: if not in email.charsets
464 5. ``utf-8``: always last, regardless of settings
464 5. ``utf-8``: always last, regardless of settings
465
465
466 Email example::
466 Email example::
467
467
468 [email]
468 [email]
469 from = Joseph User <joe.user@example.com>
469 from = Joseph User <joe.user@example.com>
470 method = /usr/sbin/sendmail
470 method = /usr/sbin/sendmail
471 # charsets for western Europeans
471 # charsets for western Europeans
472 # us-ascii, utf-8 omitted, as they are tried first and last
472 # us-ascii, utf-8 omitted, as they are tried first and last
473 charsets = iso-8859-1, iso-8859-15, windows-1252
473 charsets = iso-8859-1, iso-8859-15, windows-1252
474
474
475
475
476 ``extensions``
476 ``extensions``
477 """"""""""""""
477 """"""""""""""
478
478
479 Mercurial has an extension mechanism for adding new features. To
479 Mercurial has an extension mechanism for adding new features. To
480 enable an extension, create an entry for it in this section.
480 enable an extension, create an entry for it in this section.
481
481
482 If you know that the extension is already in Python's search path,
482 If you know that the extension is already in Python's search path,
483 you can give the name of the module, followed by ``=``, with nothing
483 you can give the name of the module, followed by ``=``, with nothing
484 after the ``=``.
484 after the ``=``.
485
485
486 Otherwise, give a name that you choose, followed by ``=``, followed by
486 Otherwise, give a name that you choose, followed by ``=``, followed by
487 the path to the ``.py`` file (including the file name extension) that
487 the path to the ``.py`` file (including the file name extension) that
488 defines the extension.
488 defines the extension.
489
489
490 To explicitly disable an extension that is enabled in an hgrc of
490 To explicitly disable an extension that is enabled in an hgrc of
491 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
491 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
492 or ``foo = !`` when path is not supplied.
492 or ``foo = !`` when path is not supplied.
493
493
494 Example for ``~/.hgrc``::
494 Example for ``~/.hgrc``::
495
495
496 [extensions]
496 [extensions]
497 # (the mq extension will get loaded from Mercurial's path)
497 # (the mq extension will get loaded from Mercurial's path)
498 mq =
498 mq =
499 # (this extension will get loaded from the file specified)
499 # (this extension will get loaded from the file specified)
500 myfeature = ~/.hgext/myfeature.py
500 myfeature = ~/.hgext/myfeature.py
501
501
502
502
503 ``format``
503 ``format``
504 """"""""""
504 """"""""""
505
505
506 ``usestore``
506 ``usestore``
507 Enable or disable the "store" repository format which improves
507 Enable or disable the "store" repository format which improves
508 compatibility with systems that fold case or otherwise mangle
508 compatibility with systems that fold case or otherwise mangle
509 filenames. Enabled by default. Disabling this option will allow
509 filenames. Enabled by default. Disabling this option will allow
510 you to store longer filenames in some situations at the expense of
510 you to store longer filenames in some situations at the expense of
511 compatibility and ensures that the on-disk format of newly created
511 compatibility and ensures that the on-disk format of newly created
512 repositories will be compatible with Mercurial before version 0.9.4.
512 repositories will be compatible with Mercurial before version 0.9.4.
513
513
514 ``usefncache``
514 ``usefncache``
515 Enable or disable the "fncache" repository format which enhances
515 Enable or disable the "fncache" repository format which enhances
516 the "store" repository format (which has to be enabled to use
516 the "store" repository format (which has to be enabled to use
517 fncache) to allow longer filenames and avoids using Windows
517 fncache) to allow longer filenames and avoids using Windows
518 reserved names, e.g. "nul". Enabled by default. Disabling this
518 reserved names, e.g. "nul". Enabled by default. Disabling this
519 option ensures that the on-disk format of newly created
519 option ensures that the on-disk format of newly created
520 repositories will be compatible with Mercurial before version 1.1.
520 repositories will be compatible with Mercurial before version 1.1.
521
521
522 ``dotencode``
522 ``dotencode``
523 Enable or disable the "dotencode" repository format which enhances
523 Enable or disable the "dotencode" repository format which enhances
524 the "fncache" repository format (which has to be enabled to use
524 the "fncache" repository format (which has to be enabled to use
525 dotencode) to avoid issues with filenames starting with ._ on
525 dotencode) to avoid issues with filenames starting with ._ on
526 Mac OS X and spaces on Windows. Enabled by default. Disabling this
526 Mac OS X and spaces on Windows. Enabled by default. Disabling this
527 option ensures that the on-disk format of newly created
527 option ensures that the on-disk format of newly created
528 repositories will be compatible with Mercurial before version 1.7.
528 repositories will be compatible with Mercurial before version 1.7.
529
529
530 ``graph``
530 ``graph``
531 """""""""
531 """""""""
532
532
533 Web graph view configuration. This section let you change graph
533 Web graph view configuration. This section let you change graph
534 elements display properties by branches, for instance to make the
534 elements display properties by branches, for instance to make the
535 ``default`` branch stand out.
535 ``default`` branch stand out.
536
536
537 Each line has the following format::
537 Each line has the following format::
538
538
539 <branch>.<argument> = <value>
539 <branch>.<argument> = <value>
540
540
541 where ``<branch>`` is the name of the branch being
541 where ``<branch>`` is the name of the branch being
542 customized. Example::
542 customized. Example::
543
543
544 [graph]
544 [graph]
545 # 2px width
545 # 2px width
546 default.width = 2
546 default.width = 2
547 # red color
547 # red color
548 default.color = FF0000
548 default.color = FF0000
549
549
550 Supported arguments:
550 Supported arguments:
551
551
552 ``width``
552 ``width``
553 Set branch edges width in pixels.
553 Set branch edges width in pixels.
554
554
555 ``color``
555 ``color``
556 Set branch edges color in hexadecimal RGB notation.
556 Set branch edges color in hexadecimal RGB notation.
557
557
558 ``hooks``
558 ``hooks``
559 """""""""
559 """""""""
560
560
561 Commands or Python functions that get automatically executed by
561 Commands or Python functions that get automatically executed by
562 various actions such as starting or finishing a commit. Multiple
562 various actions such as starting or finishing a commit. Multiple
563 hooks can be run for the same action by appending a suffix to the
563 hooks can be run for the same action by appending a suffix to the
564 action. Overriding a site-wide hook can be done by changing its
564 action. Overriding a site-wide hook can be done by changing its
565 value or setting it to an empty string. Hooks can be prioritized
565 value or setting it to an empty string. Hooks can be prioritized
566 by adding a prefix of ``priority`` to the hook name on a new line
566 by adding a prefix of ``priority`` to the hook name on a new line
567 and setting the priority. The default priority is 0 if
567 and setting the priority. The default priority is 0 if
568 not specified.
568 not specified.
569
569
570 Example ``.hg/hgrc``::
570 Example ``.hg/hgrc``::
571
571
572 [hooks]
572 [hooks]
573 # update working directory after adding changesets
573 # update working directory after adding changesets
574 changegroup.update = hg update
574 changegroup.update = hg update
575 # do not use the site-wide hook
575 # do not use the site-wide hook
576 incoming =
576 incoming =
577 incoming.email = /my/email/hook
577 incoming.email = /my/email/hook
578 incoming.autobuild = /my/build/hook
578 incoming.autobuild = /my/build/hook
579 # force autobuild hook to run before other incoming hooks
579 # force autobuild hook to run before other incoming hooks
580 priority.incoming.autobuild = 1
580 priority.incoming.autobuild = 1
581
581
582 Most hooks are run with environment variables set that give useful
582 Most hooks are run with environment variables set that give useful
583 additional information. For each hook below, the environment
583 additional information. For each hook below, the environment
584 variables it is passed are listed with names of the form ``$HG_foo``.
584 variables it is passed are listed with names of the form ``$HG_foo``.
585
585
586 ``changegroup``
586 ``changegroup``
587 Run after a changegroup has been added via push, pull or unbundle.
587 Run after a changegroup has been added via push, pull or unbundle.
588 ID of the first new changeset is in ``$HG_NODE``. URL from which
588 ID of the first new changeset is in ``$HG_NODE``. URL from which
589 changes came is in ``$HG_URL``.
589 changes came is in ``$HG_URL``.
590
590
591 ``commit``
591 ``commit``
592 Run after a changeset has been created in the local repository. ID
592 Run after a changeset has been created in the local repository. ID
593 of the newly created changeset is in ``$HG_NODE``. Parent changeset
593 of the newly created changeset is in ``$HG_NODE``. Parent changeset
594 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
594 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
595
595
596 ``incoming``
596 ``incoming``
597 Run after a changeset has been pulled, pushed, or unbundled into
597 Run after a changeset has been pulled, pushed, or unbundled into
598 the local repository. The ID of the newly arrived changeset is in
598 the local repository. The ID of the newly arrived changeset is in
599 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
599 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
600
600
601 ``outgoing``
601 ``outgoing``
602 Run after sending changes from local repository to another. ID of
602 Run after sending changes from local repository to another. ID of
603 first changeset sent is in ``$HG_NODE``. Source of operation is in
603 first changeset sent is in ``$HG_NODE``. Source of operation is in
604 ``$HG_SOURCE``; see "preoutgoing" hook for description.
604 ``$HG_SOURCE``; see "preoutgoing" hook for description.
605
605
606 ``post-<command>``
606 ``post-<command>``
607 Run after successful invocations of the associated command. The
607 Run after successful invocations of the associated command. The
608 contents of the command line are passed as ``$HG_ARGS`` and the result
608 contents of the command line are passed as ``$HG_ARGS`` and the result
609 code in ``$HG_RESULT``. Parsed command line arguments are passed as
609 code in ``$HG_RESULT``. Parsed command line arguments are passed as
610 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
610 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
611 the python data internally passed to <command>. ``$HG_OPTS`` is a
611 the python data internally passed to <command>. ``$HG_OPTS`` is a
612 dictionary of options (with unspecified options set to their defaults).
612 dictionary of options (with unspecified options set to their defaults).
613 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
613 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
614
614
615 ``pre-<command>``
615 ``pre-<command>``
616 Run before executing the associated command. The contents of the
616 Run before executing the associated command. The contents of the
617 command line are passed as ``$HG_ARGS``. Parsed command line arguments
617 command line are passed as ``$HG_ARGS``. Parsed command line arguments
618 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
618 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
619 representations of the data internally passed to <command>. ``$HG_OPTS``
619 representations of the data internally passed to <command>. ``$HG_OPTS``
620 is a dictionary of options (with unspecified options set to their
620 is a dictionary of options (with unspecified options set to their
621 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
621 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
622 failure, the command doesn't execute and Mercurial returns the failure
622 failure, the command doesn't execute and Mercurial returns the failure
623 code.
623 code.
624
624
625 ``prechangegroup``
625 ``prechangegroup``
626 Run before a changegroup is added via push, pull or unbundle. Exit
626 Run before a changegroup is added via push, pull or unbundle. Exit
627 status 0 allows the changegroup to proceed. Non-zero status will
627 status 0 allows the changegroup to proceed. Non-zero status will
628 cause the push, pull or unbundle to fail. URL from which changes
628 cause the push, pull or unbundle to fail. URL from which changes
629 will come is in ``$HG_URL``.
629 will come is in ``$HG_URL``.
630
630
631 ``precommit``
631 ``precommit``
632 Run before starting a local commit. Exit status 0 allows the
632 Run before starting a local commit. Exit status 0 allows the
633 commit to proceed. Non-zero status will cause the commit to fail.
633 commit to proceed. Non-zero status will cause the commit to fail.
634 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
634 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
635
635
636 ``prelistkeys``
636 ``prelistkeys``
637 Run before listing pushkeys (like bookmarks) in the
637 Run before listing pushkeys (like bookmarks) in the
638 repository. Non-zero status will cause failure. The key namespace is
638 repository. Non-zero status will cause failure. The key namespace is
639 in ``$HG_NAMESPACE``.
639 in ``$HG_NAMESPACE``.
640
640
641 ``preoutgoing``
641 ``preoutgoing``
642 Run before collecting changes to send from the local repository to
642 Run before collecting changes to send from the local repository to
643 another. Non-zero status will cause failure. This lets you prevent
643 another. Non-zero status will cause failure. This lets you prevent
644 pull over HTTP or SSH. Also prevents against local pull, push
644 pull over HTTP or SSH. Also prevents against local pull, push
645 (outbound) or bundle commands, but not effective, since you can
645 (outbound) or bundle commands, but not effective, since you can
646 just copy files instead then. Source of operation is in
646 just copy files instead then. Source of operation is in
647 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
647 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
648 SSH or HTTP repository. If "push", "pull" or "bundle", operation
648 SSH or HTTP repository. If "push", "pull" or "bundle", operation
649 is happening on behalf of repository on same system.
649 is happening on behalf of repository on same system.
650
650
651 ``prepushkey``
651 ``prepushkey``
652 Run before a pushkey (like a bookmark) is added to the
652 Run before a pushkey (like a bookmark) is added to the
653 repository. Non-zero status will cause the key to be rejected. The
653 repository. Non-zero status will cause the key to be rejected. The
654 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
654 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
655 the old value (if any) is in ``$HG_OLD``, and the new value is in
655 the old value (if any) is in ``$HG_OLD``, and the new value is in
656 ``$HG_NEW``.
656 ``$HG_NEW``.
657
657
658 ``pretag``
658 ``pretag``
659 Run before creating a tag. Exit status 0 allows the tag to be
659 Run before creating a tag. Exit status 0 allows the tag to be
660 created. Non-zero status will cause the tag to fail. ID of
660 created. Non-zero status will cause the tag to fail. ID of
661 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
661 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
662 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
662 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
663
663
664 ``pretxnchangegroup``
664 ``pretxnchangegroup``
665 Run after a changegroup has been added via push, pull or unbundle,
665 Run after a changegroup has been added via push, pull or unbundle,
666 but before the transaction has been committed. Changegroup is
666 but before the transaction has been committed. Changegroup is
667 visible to hook program. This lets you validate incoming changes
667 visible to hook program. This lets you validate incoming changes
668 before accepting them. Passed the ID of the first new changeset in
668 before accepting them. Passed the ID of the first new changeset in
669 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
669 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
670 status will cause the transaction to be rolled back and the push,
670 status will cause the transaction to be rolled back and the push,
671 pull or unbundle will fail. URL that was source of changes is in
671 pull or unbundle will fail. URL that was source of changes is in
672 ``$HG_URL``.
672 ``$HG_URL``.
673
673
674 ``pretxncommit``
674 ``pretxncommit``
675 Run after a changeset has been created but the transaction not yet
675 Run after a changeset has been created but the transaction not yet
676 committed. Changeset is visible to hook program. This lets you
676 committed. Changeset is visible to hook program. This lets you
677 validate commit message and changes. Exit status 0 allows the
677 validate commit message and changes. Exit status 0 allows the
678 commit to proceed. Non-zero status will cause the transaction to
678 commit to proceed. Non-zero status will cause the transaction to
679 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
679 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
680 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
680 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
681
681
682 ``preupdate``
682 ``preupdate``
683 Run before updating the working directory. Exit status 0 allows
683 Run before updating the working directory. Exit status 0 allows
684 the update to proceed. Non-zero status will prevent the update.
684 the update to proceed. Non-zero status will prevent the update.
685 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
685 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
686 of second new parent is in ``$HG_PARENT2``.
686 of second new parent is in ``$HG_PARENT2``.
687
687
688 ``listkeys``
688 ``listkeys``
689 Run after listing pushkeys (like bookmarks) in the repository. The
689 Run after listing pushkeys (like bookmarks) in the repository. The
690 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
690 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
691 dictionary containing the keys and values.
691 dictionary containing the keys and values.
692
692
693 ``pushkey``
693 ``pushkey``
694 Run after a pushkey (like a bookmark) is added to the
694 Run after a pushkey (like a bookmark) is added to the
695 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
695 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
696 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
696 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
697 value is in ``$HG_NEW``.
697 value is in ``$HG_NEW``.
698
698
699 ``tag``
699 ``tag``
700 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
700 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
701 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
701 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
702 repository if ``$HG_LOCAL=0``.
702 repository if ``$HG_LOCAL=0``.
703
703
704 ``update``
704 ``update``
705 Run after updating the working directory. Changeset ID of first
705 Run after updating the working directory. Changeset ID of first
706 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
706 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
707 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
707 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
708 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
708 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
709
709
710 .. note:: It is generally better to use standard hooks rather than the
710 .. note:: It is generally better to use standard hooks rather than the
711 generic pre- and post- command hooks as they are guaranteed to be
711 generic pre- and post- command hooks as they are guaranteed to be
712 called in the appropriate contexts for influencing transactions.
712 called in the appropriate contexts for influencing transactions.
713 Also, hooks like "commit" will be called in all contexts that
713 Also, hooks like "commit" will be called in all contexts that
714 generate a commit (e.g. tag) and not just the commit command.
714 generate a commit (e.g. tag) and not just the commit command.
715
715
716 .. note:: Environment variables with empty values may not be passed to
716 .. note:: Environment variables with empty values may not be passed to
717 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
717 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
718 will have an empty value under Unix-like platforms for non-merge
718 will have an empty value under Unix-like platforms for non-merge
719 changesets, while it will not be available at all under Windows.
719 changesets, while it will not be available at all under Windows.
720
720
721 The syntax for Python hooks is as follows::
721 The syntax for Python hooks is as follows::
722
722
723 hookname = python:modulename.submodule.callable
723 hookname = python:modulename.submodule.callable
724 hookname = python:/path/to/python/module.py:callable
724 hookname = python:/path/to/python/module.py:callable
725
725
726 Python hooks are run within the Mercurial process. Each hook is
726 Python hooks are run within the Mercurial process. Each hook is
727 called with at least three keyword arguments: a ui object (keyword
727 called with at least three keyword arguments: a ui object (keyword
728 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
728 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
729 keyword that tells what kind of hook is used. Arguments listed as
729 keyword that tells what kind of hook is used. Arguments listed as
730 environment variables above are passed as keyword arguments, with no
730 environment variables above are passed as keyword arguments, with no
731 ``HG_`` prefix, and names in lower case.
731 ``HG_`` prefix, and names in lower case.
732
732
733 If a Python hook returns a "true" value or raises an exception, this
733 If a Python hook returns a "true" value or raises an exception, this
734 is treated as a failure.
734 is treated as a failure.
735
735
736
736
737 ``hostfingerprints``
737 ``hostfingerprints``
738 """"""""""""""""""""
738 """"""""""""""""""""
739
739
740 Fingerprints of the certificates of known HTTPS servers.
740 Fingerprints of the certificates of known HTTPS servers.
741 A HTTPS connection to a server with a fingerprint configured here will
741 A HTTPS connection to a server with a fingerprint configured here will
742 only succeed if the servers certificate matches the fingerprint.
742 only succeed if the servers certificate matches the fingerprint.
743 This is very similar to how ssh known hosts works.
743 This is very similar to how ssh known hosts works.
744 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
744 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
745 The CA chain and web.cacerts is not used for servers with a fingerprint.
745 The CA chain and web.cacerts is not used for servers with a fingerprint.
746
746
747 For example::
747 For example::
748
748
749 [hostfingerprints]
749 [hostfingerprints]
750 hg.intevation.org = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc
750 hg.intevation.org = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc
751
751
752 This feature is only supported when using Python 2.6 or later.
752 This feature is only supported when using Python 2.6 or later.
753
753
754
754
755 ``http_proxy``
755 ``http_proxy``
756 """"""""""""""
756 """"""""""""""
757
757
758 Used to access web-based Mercurial repositories through a HTTP
758 Used to access web-based Mercurial repositories through a HTTP
759 proxy.
759 proxy.
760
760
761 ``host``
761 ``host``
762 Host name and (optional) port of the proxy server, for example
762 Host name and (optional) port of the proxy server, for example
763 "myproxy:8000".
763 "myproxy:8000".
764
764
765 ``no``
765 ``no``
766 Optional. Comma-separated list of host names that should bypass
766 Optional. Comma-separated list of host names that should bypass
767 the proxy.
767 the proxy.
768
768
769 ``passwd``
769 ``passwd``
770 Optional. Password to authenticate with at the proxy server.
770 Optional. Password to authenticate with at the proxy server.
771
771
772 ``user``
772 ``user``
773 Optional. User name to authenticate with at the proxy server.
773 Optional. User name to authenticate with at the proxy server.
774
774
775 ``always``
775 ``always``
776 Optional. Always use the proxy, even for localhost and any entries
776 Optional. Always use the proxy, even for localhost and any entries
777 in ``http_proxy.no``. True or False. Default: False.
777 in ``http_proxy.no``. True or False. Default: False.
778
778
779 ``merge-patterns``
779 ``merge-patterns``
780 """"""""""""""""""
780 """"""""""""""""""
781
781
782 This section specifies merge tools to associate with particular file
782 This section specifies merge tools to associate with particular file
783 patterns. Tools matched here will take precedence over the default
783 patterns. Tools matched here will take precedence over the default
784 merge tool. Patterns are globs by default, rooted at the repository
784 merge tool. Patterns are globs by default, rooted at the repository
785 root.
785 root.
786
786
787 Example::
787 Example::
788
788
789 [merge-patterns]
789 [merge-patterns]
790 **.c = kdiff3
790 **.c = kdiff3
791 **.jpg = myimgmerge
791 **.jpg = myimgmerge
792
792
793 ``merge-tools``
793 ``merge-tools``
794 """""""""""""""
794 """""""""""""""
795
795
796 This section configures external merge tools to use for file-level
796 This section configures external merge tools to use for file-level
797 merges.
797 merges.
798
798
799 Example ``~/.hgrc``::
799 Example ``~/.hgrc``::
800
800
801 [merge-tools]
801 [merge-tools]
802 # Override stock tool location
802 # Override stock tool location
803 kdiff3.executable = ~/bin/kdiff3
803 kdiff3.executable = ~/bin/kdiff3
804 # Specify command line
804 # Specify command line
805 kdiff3.args = $base $local $other -o $output
805 kdiff3.args = $base $local $other -o $output
806 # Give higher priority
806 # Give higher priority
807 kdiff3.priority = 1
807 kdiff3.priority = 1
808
808
809 # Define new tool
809 # Define new tool
810 myHtmlTool.args = -m $local $other $base $output
810 myHtmlTool.args = -m $local $other $base $output
811 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
811 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
812 myHtmlTool.priority = 1
812 myHtmlTool.priority = 1
813
813
814 Supported arguments:
814 Supported arguments:
815
815
816 ``priority``
816 ``priority``
817 The priority in which to evaluate this tool.
817 The priority in which to evaluate this tool.
818 Default: 0.
818 Default: 0.
819
819
820 ``executable``
820 ``executable``
821 Either just the name of the executable or its pathname. On Windows,
821 Either just the name of the executable or its pathname. On Windows,
822 the path can use environment variables with ${ProgramFiles} syntax.
822 the path can use environment variables with ${ProgramFiles} syntax.
823 Default: the tool name.
823 Default: the tool name.
824
824
825 ``args``
825 ``args``
826 The arguments to pass to the tool executable. You can refer to the
826 The arguments to pass to the tool executable. You can refer to the
827 files being merged as well as the output file through these
827 files being merged as well as the output file through these
828 variables: ``$base``, ``$local``, ``$other``, ``$output``.
828 variables: ``$base``, ``$local``, ``$other``, ``$output``.
829 Default: ``$local $base $other``
829 Default: ``$local $base $other``
830
830
831 ``premerge``
831 ``premerge``
832 Attempt to run internal non-interactive 3-way merge tool before
832 Attempt to run internal non-interactive 3-way merge tool before
833 launching external tool. Options are ``true``, ``false``, or ``keep``
833 launching external tool. Options are ``true``, ``false``, or ``keep``
834 to leave markers in the file if the premerge fails.
834 to leave markers in the file if the premerge fails.
835 Default: True
835 Default: True
836
836
837 ``binary``
837 ``binary``
838 This tool can merge binary files. Defaults to False, unless tool
838 This tool can merge binary files. Defaults to False, unless tool
839 was selected by file pattern match.
839 was selected by file pattern match.
840
840
841 ``symlink``
841 ``symlink``
842 This tool can merge symlinks. Defaults to False, even if tool was
842 This tool can merge symlinks. Defaults to False, even if tool was
843 selected by file pattern match.
843 selected by file pattern match.
844
844
845 ``check``
845 ``check``
846 A list of merge success-checking options:
846 A list of merge success-checking options:
847
847
848 ``changed``
848 ``changed``
849 Ask whether merge was successful when the merged file shows no changes.
849 Ask whether merge was successful when the merged file shows no changes.
850 ``conflicts``
850 ``conflicts``
851 Check whether there are conflicts even though the tool reported success.
851 Check whether there are conflicts even though the tool reported success.
852 ``prompt``
852 ``prompt``
853 Always prompt for merge success, regardless of success reported by tool.
853 Always prompt for merge success, regardless of success reported by tool.
854
854
855 ``checkchanged``
855 ``checkchanged``
856 True is equivalent to ``check = changed``.
856 True is equivalent to ``check = changed``.
857 Default: False
857 Default: False
858
858
859 ``checkconflicts``
859 ``checkconflicts``
860 True is equivalent to ``check = conflicts``.
860 True is equivalent to ``check = conflicts``.
861 Default: False
861 Default: False
862
862
863 ``fixeol``
863 ``fixeol``
864 Attempt to fix up EOL changes caused by the merge tool.
864 Attempt to fix up EOL changes caused by the merge tool.
865 Default: False
865 Default: False
866
866
867 ``gui``
867 ``gui``
868 This tool requires a graphical interface to run. Default: False
868 This tool requires a graphical interface to run. Default: False
869
869
870 ``regkey``
870 ``regkey``
871 Windows registry key which describes install location of this
871 Windows registry key which describes install location of this
872 tool. Mercurial will search for this key first under
872 tool. Mercurial will search for this key first under
873 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
873 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
874 Default: None
874 Default: None
875
875
876 ``regkeyalt``
876 ``regkeyalt``
877 An alternate Windows registry key to try if the first key is not
877 An alternate Windows registry key to try if the first key is not
878 found. The alternate key uses the same ``regname`` and ``regappend``
878 found. The alternate key uses the same ``regname`` and ``regappend``
879 semantics of the primary key. The most common use for this key
879 semantics of the primary key. The most common use for this key
880 is to search for 32bit applications on 64bit operating systems.
880 is to search for 32bit applications on 64bit operating systems.
881 Default: None
881 Default: None
882
882
883 ``regname``
883 ``regname``
884 Name of value to read from specified registry key. Defaults to the
884 Name of value to read from specified registry key. Defaults to the
885 unnamed (default) value.
885 unnamed (default) value.
886
886
887 ``regappend``
887 ``regappend``
888 String to append to the value read from the registry, typically
888 String to append to the value read from the registry, typically
889 the executable name of the tool.
889 the executable name of the tool.
890 Default: None
890 Default: None
891
891
892
892
893 ``patch``
893 ``patch``
894 """""""""
894 """""""""
895
895
896 Settings used when applying patches, for instance through the 'import'
896 Settings used when applying patches, for instance through the 'import'
897 command or with Mercurial Queues extension.
897 command or with Mercurial Queues extension.
898
898
899 ``eol``
899 ``eol``
900 When set to 'strict' patch content and patched files end of lines
900 When set to 'strict' patch content and patched files end of lines
901 are preserved. When set to ``lf`` or ``crlf``, both files end of
901 are preserved. When set to ``lf`` or ``crlf``, both files end of
902 lines are ignored when patching and the result line endings are
902 lines are ignored when patching and the result line endings are
903 normalized to either LF (Unix) or CRLF (Windows). When set to
903 normalized to either LF (Unix) or CRLF (Windows). When set to
904 ``auto``, end of lines are again ignored while patching but line
904 ``auto``, end of lines are again ignored while patching but line
905 endings in patched files are normalized to their original setting
905 endings in patched files are normalized to their original setting
906 on a per-file basis. If target file does not exist or has no end
906 on a per-file basis. If target file does not exist or has no end
907 of line, patch line endings are preserved.
907 of line, patch line endings are preserved.
908 Default: strict.
908 Default: strict.
909
909
910
910
911 ``paths``
911 ``paths``
912 """""""""
912 """""""""
913
913
914 Assigns symbolic names to repositories. The left side is the
914 Assigns symbolic names to repositories. The left side is the
915 symbolic name, and the right gives the directory or URL that is the
915 symbolic name, and the right gives the directory or URL that is the
916 location of the repository. Default paths can be declared by setting
916 location of the repository. Default paths can be declared by setting
917 the following entries.
917 the following entries.
918
918
919 ``default``
919 ``default``
920 Directory or URL to use when pulling if no source is specified.
920 Directory or URL to use when pulling if no source is specified.
921 Default is set to repository from which the current repository was
921 Default is set to repository from which the current repository was
922 cloned.
922 cloned.
923
923
924 ``default-push``
924 ``default-push``
925 Optional. Directory or URL to use when pushing if no destination
925 Optional. Directory or URL to use when pushing if no destination
926 is specified.
926 is specified.
927
927
928 ``phases``
928 ``phases``
929 """"""""""
929 """"""""""
930
930
931 Specifies default handling of phases. See :hg:`help phases` for more
931 Specifies default handling of phases. See :hg:`help phases` for more
932 information about working with phases.
932 information about working with phases.
933
933
934 ``publish``
934 ``publish``
935 Controls draft phase behavior when working as a server. When true,
935 Controls draft phase behavior when working as a server. When true,
936 pushed changesets are set to public in both client and server and
936 pushed changesets are set to public in both client and server and
937 pulled or cloned changesets are set to public in the client.
937 pulled or cloned changesets are set to public in the client.
938 Default: True
938 Default: True
939
939
940 ``new-commit``
940 ``new-commit``
941 Phase of newly-created commits.
941 Phase of newly-created commits.
942 Default: draft
942 Default: draft
943
943
944 ``profiling``
944 ``profiling``
945 """""""""""""
945 """""""""""""
946
946
947 Specifies profiling type, format, and file output. Two profilers are
947 Specifies profiling type, format, and file output. Two profilers are
948 supported: an instrumenting profiler (named ``ls``), and a sampling
948 supported: an instrumenting profiler (named ``ls``), and a sampling
949 profiler (named ``stat``).
949 profiler (named ``stat``).
950
950
951 In this section description, 'profiling data' stands for the raw data
951 In this section description, 'profiling data' stands for the raw data
952 collected during profiling, while 'profiling report' stands for a
952 collected during profiling, while 'profiling report' stands for a
953 statistical text report generated from the profiling data. The
953 statistical text report generated from the profiling data. The
954 profiling is done using lsprof.
954 profiling is done using lsprof.
955
955
956 ``type``
956 ``type``
957 The type of profiler to use.
957 The type of profiler to use.
958 Default: ls.
958 Default: ls.
959
959
960 ``ls``
960 ``ls``
961 Use Python's built-in instrumenting profiler. This profiler
961 Use Python's built-in instrumenting profiler. This profiler
962 works on all platforms, but each line number it reports is the
962 works on all platforms, but each line number it reports is the
963 first line of a function. This restriction makes it difficult to
963 first line of a function. This restriction makes it difficult to
964 identify the expensive parts of a non-trivial function.
964 identify the expensive parts of a non-trivial function.
965 ``stat``
965 ``stat``
966 Use a third-party statistical profiler, statprof. This profiler
966 Use a third-party statistical profiler, statprof. This profiler
967 currently runs only on Unix systems, and is most useful for
967 currently runs only on Unix systems, and is most useful for
968 profiling commands that run for longer than about 0.1 seconds.
968 profiling commands that run for longer than about 0.1 seconds.
969
969
970 ``format``
970 ``format``
971 Profiling format. Specific to the ``ls`` instrumenting profiler.
971 Profiling format. Specific to the ``ls`` instrumenting profiler.
972 Default: text.
972 Default: text.
973
973
974 ``text``
974 ``text``
975 Generate a profiling report. When saving to a file, it should be
975 Generate a profiling report. When saving to a file, it should be
976 noted that only the report is saved, and the profiling data is
976 noted that only the report is saved, and the profiling data is
977 not kept.
977 not kept.
978 ``kcachegrind``
978 ``kcachegrind``
979 Format profiling data for kcachegrind use: when saving to a
979 Format profiling data for kcachegrind use: when saving to a
980 file, the generated file can directly be loaded into
980 file, the generated file can directly be loaded into
981 kcachegrind.
981 kcachegrind.
982
982
983 ``frequency``
983 ``frequency``
984 Sampling frequency. Specific to the ``stat`` sampling profiler.
984 Sampling frequency. Specific to the ``stat`` sampling profiler.
985 Default: 1000.
985 Default: 1000.
986
986
987 ``output``
987 ``output``
988 File path where profiling data or report should be saved. If the
988 File path where profiling data or report should be saved. If the
989 file exists, it is replaced. Default: None, data is printed on
989 file exists, it is replaced. Default: None, data is printed on
990 stderr
990 stderr
991
991
992 ``revsetalias``
992 ``revsetalias``
993 """""""""""""""
993 """""""""""""""
994
994
995 Alias definitions for revsets. See :hg:`help revsets` for details.
995 Alias definitions for revsets. See :hg:`help revsets` for details.
996
996
997 ``server``
997 ``server``
998 """"""""""
998 """"""""""
999
999
1000 Controls generic server settings.
1000 Controls generic server settings.
1001
1001
1002 ``uncompressed``
1002 ``uncompressed``
1003 Whether to allow clients to clone a repository using the
1003 Whether to allow clients to clone a repository using the
1004 uncompressed streaming protocol. This transfers about 40% more
1004 uncompressed streaming protocol. This transfers about 40% more
1005 data than a regular clone, but uses less memory and CPU on both
1005 data than a regular clone, but uses less memory and CPU on both
1006 server and client. Over a LAN (100 Mbps or better) or a very fast
1006 server and client. Over a LAN (100 Mbps or better) or a very fast
1007 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
1007 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
1008 regular clone. Over most WAN connections (anything slower than
1008 regular clone. Over most WAN connections (anything slower than
1009 about 6 Mbps), uncompressed streaming is slower, because of the
1009 about 6 Mbps), uncompressed streaming is slower, because of the
1010 extra data transfer overhead. This mode will also temporarily hold
1010 extra data transfer overhead. This mode will also temporarily hold
1011 the write lock while determining what data to transfer.
1011 the write lock while determining what data to transfer.
1012 Default is True.
1012 Default is True.
1013
1013
1014 ``preferuncompressed``
1014 ``preferuncompressed``
1015 When set, clients will try to use the uncompressed streaming
1015 When set, clients will try to use the uncompressed streaming
1016 protocol. Default is False.
1016 protocol. Default is False.
1017
1017
1018 ``validate``
1018 ``validate``
1019 Whether to validate the completeness of pushed changesets by
1019 Whether to validate the completeness of pushed changesets by
1020 checking that all new file revisions specified in manifests are
1020 checking that all new file revisions specified in manifests are
1021 present. Default is False.
1021 present. Default is False.
1022
1022
1023 ``smtp``
1023 ``smtp``
1024 """"""""
1024 """"""""
1025
1025
1026 Configuration for extensions that need to send email messages.
1026 Configuration for extensions that need to send email messages.
1027
1027
1028 ``host``
1028 ``host``
1029 Host name of mail server, e.g. "mail.example.com".
1029 Host name of mail server, e.g. "mail.example.com".
1030
1030
1031 ``port``
1031 ``port``
1032 Optional. Port to connect to on mail server. Default: 25.
1032 Optional. Port to connect to on mail server. Default: 25.
1033
1033
1034 ``tls``
1034 ``tls``
1035 Optional. Method to enable TLS when connecting to mail server: starttls,
1035 Optional. Method to enable TLS when connecting to mail server: starttls,
1036 smtps or none. Default: none.
1036 smtps or none. Default: none.
1037
1037
1038 ``username``
1038 ``username``
1039 Optional. User name for authenticating with the SMTP server.
1039 Optional. User name for authenticating with the SMTP server.
1040 Default: none.
1040 Default: none.
1041
1041
1042 ``password``
1042 ``password``
1043 Optional. Password for authenticating with the SMTP server. If not
1043 Optional. Password for authenticating with the SMTP server. If not
1044 specified, interactive sessions will prompt the user for a
1044 specified, interactive sessions will prompt the user for a
1045 password; non-interactive sessions will fail. Default: none.
1045 password; non-interactive sessions will fail. Default: none.
1046
1046
1047 ``local_hostname``
1047 ``local_hostname``
1048 Optional. It's the hostname that the sender can use to identify
1048 Optional. It's the hostname that the sender can use to identify
1049 itself to the MTA.
1049 itself to the MTA.
1050
1050
1051
1051
1052 ``subpaths``
1052 ``subpaths``
1053 """"""""""""
1053 """"""""""""
1054
1054
1055 Subrepository source URLs can go stale if a remote server changes name
1055 Subrepository source URLs can go stale if a remote server changes name
1056 or becomes temporarily unavailable. This section lets you define
1056 or becomes temporarily unavailable. This section lets you define
1057 rewrite rules of the form::
1057 rewrite rules of the form::
1058
1058
1059 <pattern> = <replacement>
1059 <pattern> = <replacement>
1060
1060
1061 where ``pattern`` is a regular expression matching a subrepository
1061 where ``pattern`` is a regular expression matching a subrepository
1062 source URL and ``replacement`` is the replacement string used to
1062 source URL and ``replacement`` is the replacement string used to
1063 rewrite it. Groups can be matched in ``pattern`` and referenced in
1063 rewrite it. Groups can be matched in ``pattern`` and referenced in
1064 ``replacements``. For instance::
1064 ``replacements``. For instance::
1065
1065
1066 http://server/(.*)-hg/ = http://hg.server/\1/
1066 http://server/(.*)-hg/ = http://hg.server/\1/
1067
1067
1068 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1068 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1069
1069
1070 Relative subrepository paths are first made absolute, and the the
1070 Relative subrepository paths are first made absolute, and the the
1071 rewrite rules are then applied on the full (absolute) path. The rules
1071 rewrite rules are then applied on the full (absolute) path. The rules
1072 are applied in definition order.
1072 are applied in definition order.
1073
1073
1074 ``trusted``
1074 ``trusted``
1075 """""""""""
1075 """""""""""
1076
1076
1077 Mercurial will not use the settings in the
1077 Mercurial will not use the settings in the
1078 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1078 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1079 user or to a trusted group, as various hgrc features allow arbitrary
1079 user or to a trusted group, as various hgrc features allow arbitrary
1080 commands to be run. This issue is often encountered when configuring
1080 commands to be run. This issue is often encountered when configuring
1081 hooks or extensions for shared repositories or servers. However,
1081 hooks or extensions for shared repositories or servers. However,
1082 the web interface will use some safe settings from the ``[web]``
1082 the web interface will use some safe settings from the ``[web]``
1083 section.
1083 section.
1084
1084
1085 This section specifies what users and groups are trusted. The
1085 This section specifies what users and groups are trusted. The
1086 current user is always trusted. To trust everybody, list a user or a
1086 current user is always trusted. To trust everybody, list a user or a
1087 group with name ``*``. These settings must be placed in an
1087 group with name ``*``. These settings must be placed in an
1088 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1088 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1089 user or service running Mercurial.
1089 user or service running Mercurial.
1090
1090
1091 ``users``
1091 ``users``
1092 Comma-separated list of trusted users.
1092 Comma-separated list of trusted users.
1093
1093
1094 ``groups``
1094 ``groups``
1095 Comma-separated list of trusted groups.
1095 Comma-separated list of trusted groups.
1096
1096
1097
1097
1098 ``ui``
1098 ``ui``
1099 """"""
1099 """"""
1100
1100
1101 User interface controls.
1101 User interface controls.
1102
1102
1103 ``archivemeta``
1103 ``archivemeta``
1104 Whether to include the .hg_archival.txt file containing meta data
1104 Whether to include the .hg_archival.txt file containing meta data
1105 (hashes for the repository base and for tip) in archives created
1105 (hashes for the repository base and for tip) in archives created
1106 by the :hg:`archive` command or downloaded via hgweb.
1106 by the :hg:`archive` command or downloaded via hgweb.
1107 Default is True.
1107 Default is True.
1108
1108
1109 ``askusername``
1109 ``askusername``
1110 Whether to prompt for a username when committing. If True, and
1110 Whether to prompt for a username when committing. If True, and
1111 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1111 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1112 be prompted to enter a username. If no username is entered, the
1112 be prompted to enter a username. If no username is entered, the
1113 default ``USER@HOST`` is used instead.
1113 default ``USER@HOST`` is used instead.
1114 Default is False.
1114 Default is False.
1115
1115
1116 ``commitsubrepos``
1116 ``commitsubrepos``
1117 Whether to commit modified subrepositories when committing the
1117 Whether to commit modified subrepositories when committing the
1118 parent repository. If False and one subrepository has uncommitted
1118 parent repository. If False and one subrepository has uncommitted
1119 changes, abort the commit.
1119 changes, abort the commit.
1120 Default is False.
1120 Default is False.
1121
1121
1122 ``debug``
1122 ``debug``
1123 Print debugging information. True or False. Default is False.
1123 Print debugging information. True or False. Default is False.
1124
1124
1125 ``editor``
1125 ``editor``
1126 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1126 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1127
1127
1128 ``fallbackencoding``
1128 ``fallbackencoding``
1129 Encoding to try if it's not possible to decode the changelog using
1129 Encoding to try if it's not possible to decode the changelog using
1130 UTF-8. Default is ISO-8859-1.
1130 UTF-8. Default is ISO-8859-1.
1131
1131
1132 ``ignore``
1132 ``ignore``
1133 A file to read per-user ignore patterns from. This file should be
1133 A file to read per-user ignore patterns from. This file should be
1134 in the same format as a repository-wide .hgignore file. This
1134 in the same format as a repository-wide .hgignore file. This
1135 option supports hook syntax, so if you want to specify multiple
1135 option supports hook syntax, so if you want to specify multiple
1136 ignore files, you can do so by setting something like
1136 ignore files, you can do so by setting something like
1137 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1137 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1138 format, see the ``hgignore(5)`` man page.
1138 format, see the ``hgignore(5)`` man page.
1139
1139
1140 ``interactive``
1140 ``interactive``
1141 Allow to prompt the user. True or False. Default is True.
1141 Allow to prompt the user. True or False. Default is True.
1142
1142
1143 ``logtemplate``
1143 ``logtemplate``
1144 Template string for commands that print changesets.
1144 Template string for commands that print changesets.
1145
1145
1146 ``merge``
1146 ``merge``
1147 The conflict resolution program to use during a manual merge.
1147 The conflict resolution program to use during a manual merge.
1148 For more information on merge tools see :hg:`help merge-tools`.
1148 For more information on merge tools see :hg:`help merge-tools`.
1149 For configuring merge tools see the ``[merge-tools]`` section.
1149 For configuring merge tools see the ``[merge-tools]`` section.
1150
1150
1151 ``portablefilenames``
1151 ``portablefilenames``
1152 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1152 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1153 Default is ``warn``.
1153 Default is ``warn``.
1154 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1154 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1155 platforms, if a file with a non-portable filename is added (e.g. a file
1155 platforms, if a file with a non-portable filename is added (e.g. a file
1156 with a name that can't be created on Windows because it contains reserved
1156 with a name that can't be created on Windows because it contains reserved
1157 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1157 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1158 collision with an existing file).
1158 collision with an existing file).
1159 If set to ``ignore`` (or ``false``), no warning is printed.
1159 If set to ``ignore`` (or ``false``), no warning is printed.
1160 If set to ``abort``, the command is aborted.
1160 If set to ``abort``, the command is aborted.
1161 On Windows, this configuration option is ignored and the command aborted.
1161 On Windows, this configuration option is ignored and the command aborted.
1162
1162
1163 ``quiet``
1163 ``quiet``
1164 Reduce the amount of output printed. True or False. Default is False.
1164 Reduce the amount of output printed. True or False. Default is False.
1165
1165
1166 ``remotecmd``
1166 ``remotecmd``
1167 remote command to use for clone/push/pull operations. Default is ``hg``.
1167 remote command to use for clone/push/pull operations. Default is ``hg``.
1168
1168
1169 ``reportoldssl``
1169 ``reportoldssl``
1170 Warn if an SSL certificate is unable to be due to using Python
1170 Warn if an SSL certificate is unable to be due to using Python
1171 2.5 or earlier. True or False. Default is True.
1171 2.5 or earlier. True or False. Default is True.
1172
1172
1173 ``report_untrusted``
1173 ``report_untrusted``
1174 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1174 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1175 trusted user or group. True or False. Default is True.
1175 trusted user or group. True or False. Default is True.
1176
1176
1177 ``slash``
1177 ``slash``
1178 Display paths using a slash (``/``) as the path separator. This
1178 Display paths using a slash (``/``) as the path separator. This
1179 only makes a difference on systems where the default path
1179 only makes a difference on systems where the default path
1180 separator is not the slash character (e.g. Windows uses the
1180 separator is not the slash character (e.g. Windows uses the
1181 backslash character (``\``)).
1181 backslash character (``\``)).
1182 Default is False.
1182 Default is False.
1183
1183
1184 ``ssh``
1184 ``ssh``
1185 command to use for SSH connections. Default is ``ssh``.
1185 command to use for SSH connections. Default is ``ssh``.
1186
1186
1187 ``strict``
1187 ``strict``
1188 Require exact command names, instead of allowing unambiguous
1188 Require exact command names, instead of allowing unambiguous
1189 abbreviations. True or False. Default is False.
1189 abbreviations. True or False. Default is False.
1190
1190
1191 ``style``
1191 ``style``
1192 Name of style to use for command output.
1192 Name of style to use for command output.
1193
1193
1194 ``timeout``
1194 ``timeout``
1195 The timeout used when a lock is held (in seconds), a negative value
1195 The timeout used when a lock is held (in seconds), a negative value
1196 means no timeout. Default is 600.
1196 means no timeout. Default is 600.
1197
1197
1198 ``traceback``
1198 ``traceback``
1199 Mercurial always prints a traceback when an unknown exception
1199 Mercurial always prints a traceback when an unknown exception
1200 occurs. Setting this to True will make Mercurial print a traceback
1200 occurs. Setting this to True will make Mercurial print a traceback
1201 on all exceptions, even those recognized by Mercurial (such as
1201 on all exceptions, even those recognized by Mercurial (such as
1202 IOError or MemoryError). Default is False.
1202 IOError or MemoryError). Default is False.
1203
1203
1204 ``username``
1204 ``username``
1205 The committer of a changeset created when running "commit".
1205 The committer of a changeset created when running "commit".
1206 Typically a person's name and email address, e.g. ``Fred Widget
1206 Typically a person's name and email address, e.g. ``Fred Widget
1207 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1207 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1208 the username in hgrc is empty, it has to be specified manually or
1208 the username in hgrc is empty, it has to be specified manually or
1209 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1209 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1210 ``username =`` in the system hgrc). Environment variables in the
1210 ``username =`` in the system hgrc). Environment variables in the
1211 username are expanded.
1211 username are expanded.
1212
1212
1213 ``verbose``
1213 ``verbose``
1214 Increase the amount of output printed. True or False. Default is False.
1214 Increase the amount of output printed. True or False. Default is False.
1215
1215
1216
1216
1217 ``web``
1217 ``web``
1218 """""""
1218 """""""
1219
1219
1220 Web interface configuration. The settings in this section apply to
1220 Web interface configuration. The settings in this section apply to
1221 both the builtin webserver (started by :hg:`serve`) and the script you
1221 both the builtin webserver (started by :hg:`serve`) and the script you
1222 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1222 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1223 and WSGI).
1223 and WSGI).
1224
1224
1225 The Mercurial webserver does no authentication (it does not prompt for
1225 The Mercurial webserver does no authentication (it does not prompt for
1226 usernames and passwords to validate *who* users are), but it does do
1226 usernames and passwords to validate *who* users are), but it does do
1227 authorization (it grants or denies access for *authenticated users*
1227 authorization (it grants or denies access for *authenticated users*
1228 based on settings in this section). You must either configure your
1228 based on settings in this section). You must either configure your
1229 webserver to do authentication for you, or disable the authorization
1229 webserver to do authentication for you, or disable the authorization
1230 checks.
1230 checks.
1231
1231
1232 For a quick setup in a trusted environment, e.g., a private LAN, where
1232 For a quick setup in a trusted environment, e.g., a private LAN, where
1233 you want it to accept pushes from anybody, you can use the following
1233 you want it to accept pushes from anybody, you can use the following
1234 command line::
1234 command line::
1235
1235
1236 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1236 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1237
1237
1238 Note that this will allow anybody to push anything to the server and
1238 Note that this will allow anybody to push anything to the server and
1239 that this should not be used for public servers.
1239 that this should not be used for public servers.
1240
1240
1241 The full set of options is:
1241 The full set of options is:
1242
1242
1243 ``accesslog``
1243 ``accesslog``
1244 Where to output the access log. Default is stdout.
1244 Where to output the access log. Default is stdout.
1245
1245
1246 ``address``
1246 ``address``
1247 Interface address to bind to. Default is all.
1247 Interface address to bind to. Default is all.
1248
1248
1249 ``allow_archive``
1249 ``allow_archive``
1250 List of archive format (bz2, gz, zip) allowed for downloading.
1250 List of archive format (bz2, gz, zip) allowed for downloading.
1251 Default is empty.
1251 Default is empty.
1252
1252
1253 ``allowbz2``
1253 ``allowbz2``
1254 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1254 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1255 revisions.
1255 revisions.
1256 Default is False.
1256 Default is False.
1257
1257
1258 ``allowgz``
1258 ``allowgz``
1259 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1259 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1260 revisions.
1260 revisions.
1261 Default is False.
1261 Default is False.
1262
1262
1263 ``allowpull``
1263 ``allowpull``
1264 Whether to allow pulling from the repository. Default is True.
1264 Whether to allow pulling from the repository. Default is True.
1265
1265
1266 ``allow_push``
1266 ``allow_push``
1267 Whether to allow pushing to the repository. If empty or not set,
1267 Whether to allow pushing to the repository. If empty or not set,
1268 push is not allowed. If the special value ``*``, any remote user can
1268 push is not allowed. If the special value ``*``, any remote user can
1269 push, including unauthenticated users. Otherwise, the remote user
1269 push, including unauthenticated users. Otherwise, the remote user
1270 must have been authenticated, and the authenticated user name must
1270 must have been authenticated, and the authenticated user name must
1271 be present in this list. The contents of the allow_push list are
1271 be present in this list. The contents of the allow_push list are
1272 examined after the deny_push list.
1272 examined after the deny_push list.
1273
1273
1274 ``guessmime``
1274 ``guessmime``
1275 Control MIME types for raw download of file content.
1275 Control MIME types for raw download of file content.
1276 Set to True to let hgweb guess the content type from the file
1276 Set to True to let hgweb guess the content type from the file
1277 extension. This will serve HTML files as ``text/html`` and might
1277 extension. This will serve HTML files as ``text/html`` and might
1278 allow cross-site scripting attacks when serving untrusted
1278 allow cross-site scripting attacks when serving untrusted
1279 repositories. Default is False.
1279 repositories. Default is False.
1280
1280
1281 ``allow_read``
1281 ``allow_read``
1282 If the user has not already been denied repository access due to
1282 If the user has not already been denied repository access due to
1283 the contents of deny_read, this list determines whether to grant
1283 the contents of deny_read, this list determines whether to grant
1284 repository access to the user. If this list is not empty, and the
1284 repository access to the user. If this list is not empty, and the
1285 user is unauthenticated or not present in the list, then access is
1285 user is unauthenticated or not present in the list, then access is
1286 denied for the user. If the list is empty or not set, then access
1286 denied for the user. If the list is empty or not set, then access
1287 is permitted to all users by default. Setting allow_read to the
1287 is permitted to all users by default. Setting allow_read to the
1288 special value ``*`` is equivalent to it not being set (i.e. access
1288 special value ``*`` is equivalent to it not being set (i.e. access
1289 is permitted to all users). The contents of the allow_read list are
1289 is permitted to all users). The contents of the allow_read list are
1290 examined after the deny_read list.
1290 examined after the deny_read list.
1291
1291
1292 ``allowzip``
1292 ``allowzip``
1293 (DEPRECATED) Whether to allow .zip downloading of repository
1293 (DEPRECATED) Whether to allow .zip downloading of repository
1294 revisions. Default is False. This feature creates temporary files.
1294 revisions. Default is False. This feature creates temporary files.
1295
1295
1296 ``baseurl``
1296 ``baseurl``
1297 Base URL to use when publishing URLs in other locations, so
1297 Base URL to use when publishing URLs in other locations, so
1298 third-party tools like email notification hooks can construct
1298 third-party tools like email notification hooks can construct
1299 URLs. Example: ``http://hgserver/repos/``.
1299 URLs. Example: ``http://hgserver/repos/``.
1300
1300
1301 ``cacerts``
1301 ``cacerts``
1302 Path to file containing a list of PEM encoded certificate
1302 Path to file containing a list of PEM encoded certificate
1303 authority certificates. Environment variables and ``~user``
1303 authority certificates. Environment variables and ``~user``
1304 constructs are expanded in the filename. If specified on the
1304 constructs are expanded in the filename. If specified on the
1305 client, then it will verify the identity of remote HTTPS servers
1305 client, then it will verify the identity of remote HTTPS servers
1306 with these certificates.
1306 with these certificates.
1307
1307
1308 This feature is only supported when using Python 2.6 or later. If you wish
1308 This feature is only supported when using Python 2.6 or later. If you wish
1309 to use it with earlier versions of Python, install the backported
1309 to use it with earlier versions of Python, install the backported
1310 version of the ssl library that is available from
1310 version of the ssl library that is available from
1311 ``http://pypi.python.org``.
1311 ``http://pypi.python.org``.
1312
1312
1313 To disable SSL verification temporarily, specify ``--insecure`` from
1313 To disable SSL verification temporarily, specify ``--insecure`` from
1314 command line.
1314 command line.
1315
1315
1316 You can use OpenSSL's CA certificate file if your platform has
1316 You can use OpenSSL's CA certificate file if your platform has
1317 one. On most Linux systems this will be
1317 one. On most Linux systems this will be
1318 ``/etc/ssl/certs/ca-certificates.crt``. Otherwise you will have to
1318 ``/etc/ssl/certs/ca-certificates.crt``. Otherwise you will have to
1319 generate this file manually. The form must be as follows::
1319 generate this file manually. The form must be as follows::
1320
1320
1321 -----BEGIN CERTIFICATE-----
1321 -----BEGIN CERTIFICATE-----
1322 ... (certificate in base64 PEM encoding) ...
1322 ... (certificate in base64 PEM encoding) ...
1323 -----END CERTIFICATE-----
1323 -----END CERTIFICATE-----
1324 -----BEGIN CERTIFICATE-----
1324 -----BEGIN CERTIFICATE-----
1325 ... (certificate in base64 PEM encoding) ...
1325 ... (certificate in base64 PEM encoding) ...
1326 -----END CERTIFICATE-----
1326 -----END CERTIFICATE-----
1327
1327
1328 ``cache``
1328 ``cache``
1329 Whether to support caching in hgweb. Defaults to True.
1329 Whether to support caching in hgweb. Defaults to True.
1330
1330
1331 ``collapse``
1332 With ``descend`` enabled, repositories in subdirectories are shown at
1333 a single level alongside repositories in the current path. With
1334 ``collapse`` also enabled, repositories residing at a deeper level than
1335 the current path are grouped behind navigable directory entries that
1336 lead to the locations of these repositories. In effect, this setting
1337 collapses each collection of repositories found within a subdirectory
1338 into a single entry for that subdirectory. Default is False.
1339
1331 ``contact``
1340 ``contact``
1332 Name or email address of the person in charge of the repository.
1341 Name or email address of the person in charge of the repository.
1333 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1342 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1334
1343
1335 ``deny_push``
1344 ``deny_push``
1336 Whether to deny pushing to the repository. If empty or not set,
1345 Whether to deny pushing to the repository. If empty or not set,
1337 push is not denied. If the special value ``*``, all remote users are
1346 push is not denied. If the special value ``*``, all remote users are
1338 denied push. Otherwise, unauthenticated users are all denied, and
1347 denied push. Otherwise, unauthenticated users are all denied, and
1339 any authenticated user name present in this list is also denied. The
1348 any authenticated user name present in this list is also denied. The
1340 contents of the deny_push list are examined before the allow_push list.
1349 contents of the deny_push list are examined before the allow_push list.
1341
1350
1342 ``deny_read``
1351 ``deny_read``
1343 Whether to deny reading/viewing of the repository. If this list is
1352 Whether to deny reading/viewing of the repository. If this list is
1344 not empty, unauthenticated users are all denied, and any
1353 not empty, unauthenticated users are all denied, and any
1345 authenticated user name present in this list is also denied access to
1354 authenticated user name present in this list is also denied access to
1346 the repository. If set to the special value ``*``, all remote users
1355 the repository. If set to the special value ``*``, all remote users
1347 are denied access (rarely needed ;). If deny_read is empty or not set,
1356 are denied access (rarely needed ;). If deny_read is empty or not set,
1348 the determination of repository access depends on the presence and
1357 the determination of repository access depends on the presence and
1349 content of the allow_read list (see description). If both
1358 content of the allow_read list (see description). If both
1350 deny_read and allow_read are empty or not set, then access is
1359 deny_read and allow_read are empty or not set, then access is
1351 permitted to all users by default. If the repository is being
1360 permitted to all users by default. If the repository is being
1352 served via hgwebdir, denied users will not be able to see it in
1361 served via hgwebdir, denied users will not be able to see it in
1353 the list of repositories. The contents of the deny_read list have
1362 the list of repositories. The contents of the deny_read list have
1354 priority over (are examined before) the contents of the allow_read
1363 priority over (are examined before) the contents of the allow_read
1355 list.
1364 list.
1356
1365
1357 ``descend``
1366 ``descend``
1358 hgwebdir indexes will not descend into subdirectories. Only repositories
1367 hgwebdir indexes will not descend into subdirectories. Only repositories
1359 directly in the current path will be shown (other repositories are still
1368 directly in the current path will be shown (other repositories are still
1360 available from the index corresponding to their containing path).
1369 available from the index corresponding to their containing path).
1361
1370
1362 ``description``
1371 ``description``
1363 Textual description of the repository's purpose or contents.
1372 Textual description of the repository's purpose or contents.
1364 Default is "unknown".
1373 Default is "unknown".
1365
1374
1366 ``encoding``
1375 ``encoding``
1367 Character encoding name. Default is the current locale charset.
1376 Character encoding name. Default is the current locale charset.
1368 Example: "UTF-8"
1377 Example: "UTF-8"
1369
1378
1370 ``errorlog``
1379 ``errorlog``
1371 Where to output the error log. Default is stderr.
1380 Where to output the error log. Default is stderr.
1372
1381
1373 ``hidden``
1382 ``hidden``
1374 Whether to hide the repository in the hgwebdir index.
1383 Whether to hide the repository in the hgwebdir index.
1375 Default is False.
1384 Default is False.
1376
1385
1377 ``ipv6``
1386 ``ipv6``
1378 Whether to use IPv6. Default is False.
1387 Whether to use IPv6. Default is False.
1379
1388
1380 ``logoimg``
1389 ``logoimg``
1381 File name of the logo image that some templates display on each page.
1390 File name of the logo image that some templates display on each page.
1382 The file name is relative to ``staticurl``. That is, the full path to
1391 The file name is relative to ``staticurl``. That is, the full path to
1383 the logo image is "staticurl/logoimg".
1392 the logo image is "staticurl/logoimg".
1384 If unset, ``hglogo.png`` will be used.
1393 If unset, ``hglogo.png`` will be used.
1385
1394
1386 ``logourl``
1395 ``logourl``
1387 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1396 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1388 will be used.
1397 will be used.
1389
1398
1390 ``name``
1399 ``name``
1391 Repository name to use in the web interface. Default is current
1400 Repository name to use in the web interface. Default is current
1392 working directory.
1401 working directory.
1393
1402
1394 ``maxchanges``
1403 ``maxchanges``
1395 Maximum number of changes to list on the changelog. Default is 10.
1404 Maximum number of changes to list on the changelog. Default is 10.
1396
1405
1397 ``maxfiles``
1406 ``maxfiles``
1398 Maximum number of files to list per changeset. Default is 10.
1407 Maximum number of files to list per changeset. Default is 10.
1399
1408
1400 ``port``
1409 ``port``
1401 Port to listen on. Default is 8000.
1410 Port to listen on. Default is 8000.
1402
1411
1403 ``prefix``
1412 ``prefix``
1404 Prefix path to serve from. Default is '' (server root).
1413 Prefix path to serve from. Default is '' (server root).
1405
1414
1406 ``push_ssl``
1415 ``push_ssl``
1407 Whether to require that inbound pushes be transported over SSL to
1416 Whether to require that inbound pushes be transported over SSL to
1408 prevent password sniffing. Default is True.
1417 prevent password sniffing. Default is True.
1409
1418
1410 ``staticurl``
1419 ``staticurl``
1411 Base URL to use for static files. If unset, static files (e.g. the
1420 Base URL to use for static files. If unset, static files (e.g. the
1412 hgicon.png favicon) will be served by the CGI script itself. Use
1421 hgicon.png favicon) will be served by the CGI script itself. Use
1413 this setting to serve them directly with the HTTP server.
1422 this setting to serve them directly with the HTTP server.
1414 Example: ``http://hgserver/static/``.
1423 Example: ``http://hgserver/static/``.
1415
1424
1416 ``stripes``
1425 ``stripes``
1417 How many lines a "zebra stripe" should span in multiline output.
1426 How many lines a "zebra stripe" should span in multiline output.
1418 Default is 1; set to 0 to disable.
1427 Default is 1; set to 0 to disable.
1419
1428
1420 ``style``
1429 ``style``
1421 Which template map style to use.
1430 Which template map style to use.
1422
1431
1423 ``templates``
1432 ``templates``
1424 Where to find the HTML templates. Default is install path.
1433 Where to find the HTML templates. Default is install path.
@@ -1,1195 +1,1186 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #include <Python.h>
10 #include <Python.h>
11 #include <ctype.h>
11 #include <ctype.h>
12 #include <string.h>
12 #include <string.h>
13
13
14 #include "util.h"
14 #include "util.h"
15
15
16 static int hexdigit(char c)
16 static int hexdigit(char c)
17 {
17 {
18 if (c >= '0' && c <= '9')
18 if (c >= '0' && c <= '9')
19 return c - '0';
19 return c - '0';
20 if (c >= 'a' && c <= 'f')
20 if (c >= 'a' && c <= 'f')
21 return c - 'a' + 10;
21 return c - 'a' + 10;
22 if (c >= 'A' && c <= 'F')
22 if (c >= 'A' && c <= 'F')
23 return c - 'A' + 10;
23 return c - 'A' + 10;
24
24
25 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
25 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
26 return 0;
26 return 0;
27 }
27 }
28
28
29 /*
29 /*
30 * Turn a hex-encoded string into binary.
30 * Turn a hex-encoded string into binary.
31 */
31 */
32 static PyObject *unhexlify(const char *str, int len)
32 static PyObject *unhexlify(const char *str, int len)
33 {
33 {
34 PyObject *ret;
34 PyObject *ret;
35 const char *c;
35 const char *c;
36 char *d;
36 char *d;
37
37
38 ret = PyBytes_FromStringAndSize(NULL, len / 2);
38 ret = PyBytes_FromStringAndSize(NULL, len / 2);
39
39
40 if (!ret)
40 if (!ret)
41 return NULL;
41 return NULL;
42
42
43 d = PyBytes_AsString(ret);
43 d = PyBytes_AsString(ret);
44
44
45 for (c = str; c < str + len;) {
45 for (c = str; c < str + len;) {
46 int hi = hexdigit(*c++);
46 int hi = hexdigit(*c++);
47 int lo = hexdigit(*c++);
47 int lo = hexdigit(*c++);
48 *d++ = (hi << 4) | lo;
48 *d++ = (hi << 4) | lo;
49 }
49 }
50
50
51 return ret;
51 return ret;
52 }
52 }
53
53
54 /*
54 /*
55 * This code assumes that a manifest is stitched together with newline
55 * This code assumes that a manifest is stitched together with newline
56 * ('\n') characters.
56 * ('\n') characters.
57 */
57 */
58 static PyObject *parse_manifest(PyObject *self, PyObject *args)
58 static PyObject *parse_manifest(PyObject *self, PyObject *args)
59 {
59 {
60 PyObject *mfdict, *fdict;
60 PyObject *mfdict, *fdict;
61 char *str, *cur, *start, *zero;
61 char *str, *cur, *start, *zero;
62 int len;
62 int len;
63
63
64 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
64 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
65 &PyDict_Type, &mfdict,
65 &PyDict_Type, &mfdict,
66 &PyDict_Type, &fdict,
66 &PyDict_Type, &fdict,
67 &str, &len))
67 &str, &len))
68 goto quit;
68 goto quit;
69
69
70 for (start = cur = str, zero = NULL; cur < str + len; cur++) {
70 for (start = cur = str, zero = NULL; cur < str + len; cur++) {
71 PyObject *file = NULL, *node = NULL;
71 PyObject *file = NULL, *node = NULL;
72 PyObject *flags = NULL;
72 PyObject *flags = NULL;
73 int nlen;
73 int nlen;
74
74
75 if (!*cur) {
75 if (!*cur) {
76 zero = cur;
76 zero = cur;
77 continue;
77 continue;
78 }
78 }
79 else if (*cur != '\n')
79 else if (*cur != '\n')
80 continue;
80 continue;
81
81
82 if (!zero) {
82 if (!zero) {
83 PyErr_SetString(PyExc_ValueError,
83 PyErr_SetString(PyExc_ValueError,
84 "manifest entry has no separator");
84 "manifest entry has no separator");
85 goto quit;
85 goto quit;
86 }
86 }
87
87
88 file = PyBytes_FromStringAndSize(start, zero - start);
88 file = PyBytes_FromStringAndSize(start, zero - start);
89
89
90 if (!file)
90 if (!file)
91 goto bail;
91 goto bail;
92
92
93 nlen = cur - zero - 1;
93 nlen = cur - zero - 1;
94
94
95 node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen);
95 node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen);
96 if (!node)
96 if (!node)
97 goto bail;
97 goto bail;
98
98
99 if (nlen > 40) {
99 if (nlen > 40) {
100 flags = PyBytes_FromStringAndSize(zero + 41,
100 flags = PyBytes_FromStringAndSize(zero + 41,
101 nlen - 40);
101 nlen - 40);
102 if (!flags)
102 if (!flags)
103 goto bail;
103 goto bail;
104
104
105 if (PyDict_SetItem(fdict, file, flags) == -1)
105 if (PyDict_SetItem(fdict, file, flags) == -1)
106 goto bail;
106 goto bail;
107 }
107 }
108
108
109 if (PyDict_SetItem(mfdict, file, node) == -1)
109 if (PyDict_SetItem(mfdict, file, node) == -1)
110 goto bail;
110 goto bail;
111
111
112 start = cur + 1;
112 start = cur + 1;
113 zero = NULL;
113 zero = NULL;
114
114
115 Py_XDECREF(flags);
115 Py_XDECREF(flags);
116 Py_XDECREF(node);
116 Py_XDECREF(node);
117 Py_XDECREF(file);
117 Py_XDECREF(file);
118 continue;
118 continue;
119 bail:
119 bail:
120 Py_XDECREF(flags);
120 Py_XDECREF(flags);
121 Py_XDECREF(node);
121 Py_XDECREF(node);
122 Py_XDECREF(file);
122 Py_XDECREF(file);
123 goto quit;
123 goto quit;
124 }
124 }
125
125
126 if (len > 0 && *(cur - 1) != '\n') {
126 if (len > 0 && *(cur - 1) != '\n') {
127 PyErr_SetString(PyExc_ValueError,
127 PyErr_SetString(PyExc_ValueError,
128 "manifest contains trailing garbage");
128 "manifest contains trailing garbage");
129 goto quit;
129 goto quit;
130 }
130 }
131
131
132 Py_INCREF(Py_None);
132 Py_INCREF(Py_None);
133 return Py_None;
133 return Py_None;
134 quit:
134 quit:
135 return NULL;
135 return NULL;
136 }
136 }
137
137
138 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
138 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
139 {
139 {
140 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
140 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
141 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
141 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
142 char *str, *cur, *end, *cpos;
142 char *str, *cur, *end, *cpos;
143 int state, mode, size, mtime;
143 int state, mode, size, mtime;
144 unsigned int flen;
144 unsigned int flen;
145 int len;
145 int len;
146
146
147 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
147 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
148 &PyDict_Type, &dmap,
148 &PyDict_Type, &dmap,
149 &PyDict_Type, &cmap,
149 &PyDict_Type, &cmap,
150 &str, &len))
150 &str, &len))
151 goto quit;
151 goto quit;
152
152
153 /* read parents */
153 /* read parents */
154 if (len < 40)
154 if (len < 40)
155 goto quit;
155 goto quit;
156
156
157 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
157 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
158 if (!parents)
158 if (!parents)
159 goto quit;
159 goto quit;
160
160
161 /* read filenames */
161 /* read filenames */
162 cur = str + 40;
162 cur = str + 40;
163 end = str + len;
163 end = str + len;
164
164
165 while (cur < end - 17) {
165 while (cur < end - 17) {
166 /* unpack header */
166 /* unpack header */
167 state = *cur;
167 state = *cur;
168 mode = getbe32(cur + 1);
168 mode = getbe32(cur + 1);
169 size = getbe32(cur + 5);
169 size = getbe32(cur + 5);
170 mtime = getbe32(cur + 9);
170 mtime = getbe32(cur + 9);
171 flen = getbe32(cur + 13);
171 flen = getbe32(cur + 13);
172 cur += 17;
172 cur += 17;
173 if (cur + flen > end || cur + flen < cur) {
173 if (cur + flen > end || cur + flen < cur) {
174 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
174 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
175 goto quit;
175 goto quit;
176 }
176 }
177
177
178 entry = Py_BuildValue("ciii", state, mode, size, mtime);
178 entry = Py_BuildValue("ciii", state, mode, size, mtime);
179 if (!entry)
179 if (!entry)
180 goto quit;
180 goto quit;
181 PyObject_GC_UnTrack(entry); /* don't waste time with this */
181 PyObject_GC_UnTrack(entry); /* don't waste time with this */
182
182
183 cpos = memchr(cur, 0, flen);
183 cpos = memchr(cur, 0, flen);
184 if (cpos) {
184 if (cpos) {
185 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
185 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
186 cname = PyBytes_FromStringAndSize(cpos + 1,
186 cname = PyBytes_FromStringAndSize(cpos + 1,
187 flen - (cpos - cur) - 1);
187 flen - (cpos - cur) - 1);
188 if (!fname || !cname ||
188 if (!fname || !cname ||
189 PyDict_SetItem(cmap, fname, cname) == -1 ||
189 PyDict_SetItem(cmap, fname, cname) == -1 ||
190 PyDict_SetItem(dmap, fname, entry) == -1)
190 PyDict_SetItem(dmap, fname, entry) == -1)
191 goto quit;
191 goto quit;
192 Py_DECREF(cname);
192 Py_DECREF(cname);
193 } else {
193 } else {
194 fname = PyBytes_FromStringAndSize(cur, flen);
194 fname = PyBytes_FromStringAndSize(cur, flen);
195 if (!fname ||
195 if (!fname ||
196 PyDict_SetItem(dmap, fname, entry) == -1)
196 PyDict_SetItem(dmap, fname, entry) == -1)
197 goto quit;
197 goto quit;
198 }
198 }
199 cur += flen;
199 cur += flen;
200 Py_DECREF(fname);
200 Py_DECREF(fname);
201 Py_DECREF(entry);
201 Py_DECREF(entry);
202 fname = cname = entry = NULL;
202 fname = cname = entry = NULL;
203 }
203 }
204
204
205 ret = parents;
205 ret = parents;
206 Py_INCREF(ret);
206 Py_INCREF(ret);
207 quit:
207 quit:
208 Py_XDECREF(fname);
208 Py_XDECREF(fname);
209 Py_XDECREF(cname);
209 Py_XDECREF(cname);
210 Py_XDECREF(entry);
210 Py_XDECREF(entry);
211 Py_XDECREF(parents);
211 Py_XDECREF(parents);
212 return ret;
212 return ret;
213 }
213 }
214
214
215 /*
215 /*
216 * A base-16 trie for fast node->rev mapping.
216 * A base-16 trie for fast node->rev mapping.
217 *
217 *
218 * Positive value is index of the next node in the trie
218 * Positive value is index of the next node in the trie
219 * Negative value is a leaf: -(rev + 1)
219 * Negative value is a leaf: -(rev + 1)
220 * Zero is empty
220 * Zero is empty
221 */
221 */
222 typedef struct {
222 typedef struct {
223 int children[16];
223 int children[16];
224 } nodetree;
224 } nodetree;
225
225
226 /*
226 /*
227 * This class has two behaviours.
227 * This class has two behaviours.
228 *
228 *
229 * When used in a list-like way (with integer keys), we decode an
229 * When used in a list-like way (with integer keys), we decode an
230 * entry in a RevlogNG index file on demand. Our last entry is a
230 * entry in a RevlogNG index file on demand. Our last entry is a
231 * sentinel, always a nullid. We have limited support for
231 * sentinel, always a nullid. We have limited support for
232 * integer-keyed insert and delete, only at elements right before the
232 * integer-keyed insert and delete, only at elements right before the
233 * sentinel.
233 * sentinel.
234 *
234 *
235 * With string keys, we lazily perform a reverse mapping from node to
235 * With string keys, we lazily perform a reverse mapping from node to
236 * rev, using a base-16 trie.
236 * rev, using a base-16 trie.
237 */
237 */
238 typedef struct {
238 typedef struct {
239 PyObject_HEAD
239 PyObject_HEAD
240 /* Type-specific fields go here. */
240 /* Type-specific fields go here. */
241 PyObject *data; /* raw bytes of index */
241 PyObject *data; /* raw bytes of index */
242 PyObject **cache; /* cached tuples */
242 PyObject **cache; /* cached tuples */
243 const char **offsets; /* populated on demand */
243 const char **offsets; /* populated on demand */
244 Py_ssize_t raw_length; /* original number of elements */
244 Py_ssize_t raw_length; /* original number of elements */
245 Py_ssize_t length; /* current number of elements */
245 Py_ssize_t length; /* current number of elements */
246 PyObject *added; /* populated on demand */
246 PyObject *added; /* populated on demand */
247 nodetree *nt; /* base-16 trie */
247 nodetree *nt; /* base-16 trie */
248 int ntlength; /* # nodes in use */
248 int ntlength; /* # nodes in use */
249 int ntcapacity; /* # nodes allocated */
249 int ntcapacity; /* # nodes allocated */
250 int ntdepth; /* maximum depth of tree */
250 int ntdepth; /* maximum depth of tree */
251 int ntsplits; /* # splits performed */
251 int ntsplits; /* # splits performed */
252 int ntrev; /* last rev scanned */
252 int ntrev; /* last rev scanned */
253 int ntlookups; /* # lookups */
253 int ntlookups; /* # lookups */
254 int ntmisses; /* # lookups that miss the cache */
254 int ntmisses; /* # lookups that miss the cache */
255 int inlined;
255 int inlined;
256 } indexObject;
256 } indexObject;
257
257
258 static Py_ssize_t index_length(const indexObject *self)
258 static Py_ssize_t index_length(const indexObject *self)
259 {
259 {
260 if (self->added == NULL)
260 if (self->added == NULL)
261 return self->length;
261 return self->length;
262 return self->length + PyList_GET_SIZE(self->added);
262 return self->length + PyList_GET_SIZE(self->added);
263 }
263 }
264
264
265 static PyObject *nullentry;
265 static PyObject *nullentry;
266 static const char nullid[20];
266 static const char nullid[20];
267
267
268 static long inline_scan(indexObject *self, const char **offsets);
268 static long inline_scan(indexObject *self, const char **offsets);
269
269
270 #if LONG_MAX == 0x7fffffffL
270 #if LONG_MAX == 0x7fffffffL
271 static char *tuple_format = "Kiiiiiis#";
271 static char *tuple_format = "Kiiiiiis#";
272 #else
272 #else
273 static char *tuple_format = "kiiiiiis#";
273 static char *tuple_format = "kiiiiiis#";
274 #endif
274 #endif
275
275
276 /*
276 /*
277 * Return a pointer to the beginning of a RevlogNG record.
277 * Return a pointer to the beginning of a RevlogNG record.
278 */
278 */
279 static const char *index_deref(indexObject *self, Py_ssize_t pos)
279 static const char *index_deref(indexObject *self, Py_ssize_t pos)
280 {
280 {
281 if (self->inlined && pos > 0) {
281 if (self->inlined && pos > 0) {
282 if (self->offsets == NULL) {
282 if (self->offsets == NULL) {
283 self->offsets = malloc(self->raw_length *
283 self->offsets = malloc(self->raw_length *
284 sizeof(*self->offsets));
284 sizeof(*self->offsets));
285 if (self->offsets == NULL)
285 if (self->offsets == NULL)
286 return (const char *)PyErr_NoMemory();
286 return (const char *)PyErr_NoMemory();
287 inline_scan(self, self->offsets);
287 inline_scan(self, self->offsets);
288 }
288 }
289 return self->offsets[pos];
289 return self->offsets[pos];
290 }
290 }
291
291
292 return PyString_AS_STRING(self->data) + pos * 64;
292 return PyString_AS_STRING(self->data) + pos * 64;
293 }
293 }
294
294
295 /*
295 /*
296 * RevlogNG format (all in big endian, data may be inlined):
296 * RevlogNG format (all in big endian, data may be inlined):
297 * 6 bytes: offset
297 * 6 bytes: offset
298 * 2 bytes: flags
298 * 2 bytes: flags
299 * 4 bytes: compressed length
299 * 4 bytes: compressed length
300 * 4 bytes: uncompressed length
300 * 4 bytes: uncompressed length
301 * 4 bytes: base revision
301 * 4 bytes: base revision
302 * 4 bytes: link revision
302 * 4 bytes: link revision
303 * 4 bytes: parent 1 revision
303 * 4 bytes: parent 1 revision
304 * 4 bytes: parent 2 revision
304 * 4 bytes: parent 2 revision
305 * 32 bytes: nodeid (only 20 bytes used)
305 * 32 bytes: nodeid (only 20 bytes used)
306 */
306 */
307 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
307 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
308 {
308 {
309 uint64_t offset_flags;
309 uint64_t offset_flags;
310 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
310 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
311 const char *c_node_id;
311 const char *c_node_id;
312 const char *data;
312 const char *data;
313 Py_ssize_t length = index_length(self);
313 Py_ssize_t length = index_length(self);
314 PyObject *entry;
314 PyObject *entry;
315
315
316 if (pos < 0)
316 if (pos < 0)
317 pos += length;
317 pos += length;
318
318
319 if (pos < 0 || pos >= length) {
319 if (pos < 0 || pos >= length) {
320 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
320 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
321 return NULL;
321 return NULL;
322 }
322 }
323
323
324 if (pos == length - 1) {
324 if (pos == length - 1) {
325 Py_INCREF(nullentry);
325 Py_INCREF(nullentry);
326 return nullentry;
326 return nullentry;
327 }
327 }
328
328
329 if (pos >= self->length - 1) {
329 if (pos >= self->length - 1) {
330 PyObject *obj;
330 PyObject *obj;
331 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
331 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
332 Py_INCREF(obj);
332 Py_INCREF(obj);
333 return obj;
333 return obj;
334 }
334 }
335
335
336 if (self->cache) {
336 if (self->cache) {
337 if (self->cache[pos]) {
337 if (self->cache[pos]) {
338 Py_INCREF(self->cache[pos]);
338 Py_INCREF(self->cache[pos]);
339 return self->cache[pos];
339 return self->cache[pos];
340 }
340 }
341 } else {
341 } else {
342 self->cache = calloc(self->raw_length, sizeof(PyObject *));
342 self->cache = calloc(self->raw_length, sizeof(PyObject *));
343 if (self->cache == NULL)
343 if (self->cache == NULL)
344 return PyErr_NoMemory();
344 return PyErr_NoMemory();
345 }
345 }
346
346
347 data = index_deref(self, pos);
347 data = index_deref(self, pos);
348 if (data == NULL)
348 if (data == NULL)
349 return NULL;
349 return NULL;
350
350
351 offset_flags = getbe32(data + 4);
351 offset_flags = getbe32(data + 4);
352 if (pos == 0) /* mask out version number for the first entry */
352 if (pos == 0) /* mask out version number for the first entry */
353 offset_flags &= 0xFFFF;
353 offset_flags &= 0xFFFF;
354 else {
354 else {
355 uint32_t offset_high = getbe32(data);
355 uint32_t offset_high = getbe32(data);
356 offset_flags |= ((uint64_t)offset_high) << 32;
356 offset_flags |= ((uint64_t)offset_high) << 32;
357 }
357 }
358
358
359 comp_len = getbe32(data + 8);
359 comp_len = getbe32(data + 8);
360 uncomp_len = getbe32(data + 12);
360 uncomp_len = getbe32(data + 12);
361 base_rev = getbe32(data + 16);
361 base_rev = getbe32(data + 16);
362 link_rev = getbe32(data + 20);
362 link_rev = getbe32(data + 20);
363 parent_1 = getbe32(data + 24);
363 parent_1 = getbe32(data + 24);
364 parent_2 = getbe32(data + 28);
364 parent_2 = getbe32(data + 28);
365 c_node_id = data + 32;
365 c_node_id = data + 32;
366
366
367 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
367 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
368 uncomp_len, base_rev, link_rev,
368 uncomp_len, base_rev, link_rev,
369 parent_1, parent_2, c_node_id, 20);
369 parent_1, parent_2, c_node_id, 20);
370
370
371 if (entry)
371 if (entry)
372 PyObject_GC_UnTrack(entry);
372 PyObject_GC_UnTrack(entry);
373
373
374 self->cache[pos] = entry;
374 self->cache[pos] = entry;
375 Py_INCREF(entry);
375 Py_INCREF(entry);
376
376
377 return entry;
377 return entry;
378 }
378 }
379
379
380 /*
380 /*
381 * Return the 20-byte SHA of the node corresponding to the given rev.
381 * Return the 20-byte SHA of the node corresponding to the given rev.
382 */
382 */
383 static const char *index_node(indexObject *self, Py_ssize_t pos)
383 static const char *index_node(indexObject *self, Py_ssize_t pos)
384 {
384 {
385 Py_ssize_t length = index_length(self);
385 Py_ssize_t length = index_length(self);
386 const char *data;
386 const char *data;
387
387
388 if (pos == length - 1)
388 if (pos == length - 1)
389 return nullid;
389 return nullid;
390
390
391 if (pos >= length)
391 if (pos >= length)
392 return NULL;
392 return NULL;
393
393
394 if (pos >= self->length - 1) {
394 if (pos >= self->length - 1) {
395 PyObject *tuple, *str;
395 PyObject *tuple, *str;
396 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
396 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
397 str = PyTuple_GetItem(tuple, 7);
397 str = PyTuple_GetItem(tuple, 7);
398 return str ? PyString_AS_STRING(str) : NULL;
398 return str ? PyString_AS_STRING(str) : NULL;
399 }
399 }
400
400
401 data = index_deref(self, pos);
401 data = index_deref(self, pos);
402 return data ? data + 32 : NULL;
402 return data ? data + 32 : NULL;
403 }
403 }
404
404
405 static int nt_insert(indexObject *self, const char *node, int rev);
405 static int nt_insert(indexObject *self, const char *node, int rev);
406
406
407 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
407 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
408 {
408 {
409 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
409 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
410 return -1;
410 return -1;
411 if (*nodelen == 20)
411 if (*nodelen == 20)
412 return 0;
412 return 0;
413 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
413 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
414 return -1;
414 return -1;
415 }
415 }
416
416
417 static PyObject *index_insert(indexObject *self, PyObject *args)
417 static PyObject *index_insert(indexObject *self, PyObject *args)
418 {
418 {
419 PyObject *obj;
419 PyObject *obj;
420 char *node;
420 char *node;
421 long offset;
421 long offset;
422 Py_ssize_t len, nodelen;
422 Py_ssize_t len, nodelen;
423
423
424 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
424 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
425 return NULL;
425 return NULL;
426
426
427 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
427 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
428 PyErr_SetString(PyExc_TypeError, "8-tuple required");
428 PyErr_SetString(PyExc_TypeError, "8-tuple required");
429 return NULL;
429 return NULL;
430 }
430 }
431
431
432 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
432 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
433 return NULL;
433 return NULL;
434
434
435 len = index_length(self);
435 len = index_length(self);
436
436
437 if (offset < 0)
437 if (offset < 0)
438 offset += len;
438 offset += len;
439
439
440 if (offset != len - 1) {
440 if (offset != len - 1) {
441 PyErr_SetString(PyExc_IndexError,
441 PyErr_SetString(PyExc_IndexError,
442 "insert only supported at index -1");
442 "insert only supported at index -1");
443 return NULL;
443 return NULL;
444 }
444 }
445
445
446 if (offset > INT_MAX) {
446 if (offset > INT_MAX) {
447 PyErr_SetString(PyExc_ValueError,
447 PyErr_SetString(PyExc_ValueError,
448 "currently only 2**31 revs supported");
448 "currently only 2**31 revs supported");
449 return NULL;
449 return NULL;
450 }
450 }
451
451
452 if (self->added == NULL) {
452 if (self->added == NULL) {
453 self->added = PyList_New(0);
453 self->added = PyList_New(0);
454 if (self->added == NULL)
454 if (self->added == NULL)
455 return NULL;
455 return NULL;
456 }
456 }
457
457
458 if (PyList_Append(self->added, obj) == -1)
458 if (PyList_Append(self->added, obj) == -1)
459 return NULL;
459 return NULL;
460
460
461 if (self->nt)
461 if (self->nt)
462 nt_insert(self, node, (int)offset);
462 nt_insert(self, node, (int)offset);
463
463
464 Py_RETURN_NONE;
464 Py_RETURN_NONE;
465 }
465 }
466
466
467 static void _index_clearcaches(indexObject *self)
467 static void _index_clearcaches(indexObject *self)
468 {
468 {
469 if (self->cache) {
469 if (self->cache) {
470 Py_ssize_t i;
470 Py_ssize_t i;
471
471
472 for (i = 0; i < self->raw_length; i++) {
472 for (i = 0; i < self->raw_length; i++) {
473 Py_XDECREF(self->cache[i]);
473 if (self->cache[i]) {
474 self->cache[i] = NULL;
474 Py_DECREF(self->cache[i]);
475 self->cache[i] = NULL;
476 }
475 }
477 }
476 free(self->cache);
478 free(self->cache);
477 self->cache = NULL;
479 self->cache = NULL;
478 }
480 }
479 if (self->offsets) {
481 if (self->offsets) {
480 free(self->offsets);
482 free(self->offsets);
481 self->offsets = NULL;
483 self->offsets = NULL;
482 }
484 }
483 if (self->nt) {
485 if (self->nt) {
484 free(self->nt);
486 free(self->nt);
485 self->nt = NULL;
487 self->nt = NULL;
486 }
488 }
487 }
489 }
488
490
489 static PyObject *index_clearcaches(indexObject *self)
491 static PyObject *index_clearcaches(indexObject *self)
490 {
492 {
491 _index_clearcaches(self);
493 _index_clearcaches(self);
492 self->ntlength = self->ntcapacity = 0;
494 self->ntlength = self->ntcapacity = 0;
493 self->ntdepth = self->ntsplits = 0;
495 self->ntdepth = self->ntsplits = 0;
494 self->ntrev = -1;
496 self->ntrev = -1;
495 self->ntlookups = self->ntmisses = 0;
497 self->ntlookups = self->ntmisses = 0;
496 Py_RETURN_NONE;
498 Py_RETURN_NONE;
497 }
499 }
498
500
499 static PyObject *index_stats(indexObject *self)
501 static PyObject *index_stats(indexObject *self)
500 {
502 {
501 PyObject *obj = PyDict_New();
503 PyObject *obj = PyDict_New();
502
504
503 if (obj == NULL)
505 if (obj == NULL)
504 return NULL;
506 return NULL;
505
507
506 #define istat(__n, __d) \
508 #define istat(__n, __d) \
507 if (PyDict_SetItemString(obj, __d, PyInt_FromLong(self->__n)) == -1) \
509 if (PyDict_SetItemString(obj, __d, PyInt_FromLong(self->__n)) == -1) \
508 goto bail;
510 goto bail;
509
511
510 if (self->added) {
512 if (self->added) {
511 Py_ssize_t len = PyList_GET_SIZE(self->added);
513 Py_ssize_t len = PyList_GET_SIZE(self->added);
512 if (PyDict_SetItemString(obj, "index entries added",
514 if (PyDict_SetItemString(obj, "index entries added",
513 PyInt_FromLong(len)) == -1)
515 PyInt_FromLong(len)) == -1)
514 goto bail;
516 goto bail;
515 }
517 }
516
518
517 if (self->raw_length != self->length - 1)
519 if (self->raw_length != self->length - 1)
518 istat(raw_length, "revs on disk");
520 istat(raw_length, "revs on disk");
519 istat(length, "revs in memory");
521 istat(length, "revs in memory");
520 istat(ntcapacity, "node trie capacity");
522 istat(ntcapacity, "node trie capacity");
521 istat(ntdepth, "node trie depth");
523 istat(ntdepth, "node trie depth");
522 istat(ntlength, "node trie count");
524 istat(ntlength, "node trie count");
523 istat(ntlookups, "node trie lookups");
525 istat(ntlookups, "node trie lookups");
524 istat(ntmisses, "node trie misses");
526 istat(ntmisses, "node trie misses");
525 istat(ntrev, "node trie last rev scanned");
527 istat(ntrev, "node trie last rev scanned");
526 istat(ntsplits, "node trie splits");
528 istat(ntsplits, "node trie splits");
527
529
528 #undef istat
530 #undef istat
529
531
530 return obj;
532 return obj;
531
533
532 bail:
534 bail:
533 Py_XDECREF(obj);
535 Py_XDECREF(obj);
534 return NULL;
536 return NULL;
535 }
537 }
536
538
537 static inline int nt_level(const char *node, int level)
539 static inline int nt_level(const char *node, int level)
538 {
540 {
539 int v = node[level>>1];
541 int v = node[level>>1];
540 if (!(level & 1))
542 if (!(level & 1))
541 v >>= 4;
543 v >>= 4;
542 return v & 0xf;
544 return v & 0xf;
543 }
545 }
544
546
545 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen)
547 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen)
546 {
548 {
547 int level, off;
549 int level, off;
548
550
549 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
551 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
550 return -1;
552 return -1;
551
553
552 if (self->nt == NULL)
554 if (self->nt == NULL)
553 return -2;
555 return -2;
554
556
555 for (level = off = 0; level < nodelen; level++) {
557 for (level = off = 0; level < nodelen; level++) {
556 int k = nt_level(node, level);
558 int k = nt_level(node, level);
557 nodetree *n = &self->nt[off];
559 nodetree *n = &self->nt[off];
558 int v = n->children[k];
560 int v = n->children[k];
559
561
560 if (v < 0) {
562 if (v < 0) {
561 const char *n;
563 const char *n;
562 v = -v - 1;
564 v = -v - 1;
563 n = index_node(self, v);
565 n = index_node(self, v);
564 if (n == NULL)
566 if (n == NULL)
565 return -2;
567 return -2;
566 return memcmp(node, n, nodelen > 20 ? 20 : nodelen)
568 return memcmp(node, n, nodelen > 20 ? 20 : nodelen)
567 ? -2 : v;
569 ? -2 : v;
568 }
570 }
569 if (v == 0)
571 if (v == 0)
570 return -2;
572 return -2;
571 off = v;
573 off = v;
572 }
574 }
573 return -2;
575 return -2;
574 }
576 }
575
577
576 static int nt_new(indexObject *self)
578 static int nt_new(indexObject *self)
577 {
579 {
578 if (self->ntlength == self->ntcapacity) {
580 if (self->ntlength == self->ntcapacity) {
579 self->ntcapacity *= 2;
581 self->ntcapacity *= 2;
580 self->nt = realloc(self->nt,
582 self->nt = realloc(self->nt,
581 self->ntcapacity * sizeof(nodetree));
583 self->ntcapacity * sizeof(nodetree));
582 if (self->nt == NULL) {
584 if (self->nt == NULL) {
583 PyErr_SetString(PyExc_MemoryError, "out of memory");
585 PyErr_SetString(PyExc_MemoryError, "out of memory");
584 return -1;
586 return -1;
585 }
587 }
586 memset(&self->nt[self->ntlength], 0,
588 memset(&self->nt[self->ntlength], 0,
587 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
589 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
588 }
590 }
589 return self->ntlength++;
591 return self->ntlength++;
590 }
592 }
591
593
592 static int nt_insert(indexObject *self, const char *node, int rev)
594 static int nt_insert(indexObject *self, const char *node, int rev)
593 {
595 {
594 int level = 0;
596 int level = 0;
595 int off = 0;
597 int off = 0;
596
598
597 while (level < 20) {
599 while (level < 20) {
598 int k = nt_level(node, level);
600 int k = nt_level(node, level);
599 nodetree *n;
601 nodetree *n;
600 int v;
602 int v;
601
603
602 n = &self->nt[off];
604 n = &self->nt[off];
603 v = n->children[k];
605 v = n->children[k];
604
606
605 if (v == 0) {
607 if (v == 0) {
606 n->children[k] = -rev - 1;
608 n->children[k] = -rev - 1;
607 return 0;
609 return 0;
608 }
610 }
609 if (v < 0) {
611 if (v < 0) {
610 const char *oldnode = index_node(self, -v - 1);
612 const char *oldnode = index_node(self, -v - 1);
611 int noff;
613 int noff;
612
614
613 if (!oldnode || !memcmp(oldnode, node, 20)) {
615 if (!oldnode || !memcmp(oldnode, node, 20)) {
614 n->children[k] = -rev - 1;
616 n->children[k] = -rev - 1;
615 return 0;
617 return 0;
616 }
618 }
617 noff = nt_new(self);
619 noff = nt_new(self);
618 if (noff == -1)
620 if (noff == -1)
619 return -1;
621 return -1;
620 /* self->nt may have been changed by realloc */
622 /* self->nt may have been changed by realloc */
621 self->nt[off].children[k] = noff;
623 self->nt[off].children[k] = noff;
622 off = noff;
624 off = noff;
623 n = &self->nt[off];
625 n = &self->nt[off];
624 n->children[nt_level(oldnode, ++level)] = v;
626 n->children[nt_level(oldnode, ++level)] = v;
625 if (level > self->ntdepth)
627 if (level > self->ntdepth)
626 self->ntdepth = level;
628 self->ntdepth = level;
627 self->ntsplits += 1;
629 self->ntsplits += 1;
628 } else {
630 } else {
629 level += 1;
631 level += 1;
630 off = v;
632 off = v;
631 }
633 }
632 }
634 }
633
635
634 return -1;
636 return -1;
635 }
637 }
636
638
637 /*
639 /*
638 * Return values:
640 * Return values:
639 *
641 *
640 * -3: error (exception set)
642 * -3: error (exception set)
641 * -2: not found (no exception set)
643 * -2: not found (no exception set)
642 * rest: valid rev
644 * rest: valid rev
643 */
645 */
644 static int index_find_node(indexObject *self,
646 static int index_find_node(indexObject *self,
645 const char *node, Py_ssize_t nodelen)
647 const char *node, Py_ssize_t nodelen)
646 {
648 {
647 int rev;
649 int rev;
648
650
649 self->ntlookups++;
651 self->ntlookups++;
650 rev = nt_find(self, node, nodelen);
652 rev = nt_find(self, node, nodelen);
651 if (rev >= -1)
653 if (rev >= -1)
652 return rev;
654 return rev;
653
655
654 if (self->nt == NULL) {
656 if (self->nt == NULL) {
655 self->ntcapacity = self->raw_length < 4
657 self->ntcapacity = self->raw_length < 4
656 ? 4 : self->raw_length / 2;
658 ? 4 : self->raw_length / 2;
657 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
659 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
658 if (self->nt == NULL) {
660 if (self->nt == NULL) {
659 PyErr_SetString(PyExc_MemoryError, "out of memory");
661 PyErr_SetString(PyExc_MemoryError, "out of memory");
660 return -3;
662 return -3;
661 }
663 }
662 self->ntlength = 1;
664 self->ntlength = 1;
663 self->ntrev = (int)index_length(self) - 1;
665 self->ntrev = (int)index_length(self) - 1;
664 self->ntlookups = 1;
666 self->ntlookups = 1;
665 self->ntmisses = 0;
667 self->ntmisses = 0;
666 }
668 }
667
669
668 /*
670 /*
669 * For the first handful of lookups, we scan the entire index,
671 * For the first handful of lookups, we scan the entire index,
670 * and cache only the matching nodes. This optimizes for cases
672 * and cache only the matching nodes. This optimizes for cases
671 * like "hg tip", where only a few nodes are accessed.
673 * like "hg tip", where only a few nodes are accessed.
672 *
674 *
673 * After that, we cache every node we visit, using a single
675 * After that, we cache every node we visit, using a single
674 * scan amortized over multiple lookups. This gives the best
676 * scan amortized over multiple lookups. This gives the best
675 * bulk performance, e.g. for "hg log".
677 * bulk performance, e.g. for "hg log".
676 */
678 */
677 if (self->ntmisses++ < 4) {
679 if (self->ntmisses++ < 4) {
678 for (rev = self->ntrev - 1; rev >= 0; rev--) {
680 for (rev = self->ntrev - 1; rev >= 0; rev--) {
679 const char *n = index_node(self, rev);
681 const char *n = index_node(self, rev);
680 if (n == NULL)
682 if (n == NULL)
681 return -2;
683 return -2;
682 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
684 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
683 if (nt_insert(self, n, rev) == -1)
685 if (nt_insert(self, n, rev) == -1)
684 return -3;
686 return -3;
685 break;
687 break;
686 }
688 }
687 }
689 }
688 } else {
690 } else {
689 for (rev = self->ntrev - 1; rev >= 0; rev--) {
691 for (rev = self->ntrev - 1; rev >= 0; rev--) {
690 const char *n = index_node(self, rev);
692 const char *n = index_node(self, rev);
691 if (n == NULL)
693 if (n == NULL)
692 return -2;
694 return -2;
693 if (nt_insert(self, n, rev) == -1)
695 if (nt_insert(self, n, rev) == -1)
694 return -3;
696 return -3;
695 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
697 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
696 break;
698 break;
697 }
699 }
698 }
700 }
699 self->ntrev = rev;
701 self->ntrev = rev;
700 }
702 }
701
703
702 if (rev >= 0)
704 if (rev >= 0)
703 return rev;
705 return rev;
704 return -2;
706 return -2;
705 }
707 }
706
708
707 static PyObject *raise_revlog_error(void)
709 static PyObject *raise_revlog_error(void)
708 {
710 {
709 static PyObject *errclass;
711 static PyObject *errclass;
710 PyObject *mod = NULL, *errobj;
712 PyObject *mod = NULL, *errobj;
711
713
712 if (errclass == NULL) {
714 if (errclass == NULL) {
713 PyObject *dict;
715 PyObject *dict;
714
716
715 mod = PyImport_ImportModule("mercurial.error");
717 mod = PyImport_ImportModule("mercurial.error");
716 if (mod == NULL)
718 if (mod == NULL)
717 goto classfail;
719 goto classfail;
718
720
719 dict = PyModule_GetDict(mod);
721 dict = PyModule_GetDict(mod);
720 if (dict == NULL)
722 if (dict == NULL)
721 goto classfail;
723 goto classfail;
722
724
723 errclass = PyDict_GetItemString(dict, "RevlogError");
725 errclass = PyDict_GetItemString(dict, "RevlogError");
724 if (errclass == NULL) {
726 if (errclass == NULL) {
725 PyErr_SetString(PyExc_SystemError,
727 PyErr_SetString(PyExc_SystemError,
726 "could not find RevlogError");
728 "could not find RevlogError");
727 goto classfail;
729 goto classfail;
728 }
730 }
729 Py_INCREF(errclass);
731 Py_INCREF(errclass);
730 }
732 }
731
733
732 errobj = PyObject_CallFunction(errclass, NULL);
734 errobj = PyObject_CallFunction(errclass, NULL);
733 if (errobj == NULL)
735 if (errobj == NULL)
734 return NULL;
736 return NULL;
735 PyErr_SetObject(errclass, errobj);
737 PyErr_SetObject(errclass, errobj);
736 return errobj;
738 return errobj;
737
739
738 classfail:
740 classfail:
739 Py_XDECREF(mod);
741 Py_XDECREF(mod);
740 return NULL;
742 return NULL;
741 }
743 }
742
744
743 static PyObject *index_getitem(indexObject *self, PyObject *value)
745 static PyObject *index_getitem(indexObject *self, PyObject *value)
744 {
746 {
745 char *node;
747 char *node;
746 Py_ssize_t nodelen;
748 Py_ssize_t nodelen;
747 int rev;
749 int rev;
748
750
749 if (PyInt_Check(value))
751 if (PyInt_Check(value))
750 return index_get(self, PyInt_AS_LONG(value));
752 return index_get(self, PyInt_AS_LONG(value));
751
753
752 if (PyString_AsStringAndSize(value, &node, &nodelen) == -1)
754 if (PyString_AsStringAndSize(value, &node, &nodelen) == -1)
753 return NULL;
755 return NULL;
754 rev = index_find_node(self, node, nodelen);
756 rev = index_find_node(self, node, nodelen);
755 if (rev >= -1)
757 if (rev >= -1)
756 return PyInt_FromLong(rev);
758 return PyInt_FromLong(rev);
757 if (rev == -2)
759 if (rev == -2)
758 raise_revlog_error();
760 raise_revlog_error();
759 return NULL;
761 return NULL;
760 }
762 }
761
763
762 static PyObject *index_m_get(indexObject *self, PyObject *args)
764 static PyObject *index_m_get(indexObject *self, PyObject *args)
763 {
765 {
764 char *node;
766 char *node;
765 int nodelen, rev;
767 int nodelen, rev;
766
768
767 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
769 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
768 return NULL;
770 return NULL;
769
771
770 rev = index_find_node(self, node, nodelen);
772 rev = index_find_node(self, node, nodelen);
771 if (rev == -3)
773 if (rev == -3)
772 return NULL;
774 return NULL;
773 if (rev == -2)
775 if (rev == -2)
774 Py_RETURN_NONE;
776 Py_RETURN_NONE;
775 return PyInt_FromLong(rev);
777 return PyInt_FromLong(rev);
776 }
778 }
777
779
778 static int index_contains(indexObject *self, PyObject *value)
780 static int index_contains(indexObject *self, PyObject *value)
779 {
781 {
780 char *node;
782 char *node;
781 Py_ssize_t nodelen;
783 Py_ssize_t nodelen;
782
784
783 if (PyInt_Check(value)) {
785 if (PyInt_Check(value)) {
784 long rev = PyInt_AS_LONG(value);
786 long rev = PyInt_AS_LONG(value);
785 return rev >= -1 && rev < index_length(self);
787 return rev >= -1 && rev < index_length(self);
786 }
788 }
787
789
788 if (!PyString_Check(value))
790 if (!PyString_Check(value))
789 return 0;
791 return 0;
790
792
791 node = PyString_AS_STRING(value);
793 node = PyString_AS_STRING(value);
792 nodelen = PyString_GET_SIZE(value);
794 nodelen = PyString_GET_SIZE(value);
793
795
794 switch (index_find_node(self, node, nodelen)) {
796 switch (index_find_node(self, node, nodelen)) {
795 case -3:
797 case -3:
796 return -1;
798 return -1;
797 case -2:
799 case -2:
798 return 0;
800 return 0;
799 default:
801 default:
800 return 1;
802 return 1;
801 }
803 }
802 }
804 }
803
805
804 /*
806 /*
805 * Invalidate any trie entries introduced by added revs.
807 * Invalidate any trie entries introduced by added revs.
806 */
808 */
807 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
809 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
808 {
810 {
809 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
811 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
810
812
811 for (i = start; i < len; i++) {
813 for (i = start; i < len; i++) {
812 PyObject *tuple = PyList_GET_ITEM(self->added, i);
814 PyObject *tuple = PyList_GET_ITEM(self->added, i);
813 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
815 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
814
816
815 nt_insert(self, PyString_AS_STRING(node), -1);
817 nt_insert(self, PyString_AS_STRING(node), -1);
816 }
818 }
817
819
818 if (start == 0) {
820 if (start == 0) {
819 Py_DECREF(self->added);
821 Py_DECREF(self->added);
820 self->added = NULL;
822 self->added = NULL;
821 }
823 }
822 }
824 }
823
825
824 /*
826 /*
825 * Delete a numeric range of revs, which must be at the end of the
827 * Delete a numeric range of revs, which must be at the end of the
826 * range, but exclude the sentinel nullid entry.
828 * range, but exclude the sentinel nullid entry.
827 */
829 */
828 static int index_slice_del(indexObject *self, PyObject *item)
830 static int index_slice_del(indexObject *self, PyObject *item)
829 {
831 {
830 Py_ssize_t start, stop, step, slicelength;
832 Py_ssize_t start, stop, step, slicelength;
831 Py_ssize_t length = index_length(self);
833 Py_ssize_t length = index_length(self);
832
834
833 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
835 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
834 &start, &stop, &step, &slicelength) < 0)
836 &start, &stop, &step, &slicelength) < 0)
835 return -1;
837 return -1;
836
838
837 if (slicelength <= 0)
839 if (slicelength <= 0)
838 return 0;
840 return 0;
839
841
840 if ((step < 0 && start < stop) || (step > 0 && start > stop))
842 if ((step < 0 && start < stop) || (step > 0 && start > stop))
841 stop = start;
843 stop = start;
842
844
843 if (step < 0) {
845 if (step < 0) {
844 stop = start + 1;
846 stop = start + 1;
845 start = stop + step*(slicelength - 1) - 1;
847 start = stop + step*(slicelength - 1) - 1;
846 step = -step;
848 step = -step;
847 }
849 }
848
850
849 if (step != 1) {
851 if (step != 1) {
850 PyErr_SetString(PyExc_ValueError,
852 PyErr_SetString(PyExc_ValueError,
851 "revlog index delete requires step size of 1");
853 "revlog index delete requires step size of 1");
852 return -1;
854 return -1;
853 }
855 }
854
856
855 if (stop != length - 1) {
857 if (stop != length - 1) {
856 PyErr_SetString(PyExc_IndexError,
858 PyErr_SetString(PyExc_IndexError,
857 "revlog index deletion indices are invalid");
859 "revlog index deletion indices are invalid");
858 return -1;
860 return -1;
859 }
861 }
860
862
861 if (start < self->length - 1) {
863 if (start < self->length - 1) {
862 if (self->nt) {
864 if (self->nt) {
863 Py_ssize_t i;
865 Py_ssize_t i;
864
866
865 for (i = start + 1; i < self->length - 1; i++) {
867 for (i = start + 1; i < self->length - 1; i++) {
866 const char *node = index_node(self, i);
868 const char *node = index_node(self, i);
867
869
868 if (node)
870 if (node)
869 nt_insert(self, node, -1);
871 nt_insert(self, node, -1);
870 }
872 }
871 if (self->added)
873 if (self->added)
872 nt_invalidate_added(self, 0);
874 nt_invalidate_added(self, 0);
873 if (self->ntrev > start)
875 if (self->ntrev > start)
874 self->ntrev = (int)start;
876 self->ntrev = (int)start;
875 }
877 }
876 self->length = start + 1;
878 self->length = start + 1;
877 return 0;
879 return 0;
878 }
880 }
879
881
880 if (self->nt) {
882 if (self->nt) {
881 nt_invalidate_added(self, start - self->length + 1);
883 nt_invalidate_added(self, start - self->length + 1);
882 if (self->ntrev > start)
884 if (self->ntrev > start)
883 self->ntrev = (int)start;
885 self->ntrev = (int)start;
884 }
886 }
885 return self->added
887 return self->added
886 ? PyList_SetSlice(self->added, start - self->length + 1,
888 ? PyList_SetSlice(self->added, start - self->length + 1,
887 PyList_GET_SIZE(self->added), NULL)
889 PyList_GET_SIZE(self->added), NULL)
888 : 0;
890 : 0;
889 }
891 }
890
892
891 /*
893 /*
892 * Supported ops:
894 * Supported ops:
893 *
895 *
894 * slice deletion
896 * slice deletion
895 * string assignment (extend node->rev mapping)
897 * string assignment (extend node->rev mapping)
896 * string deletion (shrink node->rev mapping)
898 * string deletion (shrink node->rev mapping)
897 */
899 */
898 static int index_assign_subscript(indexObject *self, PyObject *item,
900 static int index_assign_subscript(indexObject *self, PyObject *item,
899 PyObject *value)
901 PyObject *value)
900 {
902 {
901 char *node;
903 char *node;
902 Py_ssize_t nodelen;
904 Py_ssize_t nodelen;
903 long rev;
905 long rev;
904
906
905 if (PySlice_Check(item) && value == NULL)
907 if (PySlice_Check(item) && value == NULL)
906 return index_slice_del(self, item);
908 return index_slice_del(self, item);
907
909
908 if (node_check(item, &node, &nodelen) == -1)
910 if (node_check(item, &node, &nodelen) == -1)
909 return -1;
911 return -1;
910
912
911 if (value == NULL)
913 if (value == NULL)
912 return self->nt ? nt_insert(self, node, -1) : 0;
914 return self->nt ? nt_insert(self, node, -1) : 0;
913 rev = PyInt_AsLong(value);
915 rev = PyInt_AsLong(value);
914 if (rev > INT_MAX || rev < 0) {
916 if (rev > INT_MAX || rev < 0) {
915 if (!PyErr_Occurred())
917 if (!PyErr_Occurred())
916 PyErr_SetString(PyExc_ValueError, "rev out of range");
918 PyErr_SetString(PyExc_ValueError, "rev out of range");
917 return -1;
919 return -1;
918 }
920 }
919 return nt_insert(self, node, (int)rev);
921 return nt_insert(self, node, (int)rev);
920 }
922 }
921
923
922 /*
924 /*
923 * Find all RevlogNG entries in an index that has inline data. Update
925 * Find all RevlogNG entries in an index that has inline data. Update
924 * the optional "offsets" table with those entries.
926 * the optional "offsets" table with those entries.
925 */
927 */
926 static long inline_scan(indexObject *self, const char **offsets)
928 static long inline_scan(indexObject *self, const char **offsets)
927 {
929 {
928 const char *data = PyString_AS_STRING(self->data);
930 const char *data = PyString_AS_STRING(self->data);
929 const char *end = data + PyString_GET_SIZE(self->data);
931 const char *end = data + PyString_GET_SIZE(self->data);
930 const long hdrsize = 64;
932 const long hdrsize = 64;
931 long incr = hdrsize;
933 long incr = hdrsize;
932 Py_ssize_t len = 0;
934 Py_ssize_t len = 0;
933
935
934 while (data + hdrsize <= end) {
936 while (data + hdrsize <= end) {
935 uint32_t comp_len;
937 uint32_t comp_len;
936 const char *old_data;
938 const char *old_data;
937 /* 3rd element of header is length of compressed inline data */
939 /* 3rd element of header is length of compressed inline data */
938 comp_len = getbe32(data + 8);
940 comp_len = getbe32(data + 8);
939 incr = hdrsize + comp_len;
941 incr = hdrsize + comp_len;
940 if (incr < hdrsize)
942 if (incr < hdrsize)
941 break;
943 break;
942 if (offsets)
944 if (offsets)
943 offsets[len] = data;
945 offsets[len] = data;
944 len++;
946 len++;
945 old_data = data;
947 old_data = data;
946 data += incr;
948 data += incr;
947 if (data <= old_data)
949 if (data <= old_data)
948 break;
950 break;
949 }
951 }
950
952
951 if (data != end && data + hdrsize != end) {
953 if (data != end && data + hdrsize != end) {
952 if (!PyErr_Occurred())
954 if (!PyErr_Occurred())
953 PyErr_SetString(PyExc_ValueError, "corrupt index file");
955 PyErr_SetString(PyExc_ValueError, "corrupt index file");
954 return -1;
956 return -1;
955 }
957 }
956
958
957 return len;
959 return len;
958 }
960 }
959
961
960 static int index_real_init(indexObject *self, const char *data, int size,
962 static int index_init(indexObject *self, PyObject *args)
961 PyObject *inlined_obj, PyObject *data_obj)
962 {
963 {
964 PyObject *data_obj, *inlined_obj;
965 Py_ssize_t size;
966
967 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
968 return -1;
969 if (!PyString_Check(data_obj)) {
970 PyErr_SetString(PyExc_TypeError, "data is not a string");
971 return -1;
972 }
973 size = PyString_GET_SIZE(data_obj);
974
963 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
975 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
964 self->data = data_obj;
976 self->data = data_obj;
965 self->cache = NULL;
977 self->cache = NULL;
966
978
967 self->added = NULL;
979 self->added = NULL;
968 self->offsets = NULL;
980 self->offsets = NULL;
969 self->nt = NULL;
981 self->nt = NULL;
970 self->ntlength = self->ntcapacity = 0;
982 self->ntlength = self->ntcapacity = 0;
971 self->ntdepth = self->ntsplits = 0;
983 self->ntdepth = self->ntsplits = 0;
972 self->ntlookups = self->ntmisses = 0;
984 self->ntlookups = self->ntmisses = 0;
973 self->ntrev = -1;
985 self->ntrev = -1;
974 Py_INCREF(self->data);
975
986
976 if (self->inlined) {
987 if (self->inlined) {
977 long len = inline_scan(self, NULL);
988 long len = inline_scan(self, NULL);
978 if (len == -1)
989 if (len == -1)
979 goto bail;
990 goto bail;
980 self->raw_length = len;
991 self->raw_length = len;
981 self->length = len + 1;
992 self->length = len + 1;
982 } else {
993 } else {
983 if (size % 64) {
994 if (size % 64) {
984 PyErr_SetString(PyExc_ValueError, "corrupt index file");
995 PyErr_SetString(PyExc_ValueError, "corrupt index file");
985 goto bail;
996 goto bail;
986 }
997 }
987 self->raw_length = size / 64;
998 self->raw_length = size / 64;
988 self->length = self->raw_length + 1;
999 self->length = self->raw_length + 1;
989 }
1000 }
1001 Py_INCREF(self->data);
990
1002
991 return 0;
1003 return 0;
992 bail:
1004 bail:
993 return -1;
1005 return -1;
994 }
1006 }
995
1007
996 static int index_init(indexObject *self, PyObject *args, PyObject *kwds)
997 {
998 const char *data;
999 int size;
1000 PyObject *inlined_obj;
1001
1002 if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj))
1003 return -1;
1004
1005 return index_real_init(self, data, size, inlined_obj,
1006 PyTuple_GET_ITEM(args, 0));
1007 }
1008
1009 static PyObject *index_nodemap(indexObject *self)
1008 static PyObject *index_nodemap(indexObject *self)
1010 {
1009 {
1010 Py_INCREF(self);
1011 return (PyObject *)self;
1011 return (PyObject *)self;
1012 }
1012 }
1013
1013
1014 static void index_dealloc(indexObject *self)
1014 static void index_dealloc(indexObject *self)
1015 {
1015 {
1016 _index_clearcaches(self);
1016 _index_clearcaches(self);
1017 Py_DECREF(self->data);
1017 Py_DECREF(self->data);
1018 Py_XDECREF(self->added);
1018 Py_XDECREF(self->added);
1019 PyObject_Del(self);
1019 PyObject_Del(self);
1020 }
1020 }
1021
1021
1022 static PySequenceMethods index_sequence_methods = {
1022 static PySequenceMethods index_sequence_methods = {
1023 (lenfunc)index_length, /* sq_length */
1023 (lenfunc)index_length, /* sq_length */
1024 0, /* sq_concat */
1024 0, /* sq_concat */
1025 0, /* sq_repeat */
1025 0, /* sq_repeat */
1026 (ssizeargfunc)index_get, /* sq_item */
1026 (ssizeargfunc)index_get, /* sq_item */
1027 0, /* sq_slice */
1027 0, /* sq_slice */
1028 0, /* sq_ass_item */
1028 0, /* sq_ass_item */
1029 0, /* sq_ass_slice */
1029 0, /* sq_ass_slice */
1030 (objobjproc)index_contains, /* sq_contains */
1030 (objobjproc)index_contains, /* sq_contains */
1031 };
1031 };
1032
1032
1033 static PyMappingMethods index_mapping_methods = {
1033 static PyMappingMethods index_mapping_methods = {
1034 (lenfunc)index_length, /* mp_length */
1034 (lenfunc)index_length, /* mp_length */
1035 (binaryfunc)index_getitem, /* mp_subscript */
1035 (binaryfunc)index_getitem, /* mp_subscript */
1036 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1036 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1037 };
1037 };
1038
1038
1039 static PyMethodDef index_methods[] = {
1039 static PyMethodDef index_methods[] = {
1040 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1040 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1041 "clear the index caches"},
1041 "clear the index caches"},
1042 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1042 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1043 "get an index entry"},
1043 "get an index entry"},
1044 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1044 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1045 "insert an index entry"},
1045 "insert an index entry"},
1046 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1046 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1047 "stats for the index"},
1047 "stats for the index"},
1048 {NULL} /* Sentinel */
1048 {NULL} /* Sentinel */
1049 };
1049 };
1050
1050
1051 static PyGetSetDef index_getset[] = {
1051 static PyGetSetDef index_getset[] = {
1052 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1052 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1053 {NULL} /* Sentinel */
1053 {NULL} /* Sentinel */
1054 };
1054 };
1055
1055
1056 static PyTypeObject indexType = {
1056 static PyTypeObject indexType = {
1057 PyObject_HEAD_INIT(NULL)
1057 PyObject_HEAD_INIT(NULL)
1058 0, /* ob_size */
1058 0, /* ob_size */
1059 "parsers.index", /* tp_name */
1059 "parsers.index", /* tp_name */
1060 sizeof(indexObject), /* tp_basicsize */
1060 sizeof(indexObject), /* tp_basicsize */
1061 0, /* tp_itemsize */
1061 0, /* tp_itemsize */
1062 (destructor)index_dealloc, /* tp_dealloc */
1062 (destructor)index_dealloc, /* tp_dealloc */
1063 0, /* tp_print */
1063 0, /* tp_print */
1064 0, /* tp_getattr */
1064 0, /* tp_getattr */
1065 0, /* tp_setattr */
1065 0, /* tp_setattr */
1066 0, /* tp_compare */
1066 0, /* tp_compare */
1067 0, /* tp_repr */
1067 0, /* tp_repr */
1068 0, /* tp_as_number */
1068 0, /* tp_as_number */
1069 &index_sequence_methods, /* tp_as_sequence */
1069 &index_sequence_methods, /* tp_as_sequence */
1070 &index_mapping_methods, /* tp_as_mapping */
1070 &index_mapping_methods, /* tp_as_mapping */
1071 0, /* tp_hash */
1071 0, /* tp_hash */
1072 0, /* tp_call */
1072 0, /* tp_call */
1073 0, /* tp_str */
1073 0, /* tp_str */
1074 0, /* tp_getattro */
1074 0, /* tp_getattro */
1075 0, /* tp_setattro */
1075 0, /* tp_setattro */
1076 0, /* tp_as_buffer */
1076 0, /* tp_as_buffer */
1077 Py_TPFLAGS_DEFAULT, /* tp_flags */
1077 Py_TPFLAGS_DEFAULT, /* tp_flags */
1078 "revlog index", /* tp_doc */
1078 "revlog index", /* tp_doc */
1079 0, /* tp_traverse */
1079 0, /* tp_traverse */
1080 0, /* tp_clear */
1080 0, /* tp_clear */
1081 0, /* tp_richcompare */
1081 0, /* tp_richcompare */
1082 0, /* tp_weaklistoffset */
1082 0, /* tp_weaklistoffset */
1083 0, /* tp_iter */
1083 0, /* tp_iter */
1084 0, /* tp_iternext */
1084 0, /* tp_iternext */
1085 index_methods, /* tp_methods */
1085 index_methods, /* tp_methods */
1086 0, /* tp_members */
1086 0, /* tp_members */
1087 index_getset, /* tp_getset */
1087 index_getset, /* tp_getset */
1088 0, /* tp_base */
1088 0, /* tp_base */
1089 0, /* tp_dict */
1089 0, /* tp_dict */
1090 0, /* tp_descr_get */
1090 0, /* tp_descr_get */
1091 0, /* tp_descr_set */
1091 0, /* tp_descr_set */
1092 0, /* tp_dictoffset */
1092 0, /* tp_dictoffset */
1093 (initproc)index_init, /* tp_init */
1093 (initproc)index_init, /* tp_init */
1094 0, /* tp_alloc */
1094 0, /* tp_alloc */
1095 PyType_GenericNew, /* tp_new */
1095 PyType_GenericNew, /* tp_new */
1096 };
1096 };
1097
1097
1098 /*
1098 /*
1099 * returns a tuple of the form (index, index, cache) with elements as
1099 * returns a tuple of the form (index, index, cache) with elements as
1100 * follows:
1100 * follows:
1101 *
1101 *
1102 * index: an index object that lazily parses RevlogNG records
1102 * index: an index object that lazily parses RevlogNG records
1103 * cache: if data is inlined, a tuple (index_file_content, 0), else None
1103 * cache: if data is inlined, a tuple (index_file_content, 0), else None
1104 *
1104 *
1105 * added complications are for backwards compatibility
1105 * added complications are for backwards compatibility
1106 */
1106 */
1107 static PyObject *parse_index2(PyObject *self, PyObject *args)
1107 static PyObject *parse_index2(PyObject *self, PyObject *args)
1108 {
1108 {
1109 const char *data;
1109 PyObject *tuple = NULL, *cache = NULL;
1110 int size, ret;
1111 PyObject *inlined_obj, *tuple = NULL, *cache = NULL;
1112 indexObject *idx;
1110 indexObject *idx;
1113
1111 int ret;
1114 if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj))
1115 return NULL;
1116
1112
1117 idx = PyObject_New(indexObject, &indexType);
1113 idx = PyObject_New(indexObject, &indexType);
1118
1119 if (idx == NULL)
1114 if (idx == NULL)
1120 goto bail;
1115 goto bail;
1121
1116
1122 ret = index_real_init(idx, data, size, inlined_obj,
1117 ret = index_init(idx, args);
1123 PyTuple_GET_ITEM(args, 0));
1118 if (ret == -1)
1124 if (ret)
1125 goto bail;
1119 goto bail;
1126
1120
1127 if (idx->inlined) {
1121 if (idx->inlined) {
1128 Py_INCREF(idx->data);
1129 cache = Py_BuildValue("iO", 0, idx->data);
1122 cache = Py_BuildValue("iO", 0, idx->data);
1130 if (cache == NULL)
1123 if (cache == NULL)
1131 goto bail;
1124 goto bail;
1132 } else {
1125 } else {
1133 cache = Py_None;
1126 cache = Py_None;
1134 Py_INCREF(cache);
1127 Py_INCREF(cache);
1135 }
1128 }
1136
1129
1137 Py_INCREF(idx);
1138
1139 tuple = Py_BuildValue("NN", idx, cache);
1130 tuple = Py_BuildValue("NN", idx, cache);
1140 if (!tuple)
1131 if (!tuple)
1141 goto bail;
1132 goto bail;
1142 return tuple;
1133 return tuple;
1143
1134
1144 bail:
1135 bail:
1145 Py_XDECREF(idx);
1136 Py_XDECREF(idx);
1146 Py_XDECREF(cache);
1137 Py_XDECREF(cache);
1147 Py_XDECREF(tuple);
1138 Py_XDECREF(tuple);
1148 return NULL;
1139 return NULL;
1149 }
1140 }
1150
1141
1151 static char parsers_doc[] = "Efficient content parsing.";
1142 static char parsers_doc[] = "Efficient content parsing.";
1152
1143
1153 static PyMethodDef methods[] = {
1144 static PyMethodDef methods[] = {
1154 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
1145 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
1155 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1146 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1156 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
1147 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
1157 {NULL, NULL}
1148 {NULL, NULL}
1158 };
1149 };
1159
1150
1160 static void module_init(PyObject *mod)
1151 static void module_init(PyObject *mod)
1161 {
1152 {
1162 if (PyType_Ready(&indexType) < 0)
1153 if (PyType_Ready(&indexType) < 0)
1163 return;
1154 return;
1164 Py_INCREF(&indexType);
1155 Py_INCREF(&indexType);
1165
1156
1166 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
1157 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
1167
1158
1168 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
1159 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
1169 -1, -1, -1, -1, nullid, 20);
1160 -1, -1, -1, -1, nullid, 20);
1170 if (nullentry)
1161 if (nullentry)
1171 PyObject_GC_UnTrack(nullentry);
1162 PyObject_GC_UnTrack(nullentry);
1172 }
1163 }
1173
1164
1174 #ifdef IS_PY3K
1165 #ifdef IS_PY3K
1175 static struct PyModuleDef parsers_module = {
1166 static struct PyModuleDef parsers_module = {
1176 PyModuleDef_HEAD_INIT,
1167 PyModuleDef_HEAD_INIT,
1177 "parsers",
1168 "parsers",
1178 parsers_doc,
1169 parsers_doc,
1179 -1,
1170 -1,
1180 methods
1171 methods
1181 };
1172 };
1182
1173
1183 PyMODINIT_FUNC PyInit_parsers(void)
1174 PyMODINIT_FUNC PyInit_parsers(void)
1184 {
1175 {
1185 PyObject *mod = PyModule_Create(&parsers_module);
1176 PyObject *mod = PyModule_Create(&parsers_module);
1186 module_init(mod);
1177 module_init(mod);
1187 return mod;
1178 return mod;
1188 }
1179 }
1189 #else
1180 #else
1190 PyMODINIT_FUNC initparsers(void)
1181 PyMODINIT_FUNC initparsers(void)
1191 {
1182 {
1192 PyObject *mod = Py_InitModule3("parsers", methods, parsers_doc);
1183 PyObject *mod = Py_InitModule3("parsers", methods, parsers_doc);
1193 module_init(mod);
1184 module_init(mod);
1194 }
1185 }
1195 #endif
1186 #endif
@@ -1,373 +1,378 b''
1 $ hg init
1 $ hg init
2
2
3 no bookmarks
3 no bookmarks
4
4
5 $ hg bookmarks
5 $ hg bookmarks
6 no bookmarks set
6 no bookmarks set
7
7
8 bookmark rev -1
8 bookmark rev -1
9
9
10 $ hg bookmark X
10 $ hg bookmark X
11
11
12 list bookmarks
12 list bookmarks
13
13
14 $ hg bookmarks
14 $ hg bookmarks
15 * X -1:000000000000
15 * X -1:000000000000
16
16
17 list bookmarks with color
17 list bookmarks with color
18
18
19 $ hg --config extensions.color= --config color.mode=ansi \
19 $ hg --config extensions.color= --config color.mode=ansi \
20 > bookmarks --color=always
20 > bookmarks --color=always
21 \x1b[0;32m * X -1:000000000000\x1b[0m (esc)
21 \x1b[0;32m * X -1:000000000000\x1b[0m (esc)
22
22
23 $ echo a > a
23 $ echo a > a
24 $ hg add a
24 $ hg add a
25 $ hg commit -m 0
25 $ hg commit -m 0
26
26
27 bookmark X moved to rev 0
27 bookmark X moved to rev 0
28
28
29 $ hg bookmarks
29 $ hg bookmarks
30 * X 0:f7b1eb17ad24
30 * X 0:f7b1eb17ad24
31
31
32 look up bookmark
32 look up bookmark
33
33
34 $ hg log -r X
34 $ hg log -r X
35 changeset: 0:f7b1eb17ad24
35 changeset: 0:f7b1eb17ad24
36 bookmark: X
36 bookmark: X
37 tag: tip
37 tag: tip
38 user: test
38 user: test
39 date: Thu Jan 01 00:00:00 1970 +0000
39 date: Thu Jan 01 00:00:00 1970 +0000
40 summary: 0
40 summary: 0
41
41
42
42
43 second bookmark for rev 0
43 second bookmark for rev 0
44
44
45 $ hg bookmark X2
45 $ hg bookmark X2
46
46
47 bookmark rev -1 again
47 bookmark rev -1 again
48
48
49 $ hg bookmark -r null Y
49 $ hg bookmark -r null Y
50
50
51 list bookmarks
51 list bookmarks
52
52
53 $ hg bookmarks
53 $ hg bookmarks
54 X 0:f7b1eb17ad24
54 X 0:f7b1eb17ad24
55 * X2 0:f7b1eb17ad24
55 * X2 0:f7b1eb17ad24
56 Y -1:000000000000
56 Y -1:000000000000
57
57
58 $ echo b > b
58 $ echo b > b
59 $ hg add b
59 $ hg add b
60 $ hg commit -m 1
60 $ hg commit -m 1
61
61
62 bookmarks revset
62 bookmarks revset
63
63
64 $ hg log -r 'bookmark()'
64 $ hg log -r 'bookmark()'
65 changeset: 0:f7b1eb17ad24
65 changeset: 0:f7b1eb17ad24
66 bookmark: X
66 bookmark: X
67 user: test
67 user: test
68 date: Thu Jan 01 00:00:00 1970 +0000
68 date: Thu Jan 01 00:00:00 1970 +0000
69 summary: 0
69 summary: 0
70
70
71 changeset: 1:925d80f479bb
71 changeset: 1:925d80f479bb
72 bookmark: X2
72 bookmark: X2
73 tag: tip
73 tag: tip
74 user: test
74 user: test
75 date: Thu Jan 01 00:00:00 1970 +0000
75 date: Thu Jan 01 00:00:00 1970 +0000
76 summary: 1
76 summary: 1
77
77
78 $ hg log -r 'bookmark(Y)'
78 $ hg log -r 'bookmark(Y)'
79 $ hg log -r 'bookmark(X2)'
79 $ hg log -r 'bookmark(X2)'
80 changeset: 1:925d80f479bb
80 changeset: 1:925d80f479bb
81 bookmark: X2
81 bookmark: X2
82 tag: tip
82 tag: tip
83 user: test
83 user: test
84 date: Thu Jan 01 00:00:00 1970 +0000
84 date: Thu Jan 01 00:00:00 1970 +0000
85 summary: 1
85 summary: 1
86
86
87 $ hg log -r 'bookmark(unknown)'
87 $ hg log -r 'bookmark(unknown)'
88 abort: bookmark 'unknown' does not exist
88 abort: bookmark 'unknown' does not exist
89 [255]
89 [255]
90
90
91 $ hg help revsets | grep 'bookmark('
91 $ hg help revsets | grep 'bookmark('
92 "bookmark([name])"
92 "bookmark([name])"
93
93
94 bookmarks X and X2 moved to rev 1, Y at rev -1
94 bookmarks X and X2 moved to rev 1, Y at rev -1
95
95
96 $ hg bookmarks
96 $ hg bookmarks
97 X 0:f7b1eb17ad24
97 X 0:f7b1eb17ad24
98 * X2 1:925d80f479bb
98 * X2 1:925d80f479bb
99 Y -1:000000000000
99 Y -1:000000000000
100
100
101 bookmark rev 0 again
101 bookmark rev 0 again
102
102
103 $ hg bookmark -r 0 Z
103 $ hg bookmark -r 0 Z
104
104
105 $ hg update X
105 $ hg update X
106 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
106 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
107 $ echo c > c
107 $ echo c > c
108 $ hg add c
108 $ hg add c
109 $ hg commit -m 2
109 $ hg commit -m 2
110 created new head
110 created new head
111
111
112 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
112 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
113
113
114 $ hg bookmarks
114 $ hg bookmarks
115 * X 2:db815d6d32e6
115 * X 2:db815d6d32e6
116 X2 1:925d80f479bb
116 X2 1:925d80f479bb
117 Y -1:000000000000
117 Y -1:000000000000
118 Z 0:f7b1eb17ad24
118 Z 0:f7b1eb17ad24
119
119
120 rename nonexistent bookmark
120 rename nonexistent bookmark
121
121
122 $ hg bookmark -m A B
122 $ hg bookmark -m A B
123 abort: bookmark 'A' does not exist
123 abort: bookmark 'A' does not exist
124 [255]
124 [255]
125
125
126 rename to existent bookmark
126 rename to existent bookmark
127
127
128 $ hg bookmark -m X Y
128 $ hg bookmark -m X Y
129 abort: bookmark 'Y' already exists (use -f to force)
129 abort: bookmark 'Y' already exists (use -f to force)
130 [255]
130 [255]
131
131
132 force rename to existent bookmark
132 force rename to existent bookmark
133
133
134 $ hg bookmark -f -m X Y
134 $ hg bookmark -f -m X Y
135
135
136 list bookmarks
136 list bookmarks
137
137
138 $ hg bookmark
138 $ hg bookmark
139 X2 1:925d80f479bb
139 X2 1:925d80f479bb
140 * Y 2:db815d6d32e6
140 * Y 2:db815d6d32e6
141 Z 0:f7b1eb17ad24
141 Z 0:f7b1eb17ad24
142
142
143 rename without new name
143 rename without new name
144
144
145 $ hg bookmark -m Y
145 $ hg bookmark -m Y
146 abort: new bookmark name required
146 abort: new bookmark name required
147 [255]
147 [255]
148
148
149 delete without name
149 delete without name
150
150
151 $ hg bookmark -d
151 $ hg bookmark -d
152 abort: bookmark name required
152 abort: bookmark name required
153 [255]
153 [255]
154
154
155 delete nonexistent bookmark
155 delete nonexistent bookmark
156
156
157 $ hg bookmark -d A
157 $ hg bookmark -d A
158 abort: bookmark 'A' does not exist
158 abort: bookmark 'A' does not exist
159 [255]
159 [255]
160
160
161 bookmark name with spaces should be stripped
161 bookmark name with spaces should be stripped
162
162
163 $ hg bookmark ' x y '
163 $ hg bookmark ' x y '
164
164
165 list bookmarks
165 list bookmarks
166
166
167 $ hg bookmarks
167 $ hg bookmarks
168 X2 1:925d80f479bb
168 X2 1:925d80f479bb
169 Y 2:db815d6d32e6
169 Y 2:db815d6d32e6
170 Z 0:f7b1eb17ad24
170 Z 0:f7b1eb17ad24
171 * x y 2:db815d6d32e6
171 * x y 2:db815d6d32e6
172
172
173 look up stripped bookmark name
173 look up stripped bookmark name
174
174
175 $ hg log -r '"x y"'
175 $ hg log -r '"x y"'
176 changeset: 2:db815d6d32e6
176 changeset: 2:db815d6d32e6
177 bookmark: Y
177 bookmark: Y
178 bookmark: x y
178 bookmark: x y
179 tag: tip
179 tag: tip
180 parent: 0:f7b1eb17ad24
180 parent: 0:f7b1eb17ad24
181 user: test
181 user: test
182 date: Thu Jan 01 00:00:00 1970 +0000
182 date: Thu Jan 01 00:00:00 1970 +0000
183 summary: 2
183 summary: 2
184
184
185
185
186 reject bookmark name with newline
186 reject bookmark name with newline
187
187
188 $ hg bookmark '
188 $ hg bookmark '
189 > '
189 > '
190 abort: bookmark name cannot contain newlines
190 abort: bookmark name cannot contain newlines
191 [255]
191 [255]
192
192
193 bookmark with existing name
193 bookmark with existing name
194
194
195 $ hg bookmark Z
195 $ hg bookmark Z
196 abort: bookmark 'Z' already exists (use -f to force)
196 abort: bookmark 'Z' already exists (use -f to force)
197 [255]
197 [255]
198
198
199 force bookmark with existing name
199 force bookmark with existing name
200
200
201 $ hg bookmark -f Z
201 $ hg bookmark -f Z
202
202
203 list bookmarks
203 list bookmarks
204
204
205 $ hg bookmark
205 $ hg bookmark
206 X2 1:925d80f479bb
206 X2 1:925d80f479bb
207 Y 2:db815d6d32e6
207 Y 2:db815d6d32e6
208 * Z 2:db815d6d32e6
208 * Z 2:db815d6d32e6
209 x y 2:db815d6d32e6
209 x y 2:db815d6d32e6
210
210
211 revision but no bookmark name
211 revision but no bookmark name
212
212
213 $ hg bookmark -r .
213 $ hg bookmark -r .
214 abort: bookmark name required
214 abort: bookmark name required
215 [255]
215 [255]
216
216
217 bookmark name with whitespace only
217 bookmark name with whitespace only
218
218
219 $ hg bookmark ' '
219 $ hg bookmark ' '
220 abort: bookmark names cannot consist entirely of whitespace
220 abort: bookmark names cannot consist entirely of whitespace
221 [255]
221 [255]
222
222
223 invalid bookmark
223 invalid bookmark
224
224
225 $ hg bookmark 'foo:bar'
225 $ hg bookmark 'foo:bar'
226 abort: bookmark 'foo:bar' contains illegal character
226 abort: bookmark 'foo:bar' contains illegal character
227 [255]
227 [255]
228
228
229 the bookmark extension should be ignored now that it is part of core
229 the bookmark extension should be ignored now that it is part of core
230
230
231 $ echo "[extensions]" >> $HGRCPATH
231 $ echo "[extensions]" >> $HGRCPATH
232 $ echo "bookmarks=" >> $HGRCPATH
232 $ echo "bookmarks=" >> $HGRCPATH
233 $ hg bookmarks
233 $ hg bookmarks
234 X2 1:925d80f479bb
234 X2 1:925d80f479bb
235 Y 2:db815d6d32e6
235 Y 2:db815d6d32e6
236 * Z 2:db815d6d32e6
236 * Z 2:db815d6d32e6
237 x y 2:db815d6d32e6
237 x y 2:db815d6d32e6
238
238
239 test summary
239 test summary
240
240
241 $ hg summary
241 $ hg summary
242 parent: 2:db815d6d32e6 tip
242 parent: 2:db815d6d32e6 tip
243 2
243 2
244 branch: default
244 branch: default
245 bookmarks: *Z Y x y
245 bookmarks: *Z Y x y
246 commit: (clean)
246 commit: (clean)
247 update: 1 new changesets, 2 branch heads (merge)
247 update: 1 new changesets, 2 branch heads (merge)
248
248
249 test id
249 test id
250
250
251 $ hg id
251 $ hg id
252 db815d6d32e6 tip Y/Z/x y
252 db815d6d32e6 tip Y/Z/x y
253
253
254 test rollback
254 test rollback
255
255
256 $ echo foo > f1
256 $ echo foo > f1
257 $ hg ci -Amr
257 $ hg ci -Amr
258 adding f1
258 adding f1
259 $ hg bookmark -f Y -r 1
259 $ hg bookmark -f Y -r 1
260 $ hg bookmark -f Z -r 1
260 $ hg bookmark -f Z -r 1
261 $ hg rollback
261 $ hg rollback
262 repository tip rolled back to revision 2 (undo commit)
262 repository tip rolled back to revision 2 (undo commit)
263 working directory now based on revision 2
263 working directory now based on revision 2
264 $ hg bookmarks
264 $ hg bookmarks
265 X2 1:925d80f479bb
265 X2 1:925d80f479bb
266 Y 2:db815d6d32e6
266 Y 2:db815d6d32e6
267 * Z 2:db815d6d32e6
267 * Z 2:db815d6d32e6
268 x y 2:db815d6d32e6
268 x y 2:db815d6d32e6
269
269
270 test clone
270 test clone
271
271
272 $ hg bookmark -r 2 -i @
272 $ hg bookmark -r 2 -i @
273 $ hg bookmark -r 2 -i a@
273 $ hg bookmark -r 2 -i a@
274 $ hg bookmarks
274 $ hg bookmarks
275 @ 2:db815d6d32e6
275 @ 2:db815d6d32e6
276 X2 1:925d80f479bb
276 X2 1:925d80f479bb
277 Y 2:db815d6d32e6
277 Y 2:db815d6d32e6
278 * Z 2:db815d6d32e6
278 * Z 2:db815d6d32e6
279 a@ 2:db815d6d32e6
279 a@ 2:db815d6d32e6
280 x y 2:db815d6d32e6
280 x y 2:db815d6d32e6
281 $ hg clone . cloned-bookmarks
281 $ hg clone . cloned-bookmarks
282 updating to branch default
282 updating to branch default
283 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
283 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
284 $ hg -R cloned-bookmarks bookmarks
284 $ hg -R cloned-bookmarks bookmarks
285 @ 2:db815d6d32e6
285 @ 2:db815d6d32e6
286 X2 1:925d80f479bb
286 X2 1:925d80f479bb
287 Y 2:db815d6d32e6
287 Y 2:db815d6d32e6
288 Z 2:db815d6d32e6
288 Z 2:db815d6d32e6
289 a@ 2:db815d6d32e6
289 a@ 2:db815d6d32e6
290 x y 2:db815d6d32e6
290 x y 2:db815d6d32e6
291
291
292 test clone with pull protocol
292 test clone with pull protocol
293
293
294 $ hg clone --pull . cloned-bookmarks-pull
294 $ hg clone --pull . cloned-bookmarks-pull
295 requesting all changes
295 requesting all changes
296 adding changesets
296 adding changesets
297 adding manifests
297 adding manifests
298 adding file changes
298 adding file changes
299 added 3 changesets with 3 changes to 3 files (+1 heads)
299 added 3 changesets with 3 changes to 3 files (+1 heads)
300 updating to branch default
300 updating to branch default
301 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
301 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
302 $ hg -R cloned-bookmarks-pull bookmarks
302 $ hg -R cloned-bookmarks-pull bookmarks
303 @ 2:db815d6d32e6
303 @ 2:db815d6d32e6
304 X2 1:925d80f479bb
304 X2 1:925d80f479bb
305 Y 2:db815d6d32e6
305 Y 2:db815d6d32e6
306 Z 2:db815d6d32e6
306 Z 2:db815d6d32e6
307 a@ 2:db815d6d32e6
307 a@ 2:db815d6d32e6
308 x y 2:db815d6d32e6
308 x y 2:db815d6d32e6
309
309
310 $ hg bookmark -d @
310 $ hg bookmark -d @
311 $ hg bookmark -d a@
311 $ hg bookmark -d a@
312
312
313 test clone with a specific revision
313 test clone with a specific revision
314
314
315 $ hg clone -r 925d80 . cloned-bookmarks-rev
315 $ hg clone -r 925d80 . cloned-bookmarks-rev
316 adding changesets
316 adding changesets
317 adding manifests
317 adding manifests
318 adding file changes
318 adding file changes
319 added 2 changesets with 2 changes to 2 files
319 added 2 changesets with 2 changes to 2 files
320 updating to branch default
320 updating to branch default
321 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
321 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
322 $ hg -R cloned-bookmarks-rev bookmarks
322 $ hg -R cloned-bookmarks-rev bookmarks
323 X2 1:925d80f479bb
323 X2 1:925d80f479bb
324
324
325 create bundle with two heads
325 create bundle with two heads
326
326
327 $ hg clone . tobundle
327 $ hg clone . tobundle
328 updating to branch default
328 updating to branch default
329 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 $ echo x > tobundle/x
330 $ echo x > tobundle/x
331 $ hg -R tobundle add tobundle/x
331 $ hg -R tobundle add tobundle/x
332 $ hg -R tobundle commit -m'x'
332 $ hg -R tobundle commit -m'x'
333 $ hg -R tobundle update -r -2
333 $ hg -R tobundle update -r -2
334 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
334 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
335 $ echo y > tobundle/y
335 $ echo y > tobundle/y
336 $ hg -R tobundle branch test
336 $ hg -R tobundle branch test
337 marked working directory as branch test
337 marked working directory as branch test
338 (branches are permanent and global, did you want a bookmark?)
338 (branches are permanent and global, did you want a bookmark?)
339 $ hg -R tobundle add tobundle/y
339 $ hg -R tobundle add tobundle/y
340 $ hg -R tobundle commit -m'y'
340 $ hg -R tobundle commit -m'y'
341 $ hg -R tobundle bundle tobundle.hg
341 $ hg -R tobundle bundle tobundle.hg
342 searching for changes
342 searching for changes
343 2 changesets found
343 2 changesets found
344 $ hg unbundle tobundle.hg
344 $ hg unbundle tobundle.hg
345 adding changesets
345 adding changesets
346 adding manifests
346 adding manifests
347 adding file changes
347 adding file changes
348 added 2 changesets with 2 changes to 2 files (+1 heads)
348 added 2 changesets with 2 changes to 2 files (+1 heads)
349 (run 'hg heads' to see heads, 'hg merge' to merge)
349 (run 'hg heads' to see heads, 'hg merge' to merge)
350 $ hg update
350 $ hg update
351 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
351 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
352 $ hg bookmarks
352 $ hg bookmarks
353 X2 1:925d80f479bb
353 X2 1:925d80f479bb
354 Y 2:db815d6d32e6
354 Y 2:db815d6d32e6
355 * Z 3:125c9a1d6df6
355 * Z 3:125c9a1d6df6
356 x y 2:db815d6d32e6
356 x y 2:db815d6d32e6
357
357
358 test wrongly formated bookmark
358 test wrongly formated bookmark
359
359
360 $ echo '' >> .hg/bookmarks
360 $ echo '' >> .hg/bookmarks
361 $ hg bookmarks
361 $ hg bookmarks
362 X2 1:925d80f479bb
362 X2 1:925d80f479bb
363 Y 2:db815d6d32e6
363 Y 2:db815d6d32e6
364 * Z 3:125c9a1d6df6
364 * Z 3:125c9a1d6df6
365 x y 2:db815d6d32e6
365 x y 2:db815d6d32e6
366 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
366 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
367 $ hg bookmarks
367 $ hg bookmarks
368 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
368 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
369 X2 1:925d80f479bb
369 X2 1:925d80f479bb
370 Y 2:db815d6d32e6
370 Y 2:db815d6d32e6
371 * Z 3:125c9a1d6df6
371 * Z 3:125c9a1d6df6
372 x y 2:db815d6d32e6
372 x y 2:db815d6d32e6
373
373
374 test missing revisions
375
376 $ echo "925d80f479bc z" > .hg/bookmarks
377 $ hg book
378 no bookmarks set
General Comments 0
You need to be logged in to leave comments. Login now