##// END OF EJS Templates
branching: merge stable into default
Raphaël Gomès -
r51356:f57f5ab0 merge default
parent child Browse files
Show More

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

1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,245 +1,246 b''
1 1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
2 2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
3 3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
4 4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
5 5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
6 6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
7 7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
8 8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
9 9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
10 10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
11 11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
12 12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
13 13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
14 14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
15 15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
16 16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
17 17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
18 18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
19 19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
20 20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
21 21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
22 22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
23 23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
24 24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
25 25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
26 26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
27 27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
28 28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
29 29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
30 30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
31 31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
32 32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
33 33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
34 34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
35 35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
36 36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
37 37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
38 38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
39 39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
40 40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
41 41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
42 42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
43 43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
44 44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
45 45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
46 46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
47 47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
48 48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
49 49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
50 50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
51 51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
52 52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
53 53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
54 54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
55 55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
56 56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
57 57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
58 58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
59 59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
60 60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
61 61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
62 62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
63 63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
64 64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
65 65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
66 66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
67 67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
68 68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
69 69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
70 70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
71 71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
72 72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
73 73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
74 74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
75 75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
76 76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
77 77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
78 78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
79 79 335a558f81dc73afeab4d7be63617392b130117f 0 iQIVAwUAUiZrIyBXgaxoKi1yAQK2iw//cquNqqSkc8Re5/TZT9I6NH+lh6DbOKjJP0Xl1Wqq0K+KSIUgZG4G32ovaEb2l5X0uY+3unRPiZ0ebl0YSw4Fb2ZiPIADXLBTOYRrY2Wwd3tpJeGI6wEgZt3SfcITV/g7NJrCjT3FlYoSOIayrExM80InSdcEM0Q3Rx6HKzY2acyxzgZeAtAW5ohFvHilSvY6p5Gcm4+QptMxvw45GPdreUmjeXZxNXNXZ8P+MjMz/QJbai/N7PjmK8lqnhkBsT48Ng/KhhmOkGntNJ2/ImBWLFGcWngSvJ7sfWwnyhndvGhe0Hq1NcCf7I8TjNDxU5TR+m+uW7xjXdLoDbUjBdX4sKXnh8ZjbYiODKBOrrDq25cf8nA/tnpKyE/qsVy60kOk6loY4XKiYmn1V49Ta0emmDx0hqo3HgxHHsHX0NDnGdWGol7cPRET0RzVobKq1A0jnrhPooWidvLh9bPzLonrWDo+ib+DuySoRkuYUK4pgZJ2mbg6daFOBEZygkSyRB8bo1UQUP7EgQDrWe4khb/5GHEfDkrQz3qu/sXvc0Ir1mOUWBFPHC2DjjCn/oMJuUkG1SwM8l2Bfv7h67ssES6YQ2+RjOix4yid7EXS/Ogl45PzCIPSI5+BbNs10JhE0w5uErBHlF53EDTe/TSLc+GU6DB6PP6dH912Njdr3jpNSUQ=
80 80 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
@@ -1,261 +1,262 b''
1 1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
2 2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
3 3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
4 4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
5 5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
6 6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
7 7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
8 8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
9 9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
10 10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
11 11 3a56574f329a368d645853e0f9e09472aee62349 0.8
12 12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
13 13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
14 14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
15 15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
16 16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
17 17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
18 18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
19 19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
20 20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
21 21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
22 22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
23 23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
24 24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
25 25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
26 26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
27 27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
28 28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
29 29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
30 30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
31 31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
32 32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
33 33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
34 34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
35 35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
36 36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
37 37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
38 38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
39 39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
40 40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
41 41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
42 42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
43 43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
44 44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
45 45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
46 46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
47 47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
48 48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
49 49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
50 50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
51 51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
52 52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
53 53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
54 54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
55 55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
56 56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
57 57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
58 58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
59 59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
60 60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
61 61 6344043924497cd06d781d9014c66802285072e4 2.0.2
62 62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
63 63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
64 64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
65 65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
66 66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
67 67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
68 68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
69 69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
70 70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
71 71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
72 72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
73 73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
74 74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
75 75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
76 76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
77 77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
78 78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
79 79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
80 80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
81 81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
82 82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
83 83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
84 84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
85 85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
86 86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
87 87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
88 88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
89 89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
90 90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
91 91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
92 92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
93 93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
94 94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
95 95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
96 96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
97 97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
98 98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
99 99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
100 100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
101 101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
102 102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
103 103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
104 104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
105 105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
106 106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
107 107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
108 108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
109 109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
110 110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
111 111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
112 112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
113 113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
114 114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
115 115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
116 116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
117 117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
118 118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
119 119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
120 120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
121 121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
122 122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
123 123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
124 124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
125 125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
126 126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
127 127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
128 128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
129 129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
130 130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
131 131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
132 132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
133 133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
134 134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
135 135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
136 136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
137 137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
138 138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
139 139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
140 140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
141 141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
142 142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
143 143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
144 144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
145 145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
146 146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
147 147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
148 148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
149 149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
150 150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
151 151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
152 152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
153 153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
154 154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
155 155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
156 156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
157 157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
158 158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
159 159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
160 160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
161 161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
162 162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
163 163 5544af8622863796a0027566f6b646e10d522c4c 4.3
164 164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
165 165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
166 166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
167 167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
168 168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
169 169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
170 170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
171 171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
172 172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
173 173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
174 174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
175 175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
176 176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
177 177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
178 178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
179 179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
180 180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
181 181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
182 182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
183 183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
184 184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
185 185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
186 186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
187 187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
188 188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
189 189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
190 190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
191 191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
192 192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
193 193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
194 194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
195 195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
196 196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
197 197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
198 198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
199 199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
200 200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
201 201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
202 202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
203 203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
204 204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
205 205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
206 206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
207 207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
208 208 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1
209 209 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2
210 210 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0
211 211 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4
212 212 065704cbdbdbb05dcd6bb814eb9bbdd982211b28 5.4.1
213 213 0ea9c86fac8974cd74dc12ea681c8986eb6da6c4 5.4.2
214 214 28163c5de797e5416f9b588940f4608269b4d50a 5.5rc0
215 215 7fc3c5fbc65f6fe85d70ea63923b8767dda4f2e0 5.5
216 216 f62bb5d07848ca598aa860a517394130b61bf2ee 5.5.1
217 217 07731064ac41dacdf0ec869ebd05c2e848c14fbf 5.5.2
218 218 0e06a7ab9e0d5c65af4e511aee1e0342998799df 5.6rc0
219 219 18c17d63fdabd009e70bf994e5efb7db422f4f7f 5.6
220 220 1d5189a57405ceca5aa244052c9f948977f4699b 5.6.1
221 221 9da65e3cf3706ff41e08b311381c588440c27baf 5.7rc0
222 222 0e2e7300f4302b02412b0b734717697049494c4c 5.7
223 223 d5d9177c0045d206db575bae6daa98e2cb2fe5bc 5.7.1
224 224 f67b8946bb1b6cfa8328dbf8d6a9128b69ccdcb4 5.8rc0
225 225 8d2b62d716b095507effaa8d56f87cd27ba659ab 5.8rc1
226 226 067f2c53fb24506c9e9fb4639871b13b19a85f8a 5.8
227 227 411dc27fd9fd076d6a031a08fcaace659afe2fe3 5.8.1
228 228 d7515d29761d5ada7d9c765f517db67db75dea9a 5.9rc0
229 229 2813d406b03607cdb8c06cb04c44efcc9a79d9a2 5.9rc1
230 230 53221078e0de65d1a821ce5311dec45a7a978301 5.9
231 231 86a60679cf619e14cee9442f865fcf31b142cb9f 5.9.1
232 232 750920b18aaaddd654756be40dec59d90f2643be 5.9.2
233 233 6ee0244fc1cf889ae543d2ce0ec45201ae0be6e1 5.9.3
234 234 a44bb185f6bdbecc754996d8386722e2f0123b0a 6.0rc0
235 235 5d08b289e2e526259d7d5ea32b70fe76d5b327d7 6.0
236 236 799fdf4cca80cb9ae40537a90995e6bd163ebc0b 6.0.1
237 237 75676122c2bf7594ac732b7388db4c74c648b365 6.0.2
238 238 dcec16e799ddb6d33fcd11b04af530250a417a58 6.0.3
239 239 c00d3ce4e94bb0ee8d809e25e1dcb2a5fab84e2c 6.1rc0
240 240 d4486810a1795fba9521449b8885ced034f3a6dd 6.1
241 241 5bd6bcd31dd1ebb63b8914b00064f96297267af7 6.1.1
242 242 0ddd5e1f5f67438af85d12e4ce6c39021dde9916 6.1.2
243 243 6b10151b962108f65bfa12b3918b1021ca334f73 6.1.3
244 244 0cc5f74ff7f0f4ac2427096bddbe102dbc2453ae 6.1.4
245 245 288de6f5d724bba7bf1669e2838f196962bb7528 6.2rc0
246 246 094a5fa3cf52f936e0de3f1e507c818bee5ece6b 6.2
247 247 f69bffd00abe3a1b94d1032eb2c92e611d16a192 6.2.1
248 248 b5c8524827d20fe2e0ca8fb1234a0fe35a1a36c7 6.2.2
249 249 dbdee8ac3e3fcdda1fa55b90c0a235125b7f8e6f 6.2.3
250 250 a3356ab610fc50000cf0ba55c424a4d96da11db7 6.3rc0
251 251 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
252 252 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3
253 253 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
254 254 0000000000000000000000000000000000000000 6.3.0
255 255 c890d8b8bc59b18e5febf60caada629df5356ee2 6.3.1
256 256 59466b13a3ae0e29a5d4f485393e516cfbb057d0 6.3.2
257 257 8830004967ad865ead89c28a410405a6e71e0796 6.3.3
258 258 05de4896508e8ec387b33eb30d8aab78d1c8e9e4 6.4rc0
259 259 f14864fffdcab725d9eac6d4f4c07be05a35f59a 6.4
260 260 83ea6ce48b4fd09fb79c4e34cc5750c805699a53 6.4.1
261 261 f952be90b0514a576dcc8bbe758ce3847faba9bb 6.4.2
262 fc445f8abcf90b33db7c463816a1b3560681767f 6.4.3
@@ -1,559 +1,560 b''
1 1 /*
2 2 * A fast client for Mercurial command server
3 3 *
4 4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 5 *
6 6 * This software may be used and distributed according to the terms of the
7 7 * GNU General Public License version 2 or any later version.
8 8 */
9 9
10 10 #include <assert.h>
11 11 #include <dirent.h>
12 12 #include <errno.h>
13 13 #include <fcntl.h>
14 14 #include <signal.h>
15 15 #include <stdio.h>
16 16 #include <stdlib.h>
17 17 #include <string.h>
18 18 #include <sys/file.h>
19 19 #include <sys/stat.h>
20 20 #include <sys/types.h>
21 21 #include <sys/un.h>
22 22 #include <sys/wait.h>
23 23 #include <time.h>
24 24 #include <unistd.h>
25 25
26 26 #include "hgclient.h"
27 27 #include "procutil.h"
28 28 #include "util.h"
29 29
30 30 #ifndef PATH_MAX
31 31 #define PATH_MAX 4096
32 32 #endif
33 33
34 extern char **environ;
35
34 36 struct cmdserveropts {
35 37 char sockname[PATH_MAX];
36 38 char initsockname[PATH_MAX];
37 39 char redirectsockname[PATH_MAX];
38 40 size_t argsize;
39 41 const char **args;
40 42 };
41 43
42 44 static void initcmdserveropts(struct cmdserveropts *opts)
43 45 {
44 46 memset(opts, 0, sizeof(struct cmdserveropts));
45 47 }
46 48
47 49 static void freecmdserveropts(struct cmdserveropts *opts)
48 50 {
49 51 free(opts->args);
50 52 opts->args = NULL;
51 53 opts->argsize = 0;
52 54 }
53 55
54 56 /*
55 57 * Test if an argument is a sensitive flag that should be passed to the server.
56 58 * Return 0 if not, otherwise the number of arguments starting from the current
57 59 * one that should be passed to the server.
58 60 */
59 61 static size_t testsensitiveflag(const char *arg)
60 62 {
61 63 static const struct {
62 64 const char *name;
63 65 size_t narg;
64 66 } flags[] = {
65 67 {"--config", 1}, {"--cwd", 1}, {"--repo", 1},
66 68 {"--repository", 1}, {"--traceback", 0}, {"-R", 1},
67 69 };
68 70 size_t i;
69 71 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) {
70 72 size_t len = strlen(flags[i].name);
71 73 size_t narg = flags[i].narg;
72 74 if (memcmp(arg, flags[i].name, len) == 0) {
73 75 if (arg[len] == '\0') {
74 76 /* --flag (value) */
75 77 return narg + 1;
76 78 } else if (arg[len] == '=' && narg > 0) {
77 79 /* --flag=value */
78 80 return 1;
79 81 } else if (flags[i].name[1] != '-') {
80 82 /* short flag */
81 83 return 1;
82 84 }
83 85 }
84 86 }
85 87 return 0;
86 88 }
87 89
88 90 /*
89 91 * Parse argv[] and put sensitive flags to opts->args
90 92 */
91 93 static void setcmdserverargs(struct cmdserveropts *opts, int argc,
92 94 const char *argv[])
93 95 {
94 96 size_t i, step;
95 97 opts->argsize = 0;
96 98 for (i = 0, step = 1; i < (size_t)argc; i += step, step = 1) {
97 99 if (!argv[i])
98 100 continue; /* pass clang-analyse */
99 101 if (strcmp(argv[i], "--") == 0)
100 102 break;
101 103 size_t n = testsensitiveflag(argv[i]);
102 104 if (n == 0 || i + n > (size_t)argc)
103 105 continue;
104 106 opts->args =
105 107 reallocx(opts->args, (n + opts->argsize) * sizeof(char *));
106 108 memcpy(opts->args + opts->argsize, argv + i,
107 109 sizeof(char *) * n);
108 110 opts->argsize += n;
109 111 step = n;
110 112 }
111 113 }
112 114
113 115 static void preparesockdir(const char *sockdir)
114 116 {
115 117 int r;
116 118 r = mkdir(sockdir, 0700);
117 119 if (r < 0 && errno != EEXIST)
118 120 abortmsgerrno("cannot create sockdir %s", sockdir);
119 121
120 122 struct stat st;
121 123 r = lstat(sockdir, &st);
122 124 if (r < 0)
123 125 abortmsgerrno("cannot stat %s", sockdir);
124 126 if (!S_ISDIR(st.st_mode))
125 127 abortmsg("cannot create sockdir %s (file exists)", sockdir);
126 128 if (st.st_uid != geteuid() || st.st_mode & 0077)
127 129 abortmsg("insecure sockdir %s", sockdir);
128 130 }
129 131
130 132 /*
131 133 * Check if a socket directory exists and is only owned by the current user.
132 134 * Return 1 if so, 0 if not. This is used to check if XDG_RUNTIME_DIR can be
133 135 * used or not. According to the specification [1], XDG_RUNTIME_DIR should be
134 136 * ignored if the directory is not owned by the user with mode 0700.
135 137 * [1]: https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
136 138 */
137 139 static int checkruntimedir(const char *sockdir)
138 140 {
139 141 struct stat st;
140 142 int r = lstat(sockdir, &st);
141 143 if (r < 0) /* ex. does not exist */
142 144 return 0;
143 145 if (!S_ISDIR(st.st_mode)) /* ex. is a file, not a directory */
144 146 return 0;
145 147 return st.st_uid == geteuid() && (st.st_mode & 0777) == 0700;
146 148 }
147 149
148 150 static void getdefaultsockdir(char sockdir[], size_t size)
149 151 {
150 152 /* by default, put socket file in secure directory
151 153 * (${XDG_RUNTIME_DIR}/chg, or /${TMPDIR:-tmp}/chg$UID)
152 154 * (permission of socket file may be ignored on some Unices) */
153 155 const char *runtimedir = getenv("XDG_RUNTIME_DIR");
154 156 int r;
155 157 if (runtimedir && checkruntimedir(runtimedir)) {
156 158 r = snprintf(sockdir, size, "%s/chg", runtimedir);
157 159 } else {
158 160 const char *tmpdir = getenv("TMPDIR");
159 161 if (!tmpdir)
160 162 tmpdir = "/tmp";
161 163 r = snprintf(sockdir, size, "%s/chg%d", tmpdir, geteuid());
162 164 }
163 165 if (r < 0 || (size_t)r >= size)
164 166 abortmsg("too long TMPDIR (r = %d)", r);
165 167 }
166 168
167 169 static void setcmdserveropts(struct cmdserveropts *opts)
168 170 {
169 171 int r;
170 172 char sockdir[PATH_MAX];
171 173 const char *envsockname = getenv("CHGSOCKNAME");
172 174 if (!envsockname) {
173 175 getdefaultsockdir(sockdir, sizeof(sockdir));
174 176 preparesockdir(sockdir);
175 177 }
176 178
177 179 const char *basename = (envsockname) ? envsockname : sockdir;
178 180 const char *sockfmt = (envsockname) ? "%s" : "%s/server";
179 181 r = snprintf(opts->sockname, sizeof(opts->sockname), sockfmt, basename);
180 182 if (r < 0 || (size_t)r >= sizeof(opts->sockname))
181 183 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
182 184 r = snprintf(opts->initsockname, sizeof(opts->initsockname), "%s.%u",
183 185 opts->sockname, (unsigned)getpid());
184 186 if (r < 0 || (size_t)r >= sizeof(opts->initsockname))
185 187 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
186 188 }
187 189
188 190 /* If the current program is, say, /a/b/c/chg, returns /a/b/c/hg. */
189 191 static char *getrelhgcmd(void)
190 192 {
191 193 ssize_t n;
192 194 char *res, *slash;
193 195 int maxsize = 4096;
194 196 res = malloc(maxsize);
195 197 if (res == NULL)
196 198 goto cleanup;
197 199 n = readlink("/proc/self/exe", res, maxsize);
198 200 if (n < 0 || n >= maxsize)
199 201 goto cleanup;
200 202 res[n] = '\0';
201 203 slash = strrchr(res, '/');
202 204 if (slash == NULL)
203 205 goto cleanup;
204 206 /* 4 is strlen("/hg") + nul byte */
205 207 if (slash + 4 >= res + maxsize)
206 208 goto cleanup;
207 209 memcpy(slash, "/hg", 4);
208 210 return res;
209 211 cleanup:
210 212 free(res);
211 213 return NULL;
212 214 }
213 215
214 216 static const char *gethgcmd(void)
215 217 {
216 218 static const char *hgcmd = NULL;
217 219 #ifdef HGPATHREL
218 220 int tryrelhgcmd = 1;
219 221 #else
220 222 int tryrelhgcmd = 0;
221 223 #endif
222 224 if (!hgcmd) {
223 225 hgcmd = getenv("CHGHG");
224 226 if (!hgcmd || hgcmd[0] == '\0')
225 227 hgcmd = getenv("HG");
226 228 if (tryrelhgcmd && (!hgcmd || hgcmd[0] == '\0'))
227 229 hgcmd = getrelhgcmd();
228 230 if (!hgcmd || hgcmd[0] == '\0')
229 231 #ifdef HGPATH
230 232 hgcmd = (HGPATH);
231 233 #else
232 234 hgcmd = "hg";
233 235 #endif
234 236 }
235 /* Set $CHGHG to the path to the seleted hg executable if it wasn't
236 * already set. This has the effect of ensuring that a new command
237 * server will be spawned if the existing command server is running from
238 * an executable at a different path. */
239 if (setenv("CHGHG", hgcmd, 1) != 0)
240 abortmsgerrno("failed to setenv");
241 237 return hgcmd;
242 238 }
243 239
244 static void execcmdserver(const char *hgcmd, const struct cmdserveropts *opts)
240 static void execcmdserver(const struct cmdserveropts *opts)
245 241 {
246
242 const char *hgcmd = gethgcmd();
247 243 const char *baseargv[] = {
248 244 hgcmd, "serve", "--no-profile", "--cmdserver",
249 245 "chgunix", "--address", opts->initsockname, "--daemon-postexec",
250 246 "chdir:/",
251 247 };
252 248 size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]);
253 249 size_t argsize = baseargvsize + opts->argsize + 1;
254 250
255 251 const char **argv = mallocx(sizeof(char *) * argsize);
256 252 memcpy(argv, baseargv, sizeof(baseargv));
257 253 if (opts->args) {
258 254 size_t size = sizeof(char *) * opts->argsize;
259 255 memcpy(argv + baseargvsize, opts->args, size);
260 256 }
261 257 argv[argsize - 1] = NULL;
262 258
263 259 const char *lc_ctype_env = getenv("LC_CTYPE");
264 260 if (lc_ctype_env == NULL) {
265 261 if (putenv("CHG_CLEAR_LC_CTYPE=") != 0)
266 262 abortmsgerrno("failed to putenv CHG_CLEAR_LC_CTYPE");
267 263 } else {
268 264 if (setenv("CHGORIG_LC_CTYPE", lc_ctype_env, 1) != 0) {
269 265 abortmsgerrno("failed to setenv CHGORIG_LC_CTYPE");
270 266 }
271 267 }
272 268
273 269 /* close any open files to avoid hanging locks */
274 270 DIR *dp = opendir("/proc/self/fd");
275 271 if (dp != NULL) {
276 272 debugmsg("closing files based on /proc contents");
277 273 struct dirent *de;
278 274 while ((de = readdir(dp))) {
279 275 errno = 0;
280 276 char *end;
281 277 long fd_value = strtol(de->d_name, &end, 10);
282 278 if (end == de->d_name) {
283 279 /* unable to convert to int (. or ..) */
284 280 continue;
285 281 }
286 282 if (errno == ERANGE) {
287 283 debugmsg("tried to parse %s, but range error "
288 284 "occurred",
289 285 de->d_name);
290 286 continue;
291 287 }
292 288 if (fd_value > STDERR_FILENO && fd_value != dirfd(dp)) {
293 289 debugmsg("closing fd %ld", fd_value);
294 290 int res = close(fd_value);
295 291 if (res) {
296 292 debugmsg("tried to close fd %ld: %d "
297 293 "(errno: %d)",
298 294 fd_value, res, errno);
299 295 }
300 296 }
301 297 }
302 298 closedir(dp);
303 299 }
304 300
305 301 if (putenv("CHGINTERNALMARK=") != 0)
306 302 abortmsgerrno("failed to putenv");
307 303 if (execvp(hgcmd, (char **)argv) < 0)
308 304 abortmsgerrno("failed to exec cmdserver");
309 305 free(argv);
310 306 }
311 307
312 308 /* Retry until we can connect to the server. Give up after some time. */
313 309 static hgclient_t *retryconnectcmdserver(struct cmdserveropts *opts, pid_t pid)
314 310 {
315 311 static const struct timespec sleepreq = {0, 10 * 1000000};
316 312 int pst = 0;
317 313
318 314 debugmsg("try connect to %s repeatedly", opts->initsockname);
319 315
320 316 unsigned int timeoutsec = 60; /* default: 60 seconds */
321 317 const char *timeoutenv = getenv("CHGTIMEOUT");
322 318 if (timeoutenv)
323 319 sscanf(timeoutenv, "%u", &timeoutsec);
324 320
325 321 for (unsigned int i = 0; !timeoutsec || i < timeoutsec * 100; i++) {
326 322 hgclient_t *hgc = hgc_open(opts->initsockname);
327 323 if (hgc) {
328 324 debugmsg("rename %s to %s", opts->initsockname,
329 325 opts->sockname);
330 326 int r = rename(opts->initsockname, opts->sockname);
331 327 if (r != 0)
332 328 abortmsgerrno("cannot rename");
333 329 return hgc;
334 330 }
335 331
336 332 if (pid > 0) {
337 333 /* collect zombie if child process fails to start */
338 334 int r = waitpid(pid, &pst, WNOHANG);
339 335 if (r != 0)
340 336 goto cleanup;
341 337 }
342 338
343 339 nanosleep(&sleepreq, NULL);
344 340 }
345 341
346 342 abortmsg("timed out waiting for cmdserver %s", opts->initsockname);
347 343 return NULL;
348 344
349 345 cleanup:
350 346 if (WIFEXITED(pst)) {
351 347 if (WEXITSTATUS(pst) == 0)
352 348 abortmsg("could not connect to cmdserver "
353 349 "(exited with status 0)");
354 350 debugmsg("cmdserver exited with status %d", WEXITSTATUS(pst));
355 351 exit(WEXITSTATUS(pst));
356 352 } else if (WIFSIGNALED(pst)) {
357 353 abortmsg("cmdserver killed by signal %d", WTERMSIG(pst));
358 354 } else {
359 355 abortmsg("error while waiting for cmdserver");
360 356 }
361 357 return NULL;
362 358 }
363 359
364 360 /* Connect to a cmdserver. Will start a new server on demand. */
365 361 static hgclient_t *connectcmdserver(struct cmdserveropts *opts)
366 362 {
367 363 const char *sockname =
368 364 opts->redirectsockname[0] ? opts->redirectsockname : opts->sockname;
369 365 debugmsg("try connect to %s", sockname);
370 366 hgclient_t *hgc = hgc_open(sockname);
371 367 if (hgc)
372 368 return hgc;
373 369
374 370 /* prevent us from being connected to an outdated server: we were
375 371 * told by a server to redirect to opts->redirectsockname and that
376 372 * address does not work. we do not want to connect to the server
377 373 * again because it will probably tell us the same thing. */
378 374 if (sockname == opts->redirectsockname)
379 375 unlink(opts->sockname);
380 376
381 377 debugmsg("start cmdserver at %s", opts->initsockname);
382 378
383 /* Get the path to the hg executable before we fork because this
384 * function might update the environment, and we want this to be
385 * reflected in both the parent and child processes. */
386 const char *hgcmd = gethgcmd();
387
388 379 pid_t pid = fork();
389 380 if (pid < 0)
390 381 abortmsg("failed to fork cmdserver process");
391 382 if (pid == 0) {
392 execcmdserver(hgcmd, opts);
383 execcmdserver(opts);
393 384 } else {
394 385 hgc = retryconnectcmdserver(opts, pid);
395 386 }
396 387
397 388 return hgc;
398 389 }
399 390
400 391 static void killcmdserver(const struct cmdserveropts *opts)
401 392 {
402 393 /* resolve config hash */
403 394 char *resolvedpath = realpath(opts->sockname, NULL);
404 395 if (resolvedpath) {
405 396 unlink(resolvedpath);
406 397 free(resolvedpath);
407 398 }
408 399 }
409 400
410 401 /* Run instructions sent from the server like unlink and set redirect path
411 402 * Return 1 if reconnect is needed, otherwise 0 */
412 403 static int runinstructions(struct cmdserveropts *opts, const char **insts)
413 404 {
414 405 int needreconnect = 0;
415 406 if (!insts)
416 407 return needreconnect;
417 408
418 409 assert(insts);
419 410 opts->redirectsockname[0] = '\0';
420 411 const char **pinst;
421 412 for (pinst = insts; *pinst; pinst++) {
422 413 debugmsg("instruction: %s", *pinst);
423 414 if (strncmp(*pinst, "unlink ", 7) == 0) {
424 415 unlink(*pinst + 7);
425 416 } else if (strncmp(*pinst, "redirect ", 9) == 0) {
426 417 int r = snprintf(opts->redirectsockname,
427 418 sizeof(opts->redirectsockname), "%s",
428 419 *pinst + 9);
429 420 if (r < 0 || r >= (int)sizeof(opts->redirectsockname))
430 421 abortmsg("redirect path is too long (%d)", r);
431 422 needreconnect = 1;
432 423 } else if (strncmp(*pinst, "exit ", 5) == 0) {
433 424 int n = 0;
434 425 if (sscanf(*pinst + 5, "%d", &n) != 1)
435 426 abortmsg("cannot read the exit code");
436 427 exit(n);
437 428 } else if (strcmp(*pinst, "reconnect") == 0) {
438 429 needreconnect = 1;
439 430 } else {
440 431 abortmsg("unknown instruction: %s", *pinst);
441 432 }
442 433 }
443 434 return needreconnect;
444 435 }
445 436
446 437 /*
447 438 * Test whether the command and the environment is unsupported or not.
448 439 *
449 440 * If any of the stdio file descriptors are not present (rare, but some tools
450 441 * might spawn new processes without stdio instead of redirecting them to the
451 442 * null device), then mark it as not supported because attachio won't work
452 443 * correctly.
453 444 *
454 445 * The command list is not designed to cover all cases. But it's fast, and does
455 446 * not depend on the server.
456 447 */
457 448 static int isunsupported(int argc, const char *argv[])
458 449 {
459 450 enum {
460 451 SERVE = 1,
461 452 DAEMON = 2,
462 453 SERVEDAEMON = SERVE | DAEMON,
463 454 };
464 455 unsigned int state = 0;
465 456 int i;
466 457 /* use fcntl to test missing stdio fds */
467 458 if (fcntl(STDIN_FILENO, F_GETFD) == -1 ||
468 459 fcntl(STDOUT_FILENO, F_GETFD) == -1 ||
469 460 fcntl(STDERR_FILENO, F_GETFD) == -1) {
470 461 debugmsg("stdio fds are missing");
471 462 return 1;
472 463 }
473 464 for (i = 0; i < argc; ++i) {
474 465 if (strcmp(argv[i], "--") == 0)
475 466 break;
476 467 /*
477 468 * there can be false positives but no false negative
478 469 * we cannot assume `serve` will always be first argument
479 470 * because global options can be passed before the command name
480 471 */
481 472 if (strcmp("serve", argv[i]) == 0)
482 473 state |= SERVE;
483 474 else if (strcmp("-d", argv[i]) == 0 ||
484 475 strcmp("--daemon", argv[i]) == 0)
485 476 state |= DAEMON;
486 477 }
487 478 return (state & SERVEDAEMON) == SERVEDAEMON;
488 479 }
489 480
490 481 static void execoriginalhg(const char *argv[])
491 482 {
492 483 debugmsg("execute original hg");
493 484 if (execvp(gethgcmd(), (char **)argv) < 0)
494 485 abortmsgerrno("failed to exec original hg");
495 486 }
496 487
497 488 int main(int argc, const char *argv[])
498 489 {
499 490 if (getenv("CHGDEBUG"))
500 491 enabledebugmsg();
501 492
502 493 if (!getenv("HGPLAIN") && isatty(fileno(stderr)))
503 494 enablecolor();
504 495
505 496 if (getenv("CHGINTERNALMARK"))
506 497 abortmsg("chg started by chg detected.\n"
507 498 "Please make sure ${HG:-hg} is not a symlink or "
508 499 "wrapper to chg. Alternatively, set $CHGHG to the "
509 500 "path of real hg.");
510 501
511 502 if (isunsupported(argc - 1, argv + 1))
512 503 execoriginalhg(argv);
513 504
514 505 struct cmdserveropts opts;
515 506 initcmdserveropts(&opts);
516 507 setcmdserveropts(&opts);
517 508 setcmdserverargs(&opts, argc, argv);
518 509
519 510 if (argc == 2) {
520 511 if (strcmp(argv[1], "--kill-chg-daemon") == 0) {
521 512 killcmdserver(&opts);
522 513 return 0;
523 514 }
524 515 }
525 516
517 /* Set $CHGHG to the path of the hg executable we intend to use. This
518 * is a no-op if $CHGHG was expliclty specified, but otherwise this
519 * ensures that we will spawn a new command server if we connect to an
520 * existing one running from a different executable. This should only
521 * only be needed when chg is built with HGPATHREL since otherwise the
522 * hg executable used when CHGHG is absent should be deterministic.
523 * */
524 if (setenv("CHGHG", gethgcmd(), 1) != 0)
525 abortmsgerrno("failed to setenv");
526
526 527 hgclient_t *hgc;
527 528 size_t retry = 0;
528 529 while (1) {
529 530 hgc = connectcmdserver(&opts);
530 531 if (!hgc)
531 532 abortmsg("cannot open hg client");
532 533 /* Use `environ(7)` instead of the optional `envp` argument to
533 534 * `main` because `envp` does not update when the environment
534 535 * changes, but `environ` does. */
535 536 hgc_setenv(hgc, (const char *const *)environ);
536 537 const char **insts = hgc_validate(hgc, argv + 1, argc - 1);
537 538 int needreconnect = runinstructions(&opts, insts);
538 539 free(insts);
539 540 if (!needreconnect)
540 541 break;
541 542 hgc_close(hgc);
542 543 if (++retry > 10)
543 544 abortmsg("too many redirections.\n"
544 545 "Please make sure %s is not a wrapper which "
545 546 "changes sensitive environment variables "
546 547 "before executing hg. If you have to use a "
547 548 "wrapper, wrap chg instead of hg.",
548 549 gethgcmd());
549 550 }
550 551
551 552 setupsignalhandler(hgc_peerpid(hgc), hgc_peerpgid(hgc));
552 553 atexit(waitpager);
553 554 int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
554 555 restoresignalhandler();
555 556 hgc_close(hgc);
556 557 freecmdserveropts(&opts);
557 558
558 559 return exitcode;
559 560 }
@@ -1,958 +1,959 b''
1 1 # fix - rewrite file content in changesets and working copy
2 2 #
3 3 # Copyright 2018 Google LLC.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7 """rewrite file content in changesets or working copy (EXPERIMENTAL)
8 8
9 9 Provides a command that runs configured tools on the contents of modified files,
10 10 writing back any fixes to the working copy or replacing changesets.
11 11
12 Fixer tools are run in the repository's root directory. This allows them to read
13 configuration files from the working copy, or even write to the working copy.
14 The working copy is not updated to match the revision being fixed. In fact,
15 several revisions may be fixed in parallel. Writes to the working copy are not
16 amended into the revision being fixed; fixer tools MUST always read content to
17 be fixed from stdin, and write fixed file content back to stdout.
18
12 19 Here is an example configuration that causes :hg:`fix` to apply automatic
13 20 formatting fixes to modified lines in C++ code::
14 21
15 22 [fix]
16 23 clang-format:command=clang-format --assume-filename={rootpath}
17 24 clang-format:linerange=--lines={first}:{last}
18 25 clang-format:pattern=set:**.cpp or **.hpp
19 26
20 27 The :command suboption forms the first part of the shell command that will be
21 28 used to fix a file. The content of the file is passed on standard input, and the
22 29 fixed file content is expected on standard output. Any output on standard error
23 30 will be displayed as a warning. If the exit status is not zero, the file will
24 31 not be affected. A placeholder warning is displayed if there is a non-zero exit
25 32 status but no standard error output. Some values may be substituted into the
26 33 command::
27 34
28 35 {rootpath} The path of the file being fixed, relative to the repo root
29 36 {basename} The name of the file being fixed, without the directory path
30 37
31 38 If the :linerange suboption is set, the tool will only be run if there are
32 39 changed lines in a file. The value of this suboption is appended to the shell
33 40 command once for every range of changed lines in the file. Some values may be
34 41 substituted into the command::
35 42
36 43 {first} The 1-based line number of the first line in the modified range
37 44 {last} The 1-based line number of the last line in the modified range
38 45
39 46 Deleted sections of a file will be ignored by :linerange, because there is no
40 47 corresponding line range in the version being fixed.
41 48
42 49 By default, tools that set :linerange will only be executed if there is at least
43 50 one changed line range. This is meant to prevent accidents like running a code
44 51 formatter in such a way that it unexpectedly reformats the whole file. If such a
45 52 tool needs to operate on unchanged files, it should set the :skipclean suboption
46 53 to false.
47 54
48 55 The :pattern suboption determines which files will be passed through each
49 56 configured tool. See :hg:`help patterns` for possible values. However, all
50 57 patterns are relative to the repo root, even if that text says they are relative
51 58 to the current working directory. If there are file arguments to :hg:`fix`, the
52 59 intersection of these patterns is used.
53 60
54 61 There is also a configurable limit for the maximum size of file that will be
55 62 processed by :hg:`fix`::
56 63
57 64 [fix]
58 65 maxfilesize = 2MB
59 66
60 67 Normally, execution of configured tools will continue after a failure (indicated
61 68 by a non-zero exit status). It can also be configured to abort after the first
62 69 such failure, so that no files will be affected if any tool fails. This abort
63 70 will also cause :hg:`fix` to exit with a non-zero status::
64 71
65 72 [fix]
66 73 failure = abort
67 74
68 75 When multiple tools are configured to affect a file, they execute in an order
69 76 defined by the :priority suboption. The priority suboption has a default value
70 77 of zero for each tool. Tools are executed in order of descending priority. The
71 78 execution order of tools with equal priority is unspecified. For example, you
72 79 could use the 'sort' and 'head' utilities to keep only the 10 smallest numbers
73 80 in a text file by ensuring that 'sort' runs before 'head'::
74 81
75 82 [fix]
76 83 sort:command = sort -n
77 84 head:command = head -n 10
78 85 sort:pattern = numbers.txt
79 86 head:pattern = numbers.txt
80 87 sort:priority = 2
81 88 head:priority = 1
82 89
83 90 To account for changes made by each tool, the line numbers used for incremental
84 91 formatting are recomputed before executing the next tool. So, each tool may see
85 92 different values for the arguments added by the :linerange suboption.
86 93
87 94 Each fixer tool is allowed to return some metadata in addition to the fixed file
88 95 content. The metadata must be placed before the file content on stdout,
89 96 separated from the file content by a zero byte. The metadata is parsed as a JSON
90 97 value (so, it should be UTF-8 encoded and contain no zero bytes). A fixer tool
91 98 is expected to produce this metadata encoding if and only if the :metadata
92 99 suboption is true::
93 100
94 101 [fix]
95 102 tool:command = tool --prepend-json-metadata
96 103 tool:metadata = true
97 104
98 105 The metadata values are passed to hooks, which can be used to print summaries or
99 106 perform other post-fixing work. The supported hooks are::
100 107
101 108 "postfixfile"
102 109 Run once for each file in each revision where any fixer tools made changes
103 110 to the file content. Provides "$HG_REV" and "$HG_PATH" to identify the file,
104 111 and "$HG_METADATA" with a map of fixer names to metadata values from fixer
105 112 tools that affected the file. Fixer tools that didn't affect the file have a
106 113 value of None. Only fixer tools that executed are present in the metadata.
107 114
108 115 "postfix"
109 116 Run once after all files and revisions have been handled. Provides
110 117 "$HG_REPLACEMENTS" with information about what revisions were created and
111 118 made obsolete. Provides a boolean "$HG_WDIRWRITTEN" to indicate whether any
112 119 files in the working copy were updated. Provides a list "$HG_METADATA"
113 120 mapping fixer tool names to lists of metadata values returned from
114 121 executions that modified a file. This aggregates the same metadata
115 122 previously passed to the "postfixfile" hook.
116
117 Fixer tools are run in the repository's root directory. This allows them to read
118 configuration files from the working copy, or even write to the working copy.
119 The working copy is not updated to match the revision being fixed. In fact,
120 several revisions may be fixed in parallel. Writes to the working copy are not
121 amended into the revision being fixed; fixer tools should always write fixed
122 file content back to stdout as documented above.
123 123 """
124 124
125 125
126 126 import collections
127 127 import itertools
128 128 import os
129 129 import re
130 130 import subprocess
131 131
132 132 from mercurial.i18n import _
133 133 from mercurial.node import (
134 134 nullid,
135 135 nullrev,
136 136 wdirrev,
137 137 )
138 138
139 139 from mercurial.utils import procutil
140 140
141 141 from mercurial import (
142 142 cmdutil,
143 143 context,
144 144 copies,
145 145 error,
146 146 logcmdutil,
147 147 match as matchmod,
148 148 mdiff,
149 149 merge,
150 150 mergestate as mergestatemod,
151 151 pycompat,
152 152 registrar,
153 153 rewriteutil,
154 154 scmutil,
155 155 util,
156 156 worker,
157 157 )
158 158
159 159 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
160 160 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
161 161 # be specifying the version(s) of Mercurial they are tested with, or
162 162 # leave the attribute unspecified.
163 163 testedwith = b'ships-with-hg-core'
164 164
165 165 cmdtable = {}
166 166 command = registrar.command(cmdtable)
167 167
168 168 configtable = {}
169 169 configitem = registrar.configitem(configtable)
170 170
171 171 # Register the suboptions allowed for each configured fixer, and default values.
172 172 FIXER_ATTRS = {
173 173 b'command': None,
174 174 b'linerange': None,
175 175 b'pattern': None,
176 176 b'priority': 0,
177 177 b'metadata': False,
178 178 b'skipclean': True,
179 179 b'enabled': True,
180 180 }
181 181
182 182 for key, default in FIXER_ATTRS.items():
183 183 configitem(b'fix', b'.*:%s$' % key, default=default, generic=True)
184 184
185 185 # A good default size allows most source code files to be fixed, but avoids
186 186 # letting fixer tools choke on huge inputs, which could be surprising to the
187 187 # user.
188 188 configitem(b'fix', b'maxfilesize', default=b'2MB')
189 189
190 190 # Allow fix commands to exit non-zero if an executed fixer tool exits non-zero.
191 191 # This helps users do shell scripts that stop when a fixer tool signals a
192 192 # problem.
193 193 configitem(b'fix', b'failure', default=b'continue')
194 194
195 195
196 196 def checktoolfailureaction(ui, message, hint=None):
197 197 """Abort with 'message' if fix.failure=abort"""
198 198 action = ui.config(b'fix', b'failure')
199 199 if action not in (b'continue', b'abort'):
200 200 raise error.Abort(
201 201 _(b'unknown fix.failure action: %s') % (action,),
202 202 hint=_(b'use "continue" or "abort"'),
203 203 )
204 204 if action == b'abort':
205 205 raise error.Abort(message, hint=hint)
206 206
207 207
208 208 allopt = (b'', b'all', False, _(b'fix all non-public non-obsolete revisions'))
209 209 baseopt = (
210 210 b'',
211 211 b'base',
212 212 [],
213 213 _(
214 214 b'revisions to diff against (overrides automatic '
215 215 b'selection, and applies to every revision being '
216 216 b'fixed)'
217 217 ),
218 218 _(b'REV'),
219 219 )
220 220 revopt = (b'r', b'rev', [], _(b'revisions to fix (ADVANCED)'), _(b'REV'))
221 221 sourceopt = (
222 222 b's',
223 223 b'source',
224 224 [],
225 225 _(b'fix the specified revisions and their descendants'),
226 226 _(b'REV'),
227 227 )
228 228 wdiropt = (b'w', b'working-dir', False, _(b'fix the working directory'))
229 229 wholeopt = (b'', b'whole', False, _(b'always fix every line of a file'))
230 230 usage = _(b'[OPTION]... [FILE]...')
231 231
232 232
233 233 @command(
234 234 b'fix',
235 235 [allopt, baseopt, revopt, sourceopt, wdiropt, wholeopt],
236 236 usage,
237 237 helpcategory=command.CATEGORY_FILE_CONTENTS,
238 238 )
239 239 def fix(ui, repo, *pats, **opts):
240 240 """rewrite file content in changesets or working directory
241 241
242 Runs any configured tools to fix the content of files. Only affects files
242 Runs any configured tools to fix the content of files. (See
243 :hg:`help -e fix` for details about configuring tools.) Only affects files
243 244 with changes, unless file arguments are provided. Only affects changed lines
244 245 of files, unless the --whole flag is used. Some tools may always affect the
245 246 whole file regardless of --whole.
246 247
247 248 If --working-dir is used, files with uncommitted changes in the working copy
248 249 will be fixed. Note that no backup are made.
249 250
250 251 If revisions are specified with --source, those revisions and their
251 252 descendants will be checked, and they may be replaced with new revisions
252 253 that have fixed file content. By automatically including the descendants,
253 254 no merging, rebasing, or evolution will be required. If an ancestor of the
254 255 working copy is included, then the working copy itself will also be fixed,
255 256 and the working copy will be updated to the fixed parent.
256 257
257 258 When determining what lines of each file to fix at each revision, the whole
258 259 set of revisions being fixed is considered, so that fixes to earlier
259 260 revisions are not forgotten in later ones. The --base flag can be used to
260 261 override this default behavior, though it is not usually desirable to do so.
261 262 """
262 263 opts = pycompat.byteskwargs(opts)
263 264 cmdutil.check_at_most_one_arg(opts, b'all', b'source', b'rev')
264 265 cmdutil.check_incompatible_arguments(
265 266 opts, b'working_dir', [b'all', b'source']
266 267 )
267 268
268 269 with repo.wlock(), repo.lock(), repo.transaction(b'fix'):
269 270 revstofix = getrevstofix(ui, repo, opts)
270 271 basectxs = getbasectxs(repo, opts, revstofix)
271 272 workqueue, numitems = getworkqueue(
272 273 ui, repo, pats, opts, revstofix, basectxs
273 274 )
274 275 basepaths = getbasepaths(repo, opts, workqueue, basectxs)
275 276 fixers = getfixers(ui)
276 277
277 278 # Rather than letting each worker independently fetch the files
278 279 # (which also would add complications for shared/keepalive
279 280 # connections), prefetch them all first.
280 281 _prefetchfiles(repo, workqueue, basepaths)
281 282
282 283 # There are no data dependencies between the workers fixing each file
283 284 # revision, so we can use all available parallelism.
284 285 def getfixes(items):
285 286 for srcrev, path, dstrevs in items:
286 287 ctx = repo[srcrev]
287 288 olddata = ctx[path].data()
288 289 metadata, newdata = fixfile(
289 290 ui,
290 291 repo,
291 292 opts,
292 293 fixers,
293 294 ctx,
294 295 path,
295 296 basepaths,
296 297 basectxs[srcrev],
297 298 )
298 299 # We ungroup the work items now, because the code that consumes
299 300 # these results has to handle each dstrev separately, and in
300 301 # topological order. Because these are handled in topological
301 302 # order, it's important that we pass around references to
302 303 # "newdata" instead of copying it. Otherwise, we would be
303 304 # keeping more copies of file content in memory at a time than
304 305 # if we hadn't bothered to group/deduplicate the work items.
305 306 data = newdata if newdata != olddata else None
306 307 for dstrev in dstrevs:
307 308 yield (dstrev, path, metadata, data)
308 309
309 310 results = worker.worker(
310 311 ui, 1.0, getfixes, tuple(), workqueue, threadsafe=False
311 312 )
312 313
313 314 # We have to hold on to the data for each successor revision in memory
314 315 # until all its parents are committed. We ensure this by committing and
315 316 # freeing memory for the revisions in some topological order. This
316 317 # leaves a little bit of memory efficiency on the table, but also makes
317 318 # the tests deterministic. It might also be considered a feature since
318 319 # it makes the results more easily reproducible.
319 320 filedata = collections.defaultdict(dict)
320 321 aggregatemetadata = collections.defaultdict(list)
321 322 replacements = {}
322 323 wdirwritten = False
323 324 commitorder = sorted(revstofix, reverse=True)
324 325 with ui.makeprogress(
325 326 topic=_(b'fixing'), unit=_(b'files'), total=sum(numitems.values())
326 327 ) as progress:
327 328 for rev, path, filerevmetadata, newdata in results:
328 329 progress.increment(item=path)
329 330 for fixername, fixermetadata in filerevmetadata.items():
330 331 aggregatemetadata[fixername].append(fixermetadata)
331 332 if newdata is not None:
332 333 filedata[rev][path] = newdata
333 334 hookargs = {
334 335 b'rev': rev,
335 336 b'path': path,
336 337 b'metadata': filerevmetadata,
337 338 }
338 339 repo.hook(
339 340 b'postfixfile',
340 341 throw=False,
341 342 **pycompat.strkwargs(hookargs)
342 343 )
343 344 numitems[rev] -= 1
344 345 # Apply the fixes for this and any other revisions that are
345 346 # ready and sitting at the front of the queue. Using a loop here
346 347 # prevents the queue from being blocked by the first revision to
347 348 # be ready out of order.
348 349 while commitorder and not numitems[commitorder[-1]]:
349 350 rev = commitorder.pop()
350 351 ctx = repo[rev]
351 352 if rev == wdirrev:
352 353 writeworkingdir(repo, ctx, filedata[rev], replacements)
353 354 wdirwritten = bool(filedata[rev])
354 355 else:
355 356 replacerev(ui, repo, ctx, filedata[rev], replacements)
356 357 del filedata[rev]
357 358
358 359 cleanup(repo, replacements, wdirwritten)
359 360 hookargs = {
360 361 b'replacements': replacements,
361 362 b'wdirwritten': wdirwritten,
362 363 b'metadata': aggregatemetadata,
363 364 }
364 365 repo.hook(b'postfix', throw=True, **pycompat.strkwargs(hookargs))
365 366
366 367
367 368 def cleanup(repo, replacements, wdirwritten):
368 369 """Calls scmutil.cleanupnodes() with the given replacements.
369 370
370 371 "replacements" is a dict from nodeid to nodeid, with one key and one value
371 372 for every revision that was affected by fixing. This is slightly different
372 373 from cleanupnodes().
373 374
374 375 "wdirwritten" is a bool which tells whether the working copy was affected by
375 376 fixing, since it has no entry in "replacements".
376 377
377 378 Useful as a hook point for extending "hg fix" with output summarizing the
378 379 effects of the command, though we choose not to output anything here.
379 380 """
380 381 replacements = {prec: [succ] for prec, succ in replacements.items()}
381 382 scmutil.cleanupnodes(repo, replacements, b'fix', fixphase=True)
382 383
383 384
384 385 def getworkqueue(ui, repo, pats, opts, revstofix, basectxs):
385 386 """Constructs a list of files to fix and which revisions each fix applies to
386 387
387 388 To avoid duplicating work, there is usually only one work item for each file
388 389 revision that might need to be fixed. There can be multiple work items per
389 390 file revision if the same file needs to be fixed in multiple changesets with
390 391 different baserevs. Each work item also contains a list of changesets where
391 392 the file's data should be replaced with the fixed data. The work items for
392 393 earlier changesets come earlier in the work queue, to improve pipelining by
393 394 allowing the first changeset to be replaced while fixes are still being
394 395 computed for later changesets.
395 396
396 397 Also returned is a map from changesets to the count of work items that might
397 398 affect each changeset. This is used later to count when all of a changeset's
398 399 work items have been finished, without having to inspect the remaining work
399 400 queue in each worker subprocess.
400 401
401 402 The example work item (1, "foo/bar.txt", (1, 2, 3)) means that the data of
402 403 bar.txt should be read from revision 1, then fixed, and written back to
403 404 revisions 1, 2 and 3. Revision 1 is called the "srcrev" and the list of
404 405 revisions is called the "dstrevs". In practice the srcrev is always one of
405 406 the dstrevs, and we make that choice when constructing the work item so that
406 407 the choice can't be made inconsistently later on. The dstrevs should all
407 408 have the same file revision for the given path, so the choice of srcrev is
408 409 arbitrary. The wdirrev can be a dstrev and a srcrev.
409 410 """
410 411 dstrevmap = collections.defaultdict(list)
411 412 numitems = collections.defaultdict(int)
412 413 maxfilesize = ui.configbytes(b'fix', b'maxfilesize')
413 414 for rev in sorted(revstofix):
414 415 fixctx = repo[rev]
415 416 match = scmutil.match(fixctx, pats, opts)
416 417 for path in sorted(
417 418 pathstofix(ui, repo, pats, opts, match, basectxs[rev], fixctx)
418 419 ):
419 420 fctx = fixctx[path]
420 421 if fctx.islink():
421 422 continue
422 423 if fctx.size() > maxfilesize:
423 424 ui.warn(
424 425 _(b'ignoring file larger than %s: %s\n')
425 426 % (util.bytecount(maxfilesize), path)
426 427 )
427 428 continue
428 429 baserevs = tuple(ctx.rev() for ctx in basectxs[rev])
429 430 dstrevmap[(fctx.filerev(), baserevs, path)].append(rev)
430 431 numitems[rev] += 1
431 432 workqueue = [
432 433 (min(dstrevs), path, dstrevs)
433 434 for (_filerev, _baserevs, path), dstrevs in dstrevmap.items()
434 435 ]
435 436 # Move work items for earlier changesets to the front of the queue, so we
436 437 # might be able to replace those changesets (in topological order) while
437 438 # we're still processing later work items. Note the min() in the previous
438 439 # expression, which means we don't need a custom comparator here. The path
439 440 # is also important in the sort order to make the output order stable. There
440 441 # are some situations where this doesn't help much, but some situations
441 442 # where it lets us buffer O(1) files instead of O(n) files.
442 443 workqueue.sort()
443 444 return workqueue, numitems
444 445
445 446
446 447 def getrevstofix(ui, repo, opts):
447 448 """Returns the set of revision numbers that should be fixed"""
448 449 if opts[b'all']:
449 450 revs = repo.revs(b'(not public() and not obsolete()) or wdir()')
450 451 elif opts[b'source']:
451 452 source_revs = logcmdutil.revrange(repo, opts[b'source'])
452 453 revs = set(repo.revs(b'(%ld::) - obsolete()', source_revs))
453 454 if wdirrev in source_revs:
454 455 # `wdir()::` is currently empty, so manually add wdir
455 456 revs.add(wdirrev)
456 457 if repo[b'.'].rev() in revs:
457 458 revs.add(wdirrev)
458 459 else:
459 460 revs = set(logcmdutil.revrange(repo, opts[b'rev']))
460 461 if opts.get(b'working_dir'):
461 462 revs.add(wdirrev)
462 463 # Allow fixing only wdir() even if there's an unfinished operation
463 464 if not (len(revs) == 1 and wdirrev in revs):
464 465 cmdutil.checkunfinished(repo)
465 466 rewriteutil.precheck(repo, revs, b'fix')
466 467 if (
467 468 wdirrev in revs
468 469 and mergestatemod.mergestate.read(repo).unresolvedcount()
469 470 ):
470 471 raise error.Abort(b'unresolved conflicts', hint=b"use 'hg resolve'")
471 472 if not revs:
472 473 raise error.Abort(
473 474 b'no changesets specified', hint=b'use --source or --working-dir'
474 475 )
475 476 return revs
476 477
477 478
478 479 def pathstofix(ui, repo, pats, opts, match, basectxs, fixctx):
479 480 """Returns the set of files that should be fixed in a context
480 481
481 482 The result depends on the base contexts; we include any file that has
482 483 changed relative to any of the base contexts. Base contexts should be
483 484 ancestors of the context being fixed.
484 485 """
485 486 files = set()
486 487 for basectx in basectxs:
487 488 stat = basectx.status(
488 489 fixctx, match=match, listclean=bool(pats), listunknown=bool(pats)
489 490 )
490 491 files.update(
491 492 set(
492 493 itertools.chain(
493 494 stat.added, stat.modified, stat.clean, stat.unknown
494 495 )
495 496 )
496 497 )
497 498 return files
498 499
499 500
500 501 def lineranges(opts, path, basepaths, basectxs, fixctx, content2):
501 502 """Returns the set of line ranges that should be fixed in a file
502 503
503 504 Of the form [(10, 20), (30, 40)].
504 505
505 506 This depends on the given base contexts; we must consider lines that have
506 507 changed versus any of the base contexts, and whether the file has been
507 508 renamed versus any of them.
508 509
509 510 Another way to understand this is that we exclude line ranges that are
510 511 common to the file in all base contexts.
511 512 """
512 513 if opts.get(b'whole'):
513 514 # Return a range containing all lines. Rely on the diff implementation's
514 515 # idea of how many lines are in the file, instead of reimplementing it.
515 516 return difflineranges(b'', content2)
516 517
517 518 rangeslist = []
518 519 for basectx in basectxs:
519 520 basepath = basepaths.get((basectx.rev(), fixctx.rev(), path), path)
520 521
521 522 if basepath in basectx:
522 523 content1 = basectx[basepath].data()
523 524 else:
524 525 content1 = b''
525 526 rangeslist.extend(difflineranges(content1, content2))
526 527 return unionranges(rangeslist)
527 528
528 529
529 530 def getbasepaths(repo, opts, workqueue, basectxs):
530 531 if opts.get(b'whole'):
531 532 # Base paths will never be fetched for line range determination.
532 533 return {}
533 534
534 535 basepaths = {}
535 536 for srcrev, path, _dstrevs in workqueue:
536 537 fixctx = repo[srcrev]
537 538 for basectx in basectxs[srcrev]:
538 539 basepath = copies.pathcopies(basectx, fixctx).get(path, path)
539 540 if basepath in basectx:
540 541 basepaths[(basectx.rev(), fixctx.rev(), path)] = basepath
541 542 return basepaths
542 543
543 544
544 545 def unionranges(rangeslist):
545 546 """Return the union of some closed intervals
546 547
547 548 >>> unionranges([])
548 549 []
549 550 >>> unionranges([(1, 100)])
550 551 [(1, 100)]
551 552 >>> unionranges([(1, 100), (1, 100)])
552 553 [(1, 100)]
553 554 >>> unionranges([(1, 100), (2, 100)])
554 555 [(1, 100)]
555 556 >>> unionranges([(1, 99), (1, 100)])
556 557 [(1, 100)]
557 558 >>> unionranges([(1, 100), (40, 60)])
558 559 [(1, 100)]
559 560 >>> unionranges([(1, 49), (50, 100)])
560 561 [(1, 100)]
561 562 >>> unionranges([(1, 48), (50, 100)])
562 563 [(1, 48), (50, 100)]
563 564 >>> unionranges([(1, 2), (3, 4), (5, 6)])
564 565 [(1, 6)]
565 566 """
566 567 rangeslist = sorted(set(rangeslist))
567 568 unioned = []
568 569 if rangeslist:
569 570 unioned, rangeslist = [rangeslist[0]], rangeslist[1:]
570 571 for a, b in rangeslist:
571 572 c, d = unioned[-1]
572 573 if a > d + 1:
573 574 unioned.append((a, b))
574 575 else:
575 576 unioned[-1] = (c, max(b, d))
576 577 return unioned
577 578
578 579
579 580 def difflineranges(content1, content2):
580 581 """Return list of line number ranges in content2 that differ from content1.
581 582
582 583 Line numbers are 1-based. The numbers are the first and last line contained
583 584 in the range. Single-line ranges have the same line number for the first and
584 585 last line. Excludes any empty ranges that result from lines that are only
585 586 present in content1. Relies on mdiff's idea of where the line endings are in
586 587 the string.
587 588
588 589 >>> from mercurial import pycompat
589 590 >>> lines = lambda s: b'\\n'.join([c for c in pycompat.iterbytestr(s)])
590 591 >>> difflineranges2 = lambda a, b: difflineranges(lines(a), lines(b))
591 592 >>> difflineranges2(b'', b'')
592 593 []
593 594 >>> difflineranges2(b'a', b'')
594 595 []
595 596 >>> difflineranges2(b'', b'A')
596 597 [(1, 1)]
597 598 >>> difflineranges2(b'a', b'a')
598 599 []
599 600 >>> difflineranges2(b'a', b'A')
600 601 [(1, 1)]
601 602 >>> difflineranges2(b'ab', b'')
602 603 []
603 604 >>> difflineranges2(b'', b'AB')
604 605 [(1, 2)]
605 606 >>> difflineranges2(b'abc', b'ac')
606 607 []
607 608 >>> difflineranges2(b'ab', b'aCb')
608 609 [(2, 2)]
609 610 >>> difflineranges2(b'abc', b'aBc')
610 611 [(2, 2)]
611 612 >>> difflineranges2(b'ab', b'AB')
612 613 [(1, 2)]
613 614 >>> difflineranges2(b'abcde', b'aBcDe')
614 615 [(2, 2), (4, 4)]
615 616 >>> difflineranges2(b'abcde', b'aBCDe')
616 617 [(2, 4)]
617 618 """
618 619 ranges = []
619 620 for lines, kind in mdiff.allblocks(content1, content2):
620 621 firstline, lastline = lines[2:4]
621 622 if kind == b'!' and firstline != lastline:
622 623 ranges.append((firstline + 1, lastline))
623 624 return ranges
624 625
625 626
626 627 def getbasectxs(repo, opts, revstofix):
627 628 """Returns a map of the base contexts for each revision
628 629
629 630 The base contexts determine which lines are considered modified when we
630 631 attempt to fix just the modified lines in a file. It also determines which
631 632 files we attempt to fix, so it is important to compute this even when
632 633 --whole is used.
633 634 """
634 635 # The --base flag overrides the usual logic, and we give every revision
635 636 # exactly the set of baserevs that the user specified.
636 637 if opts.get(b'base'):
637 638 baserevs = set(logcmdutil.revrange(repo, opts.get(b'base')))
638 639 if not baserevs:
639 640 baserevs = {nullrev}
640 641 basectxs = {repo[rev] for rev in baserevs}
641 642 return {rev: basectxs for rev in revstofix}
642 643
643 644 # Proceed in topological order so that we can easily determine each
644 645 # revision's baserevs by looking at its parents and their baserevs.
645 646 basectxs = collections.defaultdict(set)
646 647 for rev in sorted(revstofix):
647 648 ctx = repo[rev]
648 649 for pctx in ctx.parents():
649 650 if pctx.rev() in basectxs:
650 651 basectxs[rev].update(basectxs[pctx.rev()])
651 652 else:
652 653 basectxs[rev].add(pctx)
653 654 return basectxs
654 655
655 656
656 657 def _prefetchfiles(repo, workqueue, basepaths):
657 658 toprefetch = set()
658 659
659 660 # Prefetch the files that will be fixed.
660 661 for srcrev, path, _dstrevs in workqueue:
661 662 if srcrev == wdirrev:
662 663 continue
663 664 toprefetch.add((srcrev, path))
664 665
665 666 # Prefetch the base contents for lineranges().
666 667 for (baserev, fixrev, path), basepath in basepaths.items():
667 668 toprefetch.add((baserev, basepath))
668 669
669 670 if toprefetch:
670 671 scmutil.prefetchfiles(
671 672 repo,
672 673 [
673 674 (rev, scmutil.matchfiles(repo, [path]))
674 675 for rev, path in toprefetch
675 676 ],
676 677 )
677 678
678 679
679 680 def fixfile(ui, repo, opts, fixers, fixctx, path, basepaths, basectxs):
680 681 """Run any configured fixers that should affect the file in this context
681 682
682 683 Returns the file content that results from applying the fixers in some order
683 684 starting with the file's content in the fixctx. Fixers that support line
684 685 ranges will affect lines that have changed relative to any of the basectxs
685 686 (i.e. they will only avoid lines that are common to all basectxs).
686 687
687 688 A fixer tool's stdout will become the file's new content if and only if it
688 689 exits with code zero. The fixer tool's working directory is the repository's
689 690 root.
690 691 """
691 692 metadata = {}
692 693 newdata = fixctx[path].data()
693 694 for fixername, fixer in fixers.items():
694 695 if fixer.affects(opts, fixctx, path):
695 696 ranges = lineranges(
696 697 opts, path, basepaths, basectxs, fixctx, newdata
697 698 )
698 699 command = fixer.command(ui, path, ranges)
699 700 if command is None:
700 701 continue
701 702 msg = b'fixing: %s - %s - %s\n'
702 703 msg %= (fixctx, fixername, path)
703 704 ui.debug(msg)
704 705 ui.debug(b'subprocess: %s\n' % (command,))
705 706 proc = subprocess.Popen(
706 707 procutil.tonativestr(command),
707 708 shell=True,
708 709 cwd=procutil.tonativestr(repo.root),
709 710 stdin=subprocess.PIPE,
710 711 stdout=subprocess.PIPE,
711 712 stderr=subprocess.PIPE,
712 713 )
713 714 stdout, stderr = proc.communicate(newdata)
714 715 if stderr:
715 716 showstderr(ui, fixctx.rev(), fixername, stderr)
716 717 newerdata = stdout
717 718 if fixer.shouldoutputmetadata():
718 719 try:
719 720 metadatajson, newerdata = stdout.split(b'\0', 1)
720 721 metadata[fixername] = pycompat.json_loads(metadatajson)
721 722 except ValueError:
722 723 ui.warn(
723 724 _(b'ignored invalid output from fixer tool: %s\n')
724 725 % (fixername,)
725 726 )
726 727 continue
727 728 else:
728 729 metadata[fixername] = None
729 730 if proc.returncode == 0:
730 731 newdata = newerdata
731 732 else:
732 733 if not stderr:
733 734 message = _(b'exited with status %d\n') % (proc.returncode,)
734 735 showstderr(ui, fixctx.rev(), fixername, message)
735 736 checktoolfailureaction(
736 737 ui,
737 738 _(b'no fixes will be applied'),
738 739 hint=_(
739 740 b'use --config fix.failure=continue to apply any '
740 741 b'successful fixes anyway'
741 742 ),
742 743 )
743 744 return metadata, newdata
744 745
745 746
746 747 def showstderr(ui, rev, fixername, stderr):
747 748 """Writes the lines of the stderr string as warnings on the ui
748 749
749 750 Uses the revision number and fixername to give more context to each line of
750 751 the error message. Doesn't include file names, since those take up a lot of
751 752 space and would tend to be included in the error message if they were
752 753 relevant.
753 754 """
754 755 for line in re.split(b'[\r\n]+', stderr):
755 756 if line:
756 757 ui.warn(b'[')
757 758 if rev is None:
758 759 ui.warn(_(b'wdir'), label=b'evolve.rev')
759 760 else:
760 761 ui.warn(b'%d' % rev, label=b'evolve.rev')
761 762 ui.warn(b'] %s: %s\n' % (fixername, line))
762 763
763 764
764 765 def writeworkingdir(repo, ctx, filedata, replacements):
765 766 """Write new content to the working copy and check out the new p1 if any
766 767
767 768 We check out a new revision if and only if we fixed something in both the
768 769 working directory and its parent revision. This avoids the need for a full
769 770 update/merge, and means that the working directory simply isn't affected
770 771 unless the --working-dir flag is given.
771 772
772 773 Directly updates the dirstate for the affected files.
773 774 """
774 775 for path, data in filedata.items():
775 776 fctx = ctx[path]
776 777 fctx.write(data, fctx.flags())
777 778
778 779 oldp1 = repo.dirstate.p1()
779 780 newp1 = replacements.get(oldp1, oldp1)
780 781 if newp1 != oldp1:
781 782 assert repo.dirstate.p2() == nullid
782 783 with repo.dirstate.changing_parents(repo):
783 784 scmutil.movedirstate(repo, repo[newp1])
784 785
785 786
786 787 def replacerev(ui, repo, ctx, filedata, replacements):
787 788 """Commit a new revision like the given one, but with file content changes
788 789
789 790 "ctx" is the original revision to be replaced by a modified one.
790 791
791 792 "filedata" is a dict that maps paths to their new file content. All other
792 793 paths will be recreated from the original revision without changes.
793 794 "filedata" may contain paths that didn't exist in the original revision;
794 795 they will be added.
795 796
796 797 "replacements" is a dict that maps a single node to a single node, and it is
797 798 updated to indicate the original revision is replaced by the newly created
798 799 one. No entry is added if the replacement's node already exists.
799 800
800 801 The new revision has the same parents as the old one, unless those parents
801 802 have already been replaced, in which case those replacements are the parents
802 803 of this new revision. Thus, if revisions are replaced in topological order,
803 804 there is no need to rebase them into the original topology later.
804 805 """
805 806
806 807 p1rev, p2rev = repo.changelog.parentrevs(ctx.rev())
807 808 p1ctx, p2ctx = repo[p1rev], repo[p2rev]
808 809 newp1node = replacements.get(p1ctx.node(), p1ctx.node())
809 810 newp2node = replacements.get(p2ctx.node(), p2ctx.node())
810 811
811 812 # We don't want to create a revision that has no changes from the original,
812 813 # but we should if the original revision's parent has been replaced.
813 814 # Otherwise, we would produce an orphan that needs no actual human
814 815 # intervention to evolve. We can't rely on commit() to avoid creating the
815 816 # un-needed revision because the extra field added below produces a new hash
816 817 # regardless of file content changes.
817 818 if (
818 819 not filedata
819 820 and p1ctx.node() not in replacements
820 821 and p2ctx.node() not in replacements
821 822 ):
822 823 return
823 824
824 825 extra = ctx.extra().copy()
825 826 extra[b'fix_source'] = ctx.hex()
826 827
827 828 wctx = context.overlayworkingctx(repo)
828 829 wctx.setbase(repo[newp1node])
829 830 merge.revert_to(ctx, wc=wctx)
830 831 copies.graftcopies(wctx, ctx, ctx.p1())
831 832
832 833 for path in filedata.keys():
833 834 fctx = ctx[path]
834 835 copysource = fctx.copysource()
835 836 wctx.write(path, filedata[path], flags=fctx.flags())
836 837 if copysource:
837 838 wctx.markcopied(path, copysource)
838 839
839 840 desc = rewriteutil.update_hash_refs(
840 841 repo,
841 842 ctx.description(),
842 843 {oldnode: [newnode] for oldnode, newnode in replacements.items()},
843 844 )
844 845
845 846 memctx = wctx.tomemctx(
846 847 text=desc,
847 848 branch=ctx.branch(),
848 849 extra=extra,
849 850 date=ctx.date(),
850 851 parents=(newp1node, newp2node),
851 852 user=ctx.user(),
852 853 )
853 854
854 855 sucnode = memctx.commit()
855 856 prenode = ctx.node()
856 857 if prenode == sucnode:
857 858 ui.debug(b'node %s already existed\n' % (ctx.hex()))
858 859 else:
859 860 replacements[ctx.node()] = sucnode
860 861
861 862
862 863 def getfixers(ui):
863 864 """Returns a map of configured fixer tools indexed by their names
864 865
865 866 Each value is a Fixer object with methods that implement the behavior of the
866 867 fixer's config suboptions. Does not validate the config values.
867 868 """
868 869 fixers = {}
869 870 for name in fixernames(ui):
870 871 enabled = ui.configbool(b'fix', name + b':enabled')
871 872 command = ui.config(b'fix', name + b':command')
872 873 pattern = ui.config(b'fix', name + b':pattern')
873 874 linerange = ui.config(b'fix', name + b':linerange')
874 875 priority = ui.configint(b'fix', name + b':priority')
875 876 metadata = ui.configbool(b'fix', name + b':metadata')
876 877 skipclean = ui.configbool(b'fix', name + b':skipclean')
877 878 # Don't use a fixer if it has no pattern configured. It would be
878 879 # dangerous to let it affect all files. It would be pointless to let it
879 880 # affect no files. There is no reasonable subset of files to use as the
880 881 # default.
881 882 if command is None:
882 883 ui.warn(
883 884 _(b'fixer tool has no command configuration: %s\n') % (name,)
884 885 )
885 886 elif pattern is None:
886 887 ui.warn(
887 888 _(b'fixer tool has no pattern configuration: %s\n') % (name,)
888 889 )
889 890 elif not enabled:
890 891 ui.debug(b'ignoring disabled fixer tool: %s\n' % (name,))
891 892 else:
892 893 fixers[name] = Fixer(
893 894 command, pattern, linerange, priority, metadata, skipclean
894 895 )
895 896 return collections.OrderedDict(
896 897 sorted(fixers.items(), key=lambda item: item[1]._priority, reverse=True)
897 898 )
898 899
899 900
900 901 def fixernames(ui):
901 902 """Returns the names of [fix] config options that have suboptions"""
902 903 names = set()
903 904 for k, v in ui.configitems(b'fix'):
904 905 if b':' in k:
905 906 names.add(k.split(b':', 1)[0])
906 907 return names
907 908
908 909
909 910 class Fixer:
910 911 """Wraps the raw config values for a fixer with methods"""
911 912
912 913 def __init__(
913 914 self, command, pattern, linerange, priority, metadata, skipclean
914 915 ):
915 916 self._command = command
916 917 self._pattern = pattern
917 918 self._linerange = linerange
918 919 self._priority = priority
919 920 self._metadata = metadata
920 921 self._skipclean = skipclean
921 922
922 923 def affects(self, opts, fixctx, path):
923 924 """Should this fixer run on the file at the given path and context?"""
924 925 repo = fixctx.repo()
925 926 matcher = matchmod.match(
926 927 repo.root, repo.root, [self._pattern], ctx=fixctx
927 928 )
928 929 return matcher(path)
929 930
930 931 def shouldoutputmetadata(self):
931 932 """Should the stdout of this fixer start with JSON and a null byte?"""
932 933 return self._metadata
933 934
934 935 def command(self, ui, path, ranges):
935 936 """A shell command to use to invoke this fixer on the given file/lines
936 937
937 938 May return None if there is no appropriate command to run for the given
938 939 parameters.
939 940 """
940 941 expand = cmdutil.rendercommandtemplate
941 942 parts = [
942 943 expand(
943 944 ui,
944 945 self._command,
945 946 {b'rootpath': path, b'basename': os.path.basename(path)},
946 947 )
947 948 ]
948 949 if self._linerange:
949 950 if self._skipclean and not ranges:
950 951 # No line ranges to fix, so don't run the fixer.
951 952 return None
952 953 for first, last in ranges:
953 954 parts.append(
954 955 expand(
955 956 ui, self._linerange, {b'first': first, b'last': last}
956 957 )
957 958 )
958 959 return b' '.join(parts)
@@ -1,2975 +1,2979 b''
1 1 # configitems.py - centralized declaration of configuration option
2 2 #
3 3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8
9 9 import functools
10 10 import re
11 11
12 12 from . import (
13 13 encoding,
14 14 error,
15 15 )
16 16
17 17
18 18 def loadconfigtable(ui, extname, configtable):
19 19 """update config item known to the ui with the extension ones"""
20 20 for section, items in sorted(configtable.items()):
21 21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 22 knownkeys = set(knownitems)
23 23 newkeys = set(items)
24 24 for key in sorted(knownkeys & newkeys):
25 25 msg = b"extension '%s' overwrite config item '%s.%s'"
26 26 msg %= (extname, section, key)
27 27 ui.develwarn(msg, config=b'warn-config')
28 28
29 29 knownitems.update(items)
30 30
31 31
32 32 class configitem:
33 33 """represent a known config item
34 34
35 35 :section: the official config section where to find this item,
36 36 :name: the official name within the section,
37 37 :default: default value for this item,
38 38 :alias: optional list of tuples as alternatives,
39 39 :generic: this is a generic definition, match name using regular expression.
40 40 """
41 41
42 42 def __init__(
43 43 self,
44 44 section,
45 45 name,
46 46 default=None,
47 47 alias=(),
48 48 generic=False,
49 49 priority=0,
50 50 experimental=False,
51 51 ):
52 52 self.section = section
53 53 self.name = name
54 54 self.default = default
55 55 self.alias = list(alias)
56 56 self.generic = generic
57 57 self.priority = priority
58 58 self.experimental = experimental
59 59 self._re = None
60 60 if generic:
61 61 self._re = re.compile(self.name)
62 62
63 63
64 64 class itemregister(dict):
65 65 """A specialized dictionary that can handle wild-card selection"""
66 66
67 67 def __init__(self):
68 68 super(itemregister, self).__init__()
69 69 self._generics = set()
70 70
71 71 def update(self, other):
72 72 super(itemregister, self).update(other)
73 73 self._generics.update(other._generics)
74 74
75 75 def __setitem__(self, key, item):
76 76 super(itemregister, self).__setitem__(key, item)
77 77 if item.generic:
78 78 self._generics.add(item)
79 79
80 80 def get(self, key):
81 81 baseitem = super(itemregister, self).get(key)
82 82 if baseitem is not None and not baseitem.generic:
83 83 return baseitem
84 84
85 85 # search for a matching generic item
86 86 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
87 87 for item in generics:
88 88 # we use 'match' instead of 'search' to make the matching simpler
89 89 # for people unfamiliar with regular expression. Having the match
90 90 # rooted to the start of the string will produce less surprising
91 91 # result for user writing simple regex for sub-attribute.
92 92 #
93 93 # For example using "color\..*" match produces an unsurprising
94 94 # result, while using search could suddenly match apparently
95 95 # unrelated configuration that happens to contains "color."
96 96 # anywhere. This is a tradeoff where we favor requiring ".*" on
97 97 # some match to avoid the need to prefix most pattern with "^".
98 98 # The "^" seems more error prone.
99 99 if item._re.match(key):
100 100 return item
101 101
102 102 return None
103 103
104 104
105 105 coreitems = {}
106 106
107 107
108 108 def _register(configtable, *args, **kwargs):
109 109 item = configitem(*args, **kwargs)
110 110 section = configtable.setdefault(item.section, itemregister())
111 111 if item.name in section:
112 112 msg = b"duplicated config item registration for '%s.%s'"
113 113 raise error.ProgrammingError(msg % (item.section, item.name))
114 114 section[item.name] = item
115 115
116 116
117 117 # special value for case where the default is derived from other values
118 118 dynamicdefault = object()
119 119
120 120 # Registering actual config items
121 121
122 122
123 123 def getitemregister(configtable):
124 124 f = functools.partial(_register, configtable)
125 125 # export pseudo enum as configitem.*
126 126 f.dynamicdefault = dynamicdefault
127 127 return f
128 128
129 129
130 130 coreconfigitem = getitemregister(coreitems)
131 131
132 132
133 133 def _registerdiffopts(section, configprefix=b''):
134 134 coreconfigitem(
135 135 section,
136 136 configprefix + b'nodates',
137 137 default=False,
138 138 )
139 139 coreconfigitem(
140 140 section,
141 141 configprefix + b'showfunc',
142 142 default=False,
143 143 )
144 144 coreconfigitem(
145 145 section,
146 146 configprefix + b'unified',
147 147 default=None,
148 148 )
149 149 coreconfigitem(
150 150 section,
151 151 configprefix + b'git',
152 152 default=False,
153 153 )
154 154 coreconfigitem(
155 155 section,
156 156 configprefix + b'ignorews',
157 157 default=False,
158 158 )
159 159 coreconfigitem(
160 160 section,
161 161 configprefix + b'ignorewsamount',
162 162 default=False,
163 163 )
164 164 coreconfigitem(
165 165 section,
166 166 configprefix + b'ignoreblanklines',
167 167 default=False,
168 168 )
169 169 coreconfigitem(
170 170 section,
171 171 configprefix + b'ignorewseol',
172 172 default=False,
173 173 )
174 174 coreconfigitem(
175 175 section,
176 176 configprefix + b'nobinary',
177 177 default=False,
178 178 )
179 179 coreconfigitem(
180 180 section,
181 181 configprefix + b'noprefix',
182 182 default=False,
183 183 )
184 184 coreconfigitem(
185 185 section,
186 186 configprefix + b'word-diff',
187 187 default=False,
188 188 )
189 189
190 190
191 191 coreconfigitem(
192 192 b'alias',
193 193 b'.*',
194 194 default=dynamicdefault,
195 195 generic=True,
196 196 )
197 197 coreconfigitem(
198 198 b'auth',
199 199 b'cookiefile',
200 200 default=None,
201 201 )
202 202 _registerdiffopts(section=b'annotate')
203 203 # bookmarks.pushing: internal hack for discovery
204 204 coreconfigitem(
205 205 b'bookmarks',
206 206 b'pushing',
207 207 default=list,
208 208 )
209 209 # bundle.mainreporoot: internal hack for bundlerepo
210 210 coreconfigitem(
211 211 b'bundle',
212 212 b'mainreporoot',
213 213 default=b'',
214 214 )
215 215 coreconfigitem(
216 216 b'censor',
217 217 b'policy',
218 218 default=b'abort',
219 219 experimental=True,
220 220 )
221 221 coreconfigitem(
222 222 b'chgserver',
223 223 b'idletimeout',
224 224 default=3600,
225 225 )
226 226 coreconfigitem(
227 227 b'chgserver',
228 228 b'skiphash',
229 229 default=False,
230 230 )
231 231 coreconfigitem(
232 232 b'cmdserver',
233 233 b'log',
234 234 default=None,
235 235 )
236 236 coreconfigitem(
237 237 b'cmdserver',
238 238 b'max-log-files',
239 239 default=7,
240 240 )
241 241 coreconfigitem(
242 242 b'cmdserver',
243 243 b'max-log-size',
244 244 default=b'1 MB',
245 245 )
246 246 coreconfigitem(
247 247 b'cmdserver',
248 248 b'max-repo-cache',
249 249 default=0,
250 250 experimental=True,
251 251 )
252 252 coreconfigitem(
253 253 b'cmdserver',
254 254 b'message-encodings',
255 255 default=list,
256 256 )
257 257 coreconfigitem(
258 258 b'cmdserver',
259 259 b'track-log',
260 260 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
261 261 )
262 262 coreconfigitem(
263 263 b'cmdserver',
264 264 b'shutdown-on-interrupt',
265 265 default=True,
266 266 )
267 267 coreconfigitem(
268 268 b'color',
269 269 b'.*',
270 270 default=None,
271 271 generic=True,
272 272 )
273 273 coreconfigitem(
274 274 b'color',
275 275 b'mode',
276 276 default=b'auto',
277 277 )
278 278 coreconfigitem(
279 279 b'color',
280 280 b'pagermode',
281 281 default=dynamicdefault,
282 282 )
283 283 coreconfigitem(
284 284 b'command-templates',
285 285 b'graphnode',
286 286 default=None,
287 287 alias=[(b'ui', b'graphnodetemplate')],
288 288 )
289 289 coreconfigitem(
290 290 b'command-templates',
291 291 b'log',
292 292 default=None,
293 293 alias=[(b'ui', b'logtemplate')],
294 294 )
295 295 coreconfigitem(
296 296 b'command-templates',
297 297 b'mergemarker',
298 298 default=(
299 299 b'{node|short} '
300 300 b'{ifeq(tags, "tip", "", '
301 301 b'ifeq(tags, "", "", "{tags} "))}'
302 302 b'{if(bookmarks, "{bookmarks} ")}'
303 303 b'{ifeq(branch, "default", "", "{branch} ")}'
304 304 b'- {author|user}: {desc|firstline}'
305 305 ),
306 306 alias=[(b'ui', b'mergemarkertemplate')],
307 307 )
308 308 coreconfigitem(
309 309 b'command-templates',
310 310 b'pre-merge-tool-output',
311 311 default=None,
312 312 alias=[(b'ui', b'pre-merge-tool-output-template')],
313 313 )
314 314 coreconfigitem(
315 315 b'command-templates',
316 316 b'oneline-summary',
317 317 default=None,
318 318 )
319 319 coreconfigitem(
320 320 b'command-templates',
321 321 b'oneline-summary.*',
322 322 default=dynamicdefault,
323 323 generic=True,
324 324 )
325 325 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
326 326 coreconfigitem(
327 327 b'commands',
328 328 b'commit.post-status',
329 329 default=False,
330 330 )
331 331 coreconfigitem(
332 332 b'commands',
333 333 b'grep.all-files',
334 334 default=False,
335 335 experimental=True,
336 336 )
337 337 coreconfigitem(
338 338 b'commands',
339 339 b'merge.require-rev',
340 340 default=False,
341 341 )
342 342 coreconfigitem(
343 343 b'commands',
344 344 b'push.require-revs',
345 345 default=False,
346 346 )
347 347 coreconfigitem(
348 348 b'commands',
349 349 b'resolve.confirm',
350 350 default=False,
351 351 )
352 352 coreconfigitem(
353 353 b'commands',
354 354 b'resolve.explicit-re-merge',
355 355 default=False,
356 356 )
357 357 coreconfigitem(
358 358 b'commands',
359 359 b'resolve.mark-check',
360 360 default=b'none',
361 361 )
362 362 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
363 363 coreconfigitem(
364 364 b'commands',
365 365 b'show.aliasprefix',
366 366 default=list,
367 367 )
368 368 coreconfigitem(
369 369 b'commands',
370 370 b'status.relative',
371 371 default=False,
372 372 )
373 373 coreconfigitem(
374 374 b'commands',
375 375 b'status.skipstates',
376 376 default=[],
377 377 experimental=True,
378 378 )
379 379 coreconfigitem(
380 380 b'commands',
381 381 b'status.terse',
382 382 default=b'',
383 383 )
384 384 coreconfigitem(
385 385 b'commands',
386 386 b'status.verbose',
387 387 default=False,
388 388 )
389 389 coreconfigitem(
390 390 b'commands',
391 391 b'update.check',
392 392 default=None,
393 393 )
394 394 coreconfigitem(
395 395 b'commands',
396 396 b'update.requiredest',
397 397 default=False,
398 398 )
399 399 coreconfigitem(
400 400 b'committemplate',
401 401 b'.*',
402 402 default=None,
403 403 generic=True,
404 404 )
405 405 coreconfigitem(
406 406 b'convert',
407 407 b'bzr.saverev',
408 408 default=True,
409 409 )
410 410 coreconfigitem(
411 411 b'convert',
412 412 b'cvsps.cache',
413 413 default=True,
414 414 )
415 415 coreconfigitem(
416 416 b'convert',
417 417 b'cvsps.fuzz',
418 418 default=60,
419 419 )
420 420 coreconfigitem(
421 421 b'convert',
422 422 b'cvsps.logencoding',
423 423 default=None,
424 424 )
425 425 coreconfigitem(
426 426 b'convert',
427 427 b'cvsps.mergefrom',
428 428 default=None,
429 429 )
430 430 coreconfigitem(
431 431 b'convert',
432 432 b'cvsps.mergeto',
433 433 default=None,
434 434 )
435 435 coreconfigitem(
436 436 b'convert',
437 437 b'git.committeractions',
438 438 default=lambda: [b'messagedifferent'],
439 439 )
440 440 coreconfigitem(
441 441 b'convert',
442 442 b'git.extrakeys',
443 443 default=list,
444 444 )
445 445 coreconfigitem(
446 446 b'convert',
447 447 b'git.findcopiesharder',
448 448 default=False,
449 449 )
450 450 coreconfigitem(
451 451 b'convert',
452 452 b'git.remoteprefix',
453 453 default=b'remote',
454 454 )
455 455 coreconfigitem(
456 456 b'convert',
457 457 b'git.renamelimit',
458 458 default=400,
459 459 )
460 460 coreconfigitem(
461 461 b'convert',
462 462 b'git.saverev',
463 463 default=True,
464 464 )
465 465 coreconfigitem(
466 466 b'convert',
467 467 b'git.similarity',
468 468 default=50,
469 469 )
470 470 coreconfigitem(
471 471 b'convert',
472 472 b'git.skipsubmodules',
473 473 default=False,
474 474 )
475 475 coreconfigitem(
476 476 b'convert',
477 477 b'hg.clonebranches',
478 478 default=False,
479 479 )
480 480 coreconfigitem(
481 481 b'convert',
482 482 b'hg.ignoreerrors',
483 483 default=False,
484 484 )
485 485 coreconfigitem(
486 486 b'convert',
487 487 b'hg.preserve-hash',
488 488 default=False,
489 489 )
490 490 coreconfigitem(
491 491 b'convert',
492 492 b'hg.revs',
493 493 default=None,
494 494 )
495 495 coreconfigitem(
496 496 b'convert',
497 497 b'hg.saverev',
498 498 default=False,
499 499 )
500 500 coreconfigitem(
501 501 b'convert',
502 502 b'hg.sourcename',
503 503 default=None,
504 504 )
505 505 coreconfigitem(
506 506 b'convert',
507 507 b'hg.startrev',
508 508 default=None,
509 509 )
510 510 coreconfigitem(
511 511 b'convert',
512 512 b'hg.tagsbranch',
513 513 default=b'default',
514 514 )
515 515 coreconfigitem(
516 516 b'convert',
517 517 b'hg.usebranchnames',
518 518 default=True,
519 519 )
520 520 coreconfigitem(
521 521 b'convert',
522 522 b'ignoreancestorcheck',
523 523 default=False,
524 524 experimental=True,
525 525 )
526 526 coreconfigitem(
527 527 b'convert',
528 528 b'localtimezone',
529 529 default=False,
530 530 )
531 531 coreconfigitem(
532 532 b'convert',
533 533 b'p4.encoding',
534 534 default=dynamicdefault,
535 535 )
536 536 coreconfigitem(
537 537 b'convert',
538 538 b'p4.startrev',
539 539 default=0,
540 540 )
541 541 coreconfigitem(
542 542 b'convert',
543 543 b'skiptags',
544 544 default=False,
545 545 )
546 546 coreconfigitem(
547 547 b'convert',
548 548 b'svn.debugsvnlog',
549 549 default=True,
550 550 )
551 551 coreconfigitem(
552 552 b'convert',
553 553 b'svn.trunk',
554 554 default=None,
555 555 )
556 556 coreconfigitem(
557 557 b'convert',
558 558 b'svn.tags',
559 559 default=None,
560 560 )
561 561 coreconfigitem(
562 562 b'convert',
563 563 b'svn.branches',
564 564 default=None,
565 565 )
566 566 coreconfigitem(
567 567 b'convert',
568 568 b'svn.startrev',
569 569 default=0,
570 570 )
571 571 coreconfigitem(
572 572 b'convert',
573 573 b'svn.dangerous-set-commit-dates',
574 574 default=False,
575 575 )
576 576 coreconfigitem(
577 577 b'debug',
578 578 b'dirstate.delaywrite',
579 579 default=0,
580 580 )
581 581 coreconfigitem(
582 582 b'debug',
583 583 b'revlog.verifyposition.changelog',
584 584 default=b'',
585 585 )
586 586 coreconfigitem(
587 587 b'debug',
588 588 b'revlog.debug-delta',
589 589 default=False,
590 590 )
591 591 # display extra information about the bundling process
592 592 coreconfigitem(
593 593 b'debug',
594 594 b'bundling-stats',
595 595 default=False,
596 596 )
597 597 # display extra information about the unbundling process
598 598 coreconfigitem(
599 599 b'debug',
600 600 b'unbundling-stats',
601 601 default=False,
602 602 )
603 603 coreconfigitem(
604 604 b'defaults',
605 605 b'.*',
606 606 default=None,
607 607 generic=True,
608 608 )
609 609 coreconfigitem(
610 610 b'devel',
611 611 b'all-warnings',
612 612 default=False,
613 613 )
614 614 coreconfigitem(
615 615 b'devel',
616 616 b'bundle2.debug',
617 617 default=False,
618 618 )
619 # which kind of delta to put in the bundled changegroup. Possible value
620 # - '': use default behavior
621 # - p1: force to always use delta against p1
622 # - full: force to always use full content
619 623 coreconfigitem(
620 624 b'devel',
621 625 b'bundle.delta',
622 626 default=b'',
623 627 )
624 628 coreconfigitem(
625 629 b'devel',
626 630 b'cache-vfs',
627 631 default=None,
628 632 )
629 633 coreconfigitem(
630 634 b'devel',
631 635 b'check-locks',
632 636 default=False,
633 637 )
634 638 coreconfigitem(
635 639 b'devel',
636 640 b'check-relroot',
637 641 default=False,
638 642 )
639 643 # Track copy information for all file, not just "added" one (very slow)
640 644 coreconfigitem(
641 645 b'devel',
642 646 b'copy-tracing.trace-all-files',
643 647 default=False,
644 648 )
645 649 coreconfigitem(
646 650 b'devel',
647 651 b'default-date',
648 652 default=None,
649 653 )
650 654 coreconfigitem(
651 655 b'devel',
652 656 b'deprec-warn',
653 657 default=False,
654 658 )
655 659 # possible values:
656 660 # - auto (the default)
657 661 # - force-append
658 662 # - force-new
659 663 coreconfigitem(
660 664 b'devel',
661 665 b'dirstate.v2.data_update_mode',
662 666 default="auto",
663 667 )
664 668 coreconfigitem(
665 669 b'devel',
666 670 b'disableloaddefaultcerts',
667 671 default=False,
668 672 )
669 673 coreconfigitem(
670 674 b'devel',
671 675 b'warn-empty-changegroup',
672 676 default=False,
673 677 )
674 678 coreconfigitem(
675 679 b'devel',
676 680 b'legacy.exchange',
677 681 default=list,
678 682 )
679 683 # When True, revlogs use a special reference version of the nodemap, that is not
680 684 # performant but is "known" to behave properly.
681 685 coreconfigitem(
682 686 b'devel',
683 687 b'persistent-nodemap',
684 688 default=False,
685 689 )
686 690 coreconfigitem(
687 691 b'devel',
688 692 b'servercafile',
689 693 default=b'',
690 694 )
691 695 # This config option is intended for use in tests only. It is a giant
692 696 # footgun to kill security. Don't define it.
693 697 coreconfigitem(
694 698 b'devel',
695 699 b'server-insecure-exact-protocol',
696 700 default=b'',
697 701 )
698 702 coreconfigitem(
699 703 b'devel',
700 704 b'serverrequirecert',
701 705 default=False,
702 706 )
703 707 # Makes the status algorithm wait for the existence of this file
704 708 # (or until a timeout of `devel.sync.status.pre-dirstate-write-file-timeout`
705 709 # seconds) before taking the lock and writing the dirstate.
706 710 # Status signals that it's ready to wait by creating a file
707 711 # with the same name + `.waiting`.
708 712 # Useful when testing race conditions.
709 713 coreconfigitem(
710 714 b'devel',
711 715 b'sync.status.pre-dirstate-write-file',
712 716 default=None,
713 717 )
714 718 coreconfigitem(
715 719 b'devel',
716 720 b'sync.status.pre-dirstate-write-file-timeout',
717 721 default=2,
718 722 )
719 723 coreconfigitem(
720 724 b'devel',
721 725 b'sync.dirstate.post-docket-read-file',
722 726 default=None,
723 727 )
724 728 coreconfigitem(
725 729 b'devel',
726 730 b'sync.dirstate.post-docket-read-file-timeout',
727 731 default=2,
728 732 )
729 733 coreconfigitem(
730 734 b'devel',
731 735 b'sync.dirstate.pre-read-file',
732 736 default=None,
733 737 )
734 738 coreconfigitem(
735 739 b'devel',
736 740 b'sync.dirstate.pre-read-file-timeout',
737 741 default=2,
738 742 )
739 743 coreconfigitem(
740 744 b'devel',
741 745 b'strip-obsmarkers',
742 746 default=True,
743 747 )
744 748 coreconfigitem(
745 749 b'devel',
746 750 b'warn-config',
747 751 default=None,
748 752 )
749 753 coreconfigitem(
750 754 b'devel',
751 755 b'warn-config-default',
752 756 default=None,
753 757 )
754 758 coreconfigitem(
755 759 b'devel',
756 760 b'user.obsmarker',
757 761 default=None,
758 762 )
759 763 coreconfigitem(
760 764 b'devel',
761 765 b'warn-config-unknown',
762 766 default=None,
763 767 )
764 768 coreconfigitem(
765 769 b'devel',
766 770 b'debug.copies',
767 771 default=False,
768 772 )
769 773 coreconfigitem(
770 774 b'devel',
771 775 b'copy-tracing.multi-thread',
772 776 default=True,
773 777 )
774 778 coreconfigitem(
775 779 b'devel',
776 780 b'debug.extensions',
777 781 default=False,
778 782 )
779 783 coreconfigitem(
780 784 b'devel',
781 785 b'debug.repo-filters',
782 786 default=False,
783 787 )
784 788 coreconfigitem(
785 789 b'devel',
786 790 b'debug.peer-request',
787 791 default=False,
788 792 )
789 793 # If discovery.exchange-heads is False, the discovery will not start with
790 794 # remote head fetching and local head querying.
791 795 coreconfigitem(
792 796 b'devel',
793 797 b'discovery.exchange-heads',
794 798 default=True,
795 799 )
796 800 # If devel.debug.abort-update is True, then any merge with the working copy,
797 801 # e.g. [hg update], will be aborted after figuring out what needs to be done,
798 802 # but before spawning the parallel worker
799 803 coreconfigitem(
800 804 b'devel',
801 805 b'debug.abort-update',
802 806 default=False,
803 807 )
804 808 # If discovery.grow-sample is False, the sample size used in set discovery will
805 809 # not be increased through the process
806 810 coreconfigitem(
807 811 b'devel',
808 812 b'discovery.grow-sample',
809 813 default=True,
810 814 )
811 815 # When discovery.grow-sample.dynamic is True, the default, the sample size is
812 816 # adapted to the shape of the undecided set (it is set to the max of:
813 817 # <target-size>, len(roots(undecided)), len(heads(undecided)
814 818 coreconfigitem(
815 819 b'devel',
816 820 b'discovery.grow-sample.dynamic',
817 821 default=True,
818 822 )
819 823 # discovery.grow-sample.rate control the rate at which the sample grow
820 824 coreconfigitem(
821 825 b'devel',
822 826 b'discovery.grow-sample.rate',
823 827 default=1.05,
824 828 )
825 829 # If discovery.randomize is False, random sampling during discovery are
826 830 # deterministic. It is meant for integration tests.
827 831 coreconfigitem(
828 832 b'devel',
829 833 b'discovery.randomize',
830 834 default=True,
831 835 )
832 836 # Control the initial size of the discovery sample
833 837 coreconfigitem(
834 838 b'devel',
835 839 b'discovery.sample-size',
836 840 default=200,
837 841 )
838 842 # Control the initial size of the discovery for initial change
839 843 coreconfigitem(
840 844 b'devel',
841 845 b'discovery.sample-size.initial',
842 846 default=100,
843 847 )
844 848 _registerdiffopts(section=b'diff')
845 849 coreconfigitem(
846 850 b'diff',
847 851 b'merge',
848 852 default=False,
849 853 experimental=True,
850 854 )
851 855 coreconfigitem(
852 856 b'email',
853 857 b'bcc',
854 858 default=None,
855 859 )
856 860 coreconfigitem(
857 861 b'email',
858 862 b'cc',
859 863 default=None,
860 864 )
861 865 coreconfigitem(
862 866 b'email',
863 867 b'charsets',
864 868 default=list,
865 869 )
866 870 coreconfigitem(
867 871 b'email',
868 872 b'from',
869 873 default=None,
870 874 )
871 875 coreconfigitem(
872 876 b'email',
873 877 b'method',
874 878 default=b'smtp',
875 879 )
876 880 coreconfigitem(
877 881 b'email',
878 882 b'reply-to',
879 883 default=None,
880 884 )
881 885 coreconfigitem(
882 886 b'email',
883 887 b'to',
884 888 default=None,
885 889 )
886 890 coreconfigitem(
887 891 b'experimental',
888 892 b'archivemetatemplate',
889 893 default=dynamicdefault,
890 894 )
891 895 coreconfigitem(
892 896 b'experimental',
893 897 b'auto-publish',
894 898 default=b'publish',
895 899 )
896 900 coreconfigitem(
897 901 b'experimental',
898 902 b'bundle-phases',
899 903 default=False,
900 904 )
901 905 coreconfigitem(
902 906 b'experimental',
903 907 b'bundle2-advertise',
904 908 default=True,
905 909 )
906 910 coreconfigitem(
907 911 b'experimental',
908 912 b'bundle2-output-capture',
909 913 default=False,
910 914 )
911 915 coreconfigitem(
912 916 b'experimental',
913 917 b'bundle2.pushback',
914 918 default=False,
915 919 )
916 920 coreconfigitem(
917 921 b'experimental',
918 922 b'bundle2lazylocking',
919 923 default=False,
920 924 )
921 925 coreconfigitem(
922 926 b'experimental',
923 927 b'bundlecomplevel',
924 928 default=None,
925 929 )
926 930 coreconfigitem(
927 931 b'experimental',
928 932 b'bundlecomplevel.bzip2',
929 933 default=None,
930 934 )
931 935 coreconfigitem(
932 936 b'experimental',
933 937 b'bundlecomplevel.gzip',
934 938 default=None,
935 939 )
936 940 coreconfigitem(
937 941 b'experimental',
938 942 b'bundlecomplevel.none',
939 943 default=None,
940 944 )
941 945 coreconfigitem(
942 946 b'experimental',
943 947 b'bundlecomplevel.zstd',
944 948 default=None,
945 949 )
946 950 coreconfigitem(
947 951 b'experimental',
948 952 b'bundlecompthreads',
949 953 default=None,
950 954 )
951 955 coreconfigitem(
952 956 b'experimental',
953 957 b'bundlecompthreads.bzip2',
954 958 default=None,
955 959 )
956 960 coreconfigitem(
957 961 b'experimental',
958 962 b'bundlecompthreads.gzip',
959 963 default=None,
960 964 )
961 965 coreconfigitem(
962 966 b'experimental',
963 967 b'bundlecompthreads.none',
964 968 default=None,
965 969 )
966 970 coreconfigitem(
967 971 b'experimental',
968 972 b'bundlecompthreads.zstd',
969 973 default=None,
970 974 )
971 975 coreconfigitem(
972 976 b'experimental',
973 977 b'changegroup3',
974 978 default=True,
975 979 )
976 980 coreconfigitem(
977 981 b'experimental',
978 982 b'changegroup4',
979 983 default=False,
980 984 )
981 985
982 986 # might remove rank configuration once the computation has no impact
983 987 coreconfigitem(
984 988 b'experimental',
985 989 b'changelog-v2.compute-rank',
986 990 default=True,
987 991 )
988 992 coreconfigitem(
989 993 b'experimental',
990 994 b'cleanup-as-archived',
991 995 default=False,
992 996 )
993 997 coreconfigitem(
994 998 b'experimental',
995 999 b'clientcompressionengines',
996 1000 default=list,
997 1001 )
998 1002 coreconfigitem(
999 1003 b'experimental',
1000 1004 b'copytrace',
1001 1005 default=b'on',
1002 1006 )
1003 1007 coreconfigitem(
1004 1008 b'experimental',
1005 1009 b'copytrace.movecandidateslimit',
1006 1010 default=100,
1007 1011 )
1008 1012 coreconfigitem(
1009 1013 b'experimental',
1010 1014 b'copytrace.sourcecommitlimit',
1011 1015 default=100,
1012 1016 )
1013 1017 coreconfigitem(
1014 1018 b'experimental',
1015 1019 b'copies.read-from',
1016 1020 default=b"filelog-only",
1017 1021 )
1018 1022 coreconfigitem(
1019 1023 b'experimental',
1020 1024 b'copies.write-to',
1021 1025 default=b'filelog-only',
1022 1026 )
1023 1027 coreconfigitem(
1024 1028 b'experimental',
1025 1029 b'crecordtest',
1026 1030 default=None,
1027 1031 )
1028 1032 coreconfigitem(
1029 1033 b'experimental',
1030 1034 b'directaccess',
1031 1035 default=False,
1032 1036 )
1033 1037 coreconfigitem(
1034 1038 b'experimental',
1035 1039 b'directaccess.revnums',
1036 1040 default=False,
1037 1041 )
1038 1042 coreconfigitem(
1039 1043 b'experimental',
1040 1044 b'editortmpinhg',
1041 1045 default=False,
1042 1046 )
1043 1047 coreconfigitem(
1044 1048 b'experimental',
1045 1049 b'evolution',
1046 1050 default=list,
1047 1051 )
1048 1052 coreconfigitem(
1049 1053 b'experimental',
1050 1054 b'evolution.allowdivergence',
1051 1055 default=False,
1052 1056 alias=[(b'experimental', b'allowdivergence')],
1053 1057 )
1054 1058 coreconfigitem(
1055 1059 b'experimental',
1056 1060 b'evolution.allowunstable',
1057 1061 default=None,
1058 1062 )
1059 1063 coreconfigitem(
1060 1064 b'experimental',
1061 1065 b'evolution.createmarkers',
1062 1066 default=None,
1063 1067 )
1064 1068 coreconfigitem(
1065 1069 b'experimental',
1066 1070 b'evolution.effect-flags',
1067 1071 default=True,
1068 1072 alias=[(b'experimental', b'effect-flags')],
1069 1073 )
1070 1074 coreconfigitem(
1071 1075 b'experimental',
1072 1076 b'evolution.exchange',
1073 1077 default=None,
1074 1078 )
1075 1079 coreconfigitem(
1076 1080 b'experimental',
1077 1081 b'evolution.bundle-obsmarker',
1078 1082 default=False,
1079 1083 )
1080 1084 coreconfigitem(
1081 1085 b'experimental',
1082 1086 b'evolution.bundle-obsmarker:mandatory',
1083 1087 default=True,
1084 1088 )
1085 1089 coreconfigitem(
1086 1090 b'experimental',
1087 1091 b'log.topo',
1088 1092 default=False,
1089 1093 )
1090 1094 coreconfigitem(
1091 1095 b'experimental',
1092 1096 b'evolution.report-instabilities',
1093 1097 default=True,
1094 1098 )
1095 1099 coreconfigitem(
1096 1100 b'experimental',
1097 1101 b'evolution.track-operation',
1098 1102 default=True,
1099 1103 )
1100 1104 # repo-level config to exclude a revset visibility
1101 1105 #
1102 1106 # The target use case is to use `share` to expose different subset of the same
1103 1107 # repository, especially server side. See also `server.view`.
1104 1108 coreconfigitem(
1105 1109 b'experimental',
1106 1110 b'extra-filter-revs',
1107 1111 default=None,
1108 1112 )
1109 1113 coreconfigitem(
1110 1114 b'experimental',
1111 1115 b'maxdeltachainspan',
1112 1116 default=-1,
1113 1117 )
1114 1118 # tracks files which were undeleted (merge might delete them but we explicitly
1115 1119 # kept/undeleted them) and creates new filenodes for them
1116 1120 coreconfigitem(
1117 1121 b'experimental',
1118 1122 b'merge-track-salvaged',
1119 1123 default=False,
1120 1124 )
1121 1125 coreconfigitem(
1122 1126 b'experimental',
1123 1127 b'mmapindexthreshold',
1124 1128 default=None,
1125 1129 )
1126 1130 coreconfigitem(
1127 1131 b'experimental',
1128 1132 b'narrow',
1129 1133 default=False,
1130 1134 )
1131 1135 coreconfigitem(
1132 1136 b'experimental',
1133 1137 b'nonnormalparanoidcheck',
1134 1138 default=False,
1135 1139 )
1136 1140 coreconfigitem(
1137 1141 b'experimental',
1138 1142 b'exportableenviron',
1139 1143 default=list,
1140 1144 )
1141 1145 coreconfigitem(
1142 1146 b'experimental',
1143 1147 b'extendedheader.index',
1144 1148 default=None,
1145 1149 )
1146 1150 coreconfigitem(
1147 1151 b'experimental',
1148 1152 b'extendedheader.similarity',
1149 1153 default=False,
1150 1154 )
1151 1155 coreconfigitem(
1152 1156 b'experimental',
1153 1157 b'graphshorten',
1154 1158 default=False,
1155 1159 )
1156 1160 coreconfigitem(
1157 1161 b'experimental',
1158 1162 b'graphstyle.parent',
1159 1163 default=dynamicdefault,
1160 1164 )
1161 1165 coreconfigitem(
1162 1166 b'experimental',
1163 1167 b'graphstyle.missing',
1164 1168 default=dynamicdefault,
1165 1169 )
1166 1170 coreconfigitem(
1167 1171 b'experimental',
1168 1172 b'graphstyle.grandparent',
1169 1173 default=dynamicdefault,
1170 1174 )
1171 1175 coreconfigitem(
1172 1176 b'experimental',
1173 1177 b'hook-track-tags',
1174 1178 default=False,
1175 1179 )
1176 1180 coreconfigitem(
1177 1181 b'experimental',
1178 1182 b'httppostargs',
1179 1183 default=False,
1180 1184 )
1181 1185 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1182 1186 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1183 1187
1184 1188 coreconfigitem(
1185 1189 b'experimental',
1186 1190 b'obsmarkers-exchange-debug',
1187 1191 default=False,
1188 1192 )
1189 1193 coreconfigitem(
1190 1194 b'experimental',
1191 1195 b'remotenames',
1192 1196 default=False,
1193 1197 )
1194 1198 coreconfigitem(
1195 1199 b'experimental',
1196 1200 b'removeemptydirs',
1197 1201 default=True,
1198 1202 )
1199 1203 coreconfigitem(
1200 1204 b'experimental',
1201 1205 b'revert.interactive.select-to-keep',
1202 1206 default=False,
1203 1207 )
1204 1208 coreconfigitem(
1205 1209 b'experimental',
1206 1210 b'revisions.prefixhexnode',
1207 1211 default=False,
1208 1212 )
1209 1213 # "out of experimental" todo list.
1210 1214 #
1211 1215 # * include management of a persistent nodemap in the main docket
1212 1216 # * enforce a "no-truncate" policy for mmap safety
1213 1217 # - for censoring operation
1214 1218 # - for stripping operation
1215 1219 # - for rollback operation
1216 1220 # * proper streaming (race free) of the docket file
1217 1221 # * track garbage data to evemtually allow rewriting -existing- sidedata.
1218 1222 # * Exchange-wise, we will also need to do something more efficient than
1219 1223 # keeping references to the affected revlogs, especially memory-wise when
1220 1224 # rewriting sidedata.
1221 1225 # * introduce a proper solution to reduce the number of filelog related files.
1222 1226 # * use caching for reading sidedata (similar to what we do for data).
1223 1227 # * no longer set offset=0 if sidedata_size=0 (simplify cutoff computation).
1224 1228 # * Improvement to consider
1225 1229 # - avoid compression header in chunk using the default compression?
1226 1230 # - forbid "inline" compression mode entirely?
1227 1231 # - split the data offset and flag field (the 2 bytes save are mostly trouble)
1228 1232 # - keep track of uncompressed -chunk- size (to preallocate memory better)
1229 1233 # - keep track of chain base or size (probably not that useful anymore)
1230 1234 coreconfigitem(
1231 1235 b'experimental',
1232 1236 b'revlogv2',
1233 1237 default=None,
1234 1238 )
1235 1239 coreconfigitem(
1236 1240 b'experimental',
1237 1241 b'revisions.disambiguatewithin',
1238 1242 default=None,
1239 1243 )
1240 1244 coreconfigitem(
1241 1245 b'experimental',
1242 1246 b'rust.index',
1243 1247 default=False,
1244 1248 )
1245 1249 coreconfigitem(
1246 1250 b'experimental',
1247 1251 b'server.allow-hidden-access',
1248 1252 default=list,
1249 1253 )
1250 1254 coreconfigitem(
1251 1255 b'experimental',
1252 1256 b'server.filesdata.recommended-batch-size',
1253 1257 default=50000,
1254 1258 )
1255 1259 coreconfigitem(
1256 1260 b'experimental',
1257 1261 b'server.manifestdata.recommended-batch-size',
1258 1262 default=100000,
1259 1263 )
1260 1264 coreconfigitem(
1261 1265 b'experimental',
1262 1266 b'server.stream-narrow-clones',
1263 1267 default=False,
1264 1268 )
1265 1269 coreconfigitem(
1266 1270 b'experimental',
1267 1271 b'single-head-per-branch',
1268 1272 default=False,
1269 1273 )
1270 1274 coreconfigitem(
1271 1275 b'experimental',
1272 1276 b'single-head-per-branch:account-closed-heads',
1273 1277 default=False,
1274 1278 )
1275 1279 coreconfigitem(
1276 1280 b'experimental',
1277 1281 b'single-head-per-branch:public-changes-only',
1278 1282 default=False,
1279 1283 )
1280 1284 coreconfigitem(
1281 1285 b'experimental',
1282 1286 b'sparse-read',
1283 1287 default=False,
1284 1288 )
1285 1289 coreconfigitem(
1286 1290 b'experimental',
1287 1291 b'sparse-read.density-threshold',
1288 1292 default=0.50,
1289 1293 )
1290 1294 coreconfigitem(
1291 1295 b'experimental',
1292 1296 b'sparse-read.min-gap-size',
1293 1297 default=b'65K',
1294 1298 )
1295 1299 coreconfigitem(
1296 1300 b'experimental',
1297 1301 b'treemanifest',
1298 1302 default=False,
1299 1303 )
1300 1304 coreconfigitem(
1301 1305 b'experimental',
1302 1306 b'update.atomic-file',
1303 1307 default=False,
1304 1308 )
1305 1309 coreconfigitem(
1306 1310 b'experimental',
1307 1311 b'web.full-garbage-collection-rate',
1308 1312 default=1, # still forcing a full collection on each request
1309 1313 )
1310 1314 coreconfigitem(
1311 1315 b'experimental',
1312 1316 b'worker.wdir-get-thread-safe',
1313 1317 default=False,
1314 1318 )
1315 1319 coreconfigitem(
1316 1320 b'experimental',
1317 1321 b'worker.repository-upgrade',
1318 1322 default=False,
1319 1323 )
1320 1324 coreconfigitem(
1321 1325 b'experimental',
1322 1326 b'xdiff',
1323 1327 default=False,
1324 1328 )
1325 1329 coreconfigitem(
1326 1330 b'extensions',
1327 1331 b'[^:]*',
1328 1332 default=None,
1329 1333 generic=True,
1330 1334 )
1331 1335 coreconfigitem(
1332 1336 b'extensions',
1333 1337 b'[^:]*:required',
1334 1338 default=False,
1335 1339 generic=True,
1336 1340 )
1337 1341 coreconfigitem(
1338 1342 b'extdata',
1339 1343 b'.*',
1340 1344 default=None,
1341 1345 generic=True,
1342 1346 )
1343 1347 coreconfigitem(
1344 1348 b'format',
1345 1349 b'bookmarks-in-store',
1346 1350 default=False,
1347 1351 )
1348 1352 coreconfigitem(
1349 1353 b'format',
1350 1354 b'chunkcachesize',
1351 1355 default=None,
1352 1356 experimental=True,
1353 1357 )
1354 1358 coreconfigitem(
1355 1359 # Enable this dirstate format *when creating a new repository*.
1356 1360 # Which format to use for existing repos is controlled by .hg/requires
1357 1361 b'format',
1358 1362 b'use-dirstate-v2',
1359 1363 default=False,
1360 1364 experimental=True,
1361 1365 alias=[(b'format', b'exp-rc-dirstate-v2')],
1362 1366 )
1363 1367 coreconfigitem(
1364 1368 b'format',
1365 1369 b'use-dirstate-v2.automatic-upgrade-of-mismatching-repositories',
1366 1370 default=False,
1367 1371 experimental=True,
1368 1372 )
1369 1373 coreconfigitem(
1370 1374 b'format',
1371 1375 b'use-dirstate-v2.automatic-upgrade-of-mismatching-repositories:quiet',
1372 1376 default=False,
1373 1377 experimental=True,
1374 1378 )
1375 1379 coreconfigitem(
1376 1380 b'format',
1377 1381 b'use-dirstate-tracked-hint',
1378 1382 default=False,
1379 1383 experimental=True,
1380 1384 )
1381 1385 coreconfigitem(
1382 1386 b'format',
1383 1387 b'use-dirstate-tracked-hint.version',
1384 1388 default=1,
1385 1389 experimental=True,
1386 1390 )
1387 1391 coreconfigitem(
1388 1392 b'format',
1389 1393 b'use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories',
1390 1394 default=False,
1391 1395 experimental=True,
1392 1396 )
1393 1397 coreconfigitem(
1394 1398 b'format',
1395 1399 b'use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories:quiet',
1396 1400 default=False,
1397 1401 experimental=True,
1398 1402 )
1399 1403 coreconfigitem(
1400 1404 b'format',
1401 1405 b'dotencode',
1402 1406 default=True,
1403 1407 )
1404 1408 coreconfigitem(
1405 1409 b'format',
1406 1410 b'generaldelta',
1407 1411 default=False,
1408 1412 experimental=True,
1409 1413 )
1410 1414 coreconfigitem(
1411 1415 b'format',
1412 1416 b'manifestcachesize',
1413 1417 default=None,
1414 1418 experimental=True,
1415 1419 )
1416 1420 coreconfigitem(
1417 1421 b'format',
1418 1422 b'maxchainlen',
1419 1423 default=dynamicdefault,
1420 1424 experimental=True,
1421 1425 )
1422 1426 coreconfigitem(
1423 1427 b'format',
1424 1428 b'obsstore-version',
1425 1429 default=None,
1426 1430 )
1427 1431 coreconfigitem(
1428 1432 b'format',
1429 1433 b'sparse-revlog',
1430 1434 default=True,
1431 1435 )
1432 1436 coreconfigitem(
1433 1437 b'format',
1434 1438 b'revlog-compression',
1435 1439 default=lambda: [b'zstd', b'zlib'],
1436 1440 alias=[(b'experimental', b'format.compression')],
1437 1441 )
1438 1442 # Experimental TODOs:
1439 1443 #
1440 1444 # * Same as for revlogv2 (but for the reduction of the number of files)
1441 1445 # * Actually computing the rank of changesets
1442 1446 # * Improvement to investigate
1443 1447 # - storing .hgtags fnode
1444 1448 # - storing branch related identifier
1445 1449
1446 1450 coreconfigitem(
1447 1451 b'format',
1448 1452 b'exp-use-changelog-v2',
1449 1453 default=None,
1450 1454 experimental=True,
1451 1455 )
1452 1456 coreconfigitem(
1453 1457 b'format',
1454 1458 b'usefncache',
1455 1459 default=True,
1456 1460 )
1457 1461 coreconfigitem(
1458 1462 b'format',
1459 1463 b'usegeneraldelta',
1460 1464 default=True,
1461 1465 )
1462 1466 coreconfigitem(
1463 1467 b'format',
1464 1468 b'usestore',
1465 1469 default=True,
1466 1470 )
1467 1471
1468 1472
1469 1473 def _persistent_nodemap_default():
1470 1474 """compute `use-persistent-nodemap` default value
1471 1475
1472 1476 The feature is disabled unless a fast implementation is available.
1473 1477 """
1474 1478 from . import policy
1475 1479
1476 1480 return policy.importrust('revlog') is not None
1477 1481
1478 1482
1479 1483 coreconfigitem(
1480 1484 b'format',
1481 1485 b'use-persistent-nodemap',
1482 1486 default=_persistent_nodemap_default,
1483 1487 )
1484 1488 coreconfigitem(
1485 1489 b'format',
1486 1490 b'exp-use-copies-side-data-changeset',
1487 1491 default=False,
1488 1492 experimental=True,
1489 1493 )
1490 1494 coreconfigitem(
1491 1495 b'format',
1492 1496 b'use-share-safe',
1493 1497 default=True,
1494 1498 )
1495 1499 coreconfigitem(
1496 1500 b'format',
1497 1501 b'use-share-safe.automatic-upgrade-of-mismatching-repositories',
1498 1502 default=False,
1499 1503 experimental=True,
1500 1504 )
1501 1505 coreconfigitem(
1502 1506 b'format',
1503 1507 b'use-share-safe.automatic-upgrade-of-mismatching-repositories:quiet',
1504 1508 default=False,
1505 1509 experimental=True,
1506 1510 )
1507 1511
1508 1512 # Moving this on by default means we are confident about the scaling of phases.
1509 1513 # This is not garanteed to be the case at the time this message is written.
1510 1514 coreconfigitem(
1511 1515 b'format',
1512 1516 b'use-internal-phase',
1513 1517 default=False,
1514 1518 experimental=True,
1515 1519 )
1516 1520 # The interaction between the archived phase and obsolescence markers needs to
1517 1521 # be sorted out before wider usage of this are to be considered.
1518 1522 #
1519 1523 # At the time this message is written, behavior when archiving obsolete
1520 1524 # changeset differ significantly from stripping. As part of stripping, we also
1521 1525 # remove the obsolescence marker associated to the stripped changesets,
1522 1526 # revealing the precedecessors changesets when applicable. When archiving, we
1523 1527 # don't touch the obsolescence markers, keeping everything hidden. This can
1524 1528 # result in quite confusing situation for people combining exchanging draft
1525 1529 # with the archived phases. As some markers needed by others may be skipped
1526 1530 # during exchange.
1527 1531 coreconfigitem(
1528 1532 b'format',
1529 1533 b'exp-archived-phase',
1530 1534 default=False,
1531 1535 experimental=True,
1532 1536 )
1533 1537 coreconfigitem(
1534 1538 b'shelve',
1535 1539 b'store',
1536 1540 default=b'internal',
1537 1541 experimental=True,
1538 1542 )
1539 1543 coreconfigitem(
1540 1544 b'fsmonitor',
1541 1545 b'warn_when_unused',
1542 1546 default=True,
1543 1547 )
1544 1548 coreconfigitem(
1545 1549 b'fsmonitor',
1546 1550 b'warn_update_file_count',
1547 1551 default=50000,
1548 1552 )
1549 1553 coreconfigitem(
1550 1554 b'fsmonitor',
1551 1555 b'warn_update_file_count_rust',
1552 1556 default=400000,
1553 1557 )
1554 1558 coreconfigitem(
1555 1559 b'help',
1556 1560 br'hidden-command\..*',
1557 1561 default=False,
1558 1562 generic=True,
1559 1563 )
1560 1564 coreconfigitem(
1561 1565 b'help',
1562 1566 br'hidden-topic\..*',
1563 1567 default=False,
1564 1568 generic=True,
1565 1569 )
1566 1570 coreconfigitem(
1567 1571 b'hooks',
1568 1572 b'[^:]*',
1569 1573 default=dynamicdefault,
1570 1574 generic=True,
1571 1575 )
1572 1576 coreconfigitem(
1573 1577 b'hooks',
1574 1578 b'.*:run-with-plain',
1575 1579 default=True,
1576 1580 generic=True,
1577 1581 )
1578 1582 coreconfigitem(
1579 1583 b'hgweb-paths',
1580 1584 b'.*',
1581 1585 default=list,
1582 1586 generic=True,
1583 1587 )
1584 1588 coreconfigitem(
1585 1589 b'hostfingerprints',
1586 1590 b'.*',
1587 1591 default=list,
1588 1592 generic=True,
1589 1593 )
1590 1594 coreconfigitem(
1591 1595 b'hostsecurity',
1592 1596 b'ciphers',
1593 1597 default=None,
1594 1598 )
1595 1599 coreconfigitem(
1596 1600 b'hostsecurity',
1597 1601 b'minimumprotocol',
1598 1602 default=dynamicdefault,
1599 1603 )
1600 1604 coreconfigitem(
1601 1605 b'hostsecurity',
1602 1606 b'.*:minimumprotocol$',
1603 1607 default=dynamicdefault,
1604 1608 generic=True,
1605 1609 )
1606 1610 coreconfigitem(
1607 1611 b'hostsecurity',
1608 1612 b'.*:ciphers$',
1609 1613 default=dynamicdefault,
1610 1614 generic=True,
1611 1615 )
1612 1616 coreconfigitem(
1613 1617 b'hostsecurity',
1614 1618 b'.*:fingerprints$',
1615 1619 default=list,
1616 1620 generic=True,
1617 1621 )
1618 1622 coreconfigitem(
1619 1623 b'hostsecurity',
1620 1624 b'.*:verifycertsfile$',
1621 1625 default=None,
1622 1626 generic=True,
1623 1627 )
1624 1628
1625 1629 coreconfigitem(
1626 1630 b'http_proxy',
1627 1631 b'always',
1628 1632 default=False,
1629 1633 )
1630 1634 coreconfigitem(
1631 1635 b'http_proxy',
1632 1636 b'host',
1633 1637 default=None,
1634 1638 )
1635 1639 coreconfigitem(
1636 1640 b'http_proxy',
1637 1641 b'no',
1638 1642 default=list,
1639 1643 )
1640 1644 coreconfigitem(
1641 1645 b'http_proxy',
1642 1646 b'passwd',
1643 1647 default=None,
1644 1648 )
1645 1649 coreconfigitem(
1646 1650 b'http_proxy',
1647 1651 b'user',
1648 1652 default=None,
1649 1653 )
1650 1654
1651 1655 coreconfigitem(
1652 1656 b'http',
1653 1657 b'timeout',
1654 1658 default=None,
1655 1659 )
1656 1660
1657 1661 coreconfigitem(
1658 1662 b'logtoprocess',
1659 1663 b'commandexception',
1660 1664 default=None,
1661 1665 )
1662 1666 coreconfigitem(
1663 1667 b'logtoprocess',
1664 1668 b'commandfinish',
1665 1669 default=None,
1666 1670 )
1667 1671 coreconfigitem(
1668 1672 b'logtoprocess',
1669 1673 b'command',
1670 1674 default=None,
1671 1675 )
1672 1676 coreconfigitem(
1673 1677 b'logtoprocess',
1674 1678 b'develwarn',
1675 1679 default=None,
1676 1680 )
1677 1681 coreconfigitem(
1678 1682 b'logtoprocess',
1679 1683 b'uiblocked',
1680 1684 default=None,
1681 1685 )
1682 1686 coreconfigitem(
1683 1687 b'merge',
1684 1688 b'checkunknown',
1685 1689 default=b'abort',
1686 1690 )
1687 1691 coreconfigitem(
1688 1692 b'merge',
1689 1693 b'checkignored',
1690 1694 default=b'abort',
1691 1695 )
1692 1696 coreconfigitem(
1693 1697 b'experimental',
1694 1698 b'merge.checkpathconflicts',
1695 1699 default=False,
1696 1700 )
1697 1701 coreconfigitem(
1698 1702 b'merge',
1699 1703 b'followcopies',
1700 1704 default=True,
1701 1705 )
1702 1706 coreconfigitem(
1703 1707 b'merge',
1704 1708 b'on-failure',
1705 1709 default=b'continue',
1706 1710 )
1707 1711 coreconfigitem(
1708 1712 b'merge',
1709 1713 b'preferancestor',
1710 1714 default=lambda: [b'*'],
1711 1715 experimental=True,
1712 1716 )
1713 1717 coreconfigitem(
1714 1718 b'merge',
1715 1719 b'strict-capability-check',
1716 1720 default=False,
1717 1721 )
1718 1722 coreconfigitem(
1719 1723 b'merge',
1720 1724 b'disable-partial-tools',
1721 1725 default=False,
1722 1726 experimental=True,
1723 1727 )
1724 1728 coreconfigitem(
1725 1729 b'partial-merge-tools',
1726 1730 b'.*',
1727 1731 default=None,
1728 1732 generic=True,
1729 1733 experimental=True,
1730 1734 )
1731 1735 coreconfigitem(
1732 1736 b'partial-merge-tools',
1733 1737 br'.*\.patterns',
1734 1738 default=dynamicdefault,
1735 1739 generic=True,
1736 1740 priority=-1,
1737 1741 experimental=True,
1738 1742 )
1739 1743 coreconfigitem(
1740 1744 b'partial-merge-tools',
1741 1745 br'.*\.executable$',
1742 1746 default=dynamicdefault,
1743 1747 generic=True,
1744 1748 priority=-1,
1745 1749 experimental=True,
1746 1750 )
1747 1751 coreconfigitem(
1748 1752 b'partial-merge-tools',
1749 1753 br'.*\.order',
1750 1754 default=0,
1751 1755 generic=True,
1752 1756 priority=-1,
1753 1757 experimental=True,
1754 1758 )
1755 1759 coreconfigitem(
1756 1760 b'partial-merge-tools',
1757 1761 br'.*\.args',
1758 1762 default=b"$local $base $other",
1759 1763 generic=True,
1760 1764 priority=-1,
1761 1765 experimental=True,
1762 1766 )
1763 1767 coreconfigitem(
1764 1768 b'partial-merge-tools',
1765 1769 br'.*\.disable',
1766 1770 default=False,
1767 1771 generic=True,
1768 1772 priority=-1,
1769 1773 experimental=True,
1770 1774 )
1771 1775 coreconfigitem(
1772 1776 b'merge-tools',
1773 1777 b'.*',
1774 1778 default=None,
1775 1779 generic=True,
1776 1780 )
1777 1781 coreconfigitem(
1778 1782 b'merge-tools',
1779 1783 br'.*\.args$',
1780 1784 default=b"$local $base $other",
1781 1785 generic=True,
1782 1786 priority=-1,
1783 1787 )
1784 1788 coreconfigitem(
1785 1789 b'merge-tools',
1786 1790 br'.*\.binary$',
1787 1791 default=False,
1788 1792 generic=True,
1789 1793 priority=-1,
1790 1794 )
1791 1795 coreconfigitem(
1792 1796 b'merge-tools',
1793 1797 br'.*\.check$',
1794 1798 default=list,
1795 1799 generic=True,
1796 1800 priority=-1,
1797 1801 )
1798 1802 coreconfigitem(
1799 1803 b'merge-tools',
1800 1804 br'.*\.checkchanged$',
1801 1805 default=False,
1802 1806 generic=True,
1803 1807 priority=-1,
1804 1808 )
1805 1809 coreconfigitem(
1806 1810 b'merge-tools',
1807 1811 br'.*\.executable$',
1808 1812 default=dynamicdefault,
1809 1813 generic=True,
1810 1814 priority=-1,
1811 1815 )
1812 1816 coreconfigitem(
1813 1817 b'merge-tools',
1814 1818 br'.*\.fixeol$',
1815 1819 default=False,
1816 1820 generic=True,
1817 1821 priority=-1,
1818 1822 )
1819 1823 coreconfigitem(
1820 1824 b'merge-tools',
1821 1825 br'.*\.gui$',
1822 1826 default=False,
1823 1827 generic=True,
1824 1828 priority=-1,
1825 1829 )
1826 1830 coreconfigitem(
1827 1831 b'merge-tools',
1828 1832 br'.*\.mergemarkers$',
1829 1833 default=b'basic',
1830 1834 generic=True,
1831 1835 priority=-1,
1832 1836 )
1833 1837 coreconfigitem(
1834 1838 b'merge-tools',
1835 1839 br'.*\.mergemarkertemplate$',
1836 1840 default=dynamicdefault, # take from command-templates.mergemarker
1837 1841 generic=True,
1838 1842 priority=-1,
1839 1843 )
1840 1844 coreconfigitem(
1841 1845 b'merge-tools',
1842 1846 br'.*\.priority$',
1843 1847 default=0,
1844 1848 generic=True,
1845 1849 priority=-1,
1846 1850 )
1847 1851 coreconfigitem(
1848 1852 b'merge-tools',
1849 1853 br'.*\.premerge$',
1850 1854 default=dynamicdefault,
1851 1855 generic=True,
1852 1856 priority=-1,
1853 1857 )
1854 1858 coreconfigitem(
1855 1859 b'merge-tools',
1856 1860 br'.*\.regappend$',
1857 1861 default=b"",
1858 1862 generic=True,
1859 1863 priority=-1,
1860 1864 )
1861 1865 coreconfigitem(
1862 1866 b'merge-tools',
1863 1867 br'.*\.symlink$',
1864 1868 default=False,
1865 1869 generic=True,
1866 1870 priority=-1,
1867 1871 )
1868 1872 coreconfigitem(
1869 1873 b'pager',
1870 1874 b'attend-.*',
1871 1875 default=dynamicdefault,
1872 1876 generic=True,
1873 1877 )
1874 1878 coreconfigitem(
1875 1879 b'pager',
1876 1880 b'ignore',
1877 1881 default=list,
1878 1882 )
1879 1883 coreconfigitem(
1880 1884 b'pager',
1881 1885 b'pager',
1882 1886 default=dynamicdefault,
1883 1887 )
1884 1888 coreconfigitem(
1885 1889 b'patch',
1886 1890 b'eol',
1887 1891 default=b'strict',
1888 1892 )
1889 1893 coreconfigitem(
1890 1894 b'patch',
1891 1895 b'fuzz',
1892 1896 default=2,
1893 1897 )
1894 1898 coreconfigitem(
1895 1899 b'paths',
1896 1900 b'default',
1897 1901 default=None,
1898 1902 )
1899 1903 coreconfigitem(
1900 1904 b'paths',
1901 1905 b'default-push',
1902 1906 default=None,
1903 1907 )
1904 1908 coreconfigitem(
1905 1909 b'paths',
1906 1910 b'[^:]*',
1907 1911 default=None,
1908 1912 generic=True,
1909 1913 )
1910 1914 coreconfigitem(
1911 1915 b'paths',
1912 1916 b'.*:bookmarks.mode',
1913 1917 default='default',
1914 1918 generic=True,
1915 1919 )
1916 1920 coreconfigitem(
1917 1921 b'paths',
1918 1922 b'.*:multi-urls',
1919 1923 default=False,
1920 1924 generic=True,
1921 1925 )
1922 1926 coreconfigitem(
1923 1927 b'paths',
1924 1928 b'.*:pushrev',
1925 1929 default=None,
1926 1930 generic=True,
1927 1931 )
1928 1932 coreconfigitem(
1929 1933 b'paths',
1930 1934 b'.*:pushurl',
1931 1935 default=None,
1932 1936 generic=True,
1933 1937 )
1934 1938 coreconfigitem(
1935 1939 b'paths',
1936 1940 b'.*:pulled-delta-reuse-policy',
1937 1941 default=None,
1938 1942 generic=True,
1939 1943 )
1940 1944 coreconfigitem(
1941 1945 b'phases',
1942 1946 b'checksubrepos',
1943 1947 default=b'follow',
1944 1948 )
1945 1949 coreconfigitem(
1946 1950 b'phases',
1947 1951 b'new-commit',
1948 1952 default=b'draft',
1949 1953 )
1950 1954 coreconfigitem(
1951 1955 b'phases',
1952 1956 b'publish',
1953 1957 default=True,
1954 1958 )
1955 1959 coreconfigitem(
1956 1960 b'profiling',
1957 1961 b'enabled',
1958 1962 default=False,
1959 1963 )
1960 1964 coreconfigitem(
1961 1965 b'profiling',
1962 1966 b'format',
1963 1967 default=b'text',
1964 1968 )
1965 1969 coreconfigitem(
1966 1970 b'profiling',
1967 1971 b'freq',
1968 1972 default=1000,
1969 1973 )
1970 1974 coreconfigitem(
1971 1975 b'profiling',
1972 1976 b'limit',
1973 1977 default=30,
1974 1978 )
1975 1979 coreconfigitem(
1976 1980 b'profiling',
1977 1981 b'nested',
1978 1982 default=0,
1979 1983 )
1980 1984 coreconfigitem(
1981 1985 b'profiling',
1982 1986 b'output',
1983 1987 default=None,
1984 1988 )
1985 1989 coreconfigitem(
1986 1990 b'profiling',
1987 1991 b'showmax',
1988 1992 default=0.999,
1989 1993 )
1990 1994 coreconfigitem(
1991 1995 b'profiling',
1992 1996 b'showmin',
1993 1997 default=dynamicdefault,
1994 1998 )
1995 1999 coreconfigitem(
1996 2000 b'profiling',
1997 2001 b'showtime',
1998 2002 default=True,
1999 2003 )
2000 2004 coreconfigitem(
2001 2005 b'profiling',
2002 2006 b'sort',
2003 2007 default=b'inlinetime',
2004 2008 )
2005 2009 coreconfigitem(
2006 2010 b'profiling',
2007 2011 b'statformat',
2008 2012 default=b'hotpath',
2009 2013 )
2010 2014 coreconfigitem(
2011 2015 b'profiling',
2012 2016 b'time-track',
2013 2017 default=dynamicdefault,
2014 2018 )
2015 2019 coreconfigitem(
2016 2020 b'profiling',
2017 2021 b'type',
2018 2022 default=b'stat',
2019 2023 )
2020 2024 coreconfigitem(
2021 2025 b'progress',
2022 2026 b'assume-tty',
2023 2027 default=False,
2024 2028 )
2025 2029 coreconfigitem(
2026 2030 b'progress',
2027 2031 b'changedelay',
2028 2032 default=1,
2029 2033 )
2030 2034 coreconfigitem(
2031 2035 b'progress',
2032 2036 b'clear-complete',
2033 2037 default=True,
2034 2038 )
2035 2039 coreconfigitem(
2036 2040 b'progress',
2037 2041 b'debug',
2038 2042 default=False,
2039 2043 )
2040 2044 coreconfigitem(
2041 2045 b'progress',
2042 2046 b'delay',
2043 2047 default=3,
2044 2048 )
2045 2049 coreconfigitem(
2046 2050 b'progress',
2047 2051 b'disable',
2048 2052 default=False,
2049 2053 )
2050 2054 coreconfigitem(
2051 2055 b'progress',
2052 2056 b'estimateinterval',
2053 2057 default=60.0,
2054 2058 )
2055 2059 coreconfigitem(
2056 2060 b'progress',
2057 2061 b'format',
2058 2062 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
2059 2063 )
2060 2064 coreconfigitem(
2061 2065 b'progress',
2062 2066 b'refresh',
2063 2067 default=0.1,
2064 2068 )
2065 2069 coreconfigitem(
2066 2070 b'progress',
2067 2071 b'width',
2068 2072 default=dynamicdefault,
2069 2073 )
2070 2074 coreconfigitem(
2071 2075 b'pull',
2072 2076 b'confirm',
2073 2077 default=False,
2074 2078 )
2075 2079 coreconfigitem(
2076 2080 b'push',
2077 2081 b'pushvars.server',
2078 2082 default=False,
2079 2083 )
2080 2084 coreconfigitem(
2081 2085 b'rewrite',
2082 2086 b'backup-bundle',
2083 2087 default=True,
2084 2088 alias=[(b'ui', b'history-editing-backup')],
2085 2089 )
2086 2090 coreconfigitem(
2087 2091 b'rewrite',
2088 2092 b'update-timestamp',
2089 2093 default=False,
2090 2094 )
2091 2095 coreconfigitem(
2092 2096 b'rewrite',
2093 2097 b'empty-successor',
2094 2098 default=b'skip',
2095 2099 experimental=True,
2096 2100 )
2097 2101 # experimental as long as format.use-dirstate-v2 is.
2098 2102 coreconfigitem(
2099 2103 b'storage',
2100 2104 b'dirstate-v2.slow-path',
2101 2105 default=b"abort",
2102 2106 experimental=True,
2103 2107 )
2104 2108 coreconfigitem(
2105 2109 b'storage',
2106 2110 b'new-repo-backend',
2107 2111 default=b'revlogv1',
2108 2112 experimental=True,
2109 2113 )
2110 2114 coreconfigitem(
2111 2115 b'storage',
2112 2116 b'revlog.optimize-delta-parent-choice',
2113 2117 default=True,
2114 2118 alias=[(b'format', b'aggressivemergedeltas')],
2115 2119 )
2116 2120 coreconfigitem(
2117 2121 b'storage',
2118 2122 b'revlog.delta-parent-search.candidate-group-chunk-size',
2119 2123 default=20,
2120 2124 )
2121 2125 coreconfigitem(
2122 2126 b'storage',
2123 2127 b'revlog.issue6528.fix-incoming',
2124 2128 default=True,
2125 2129 )
2126 2130 # experimental as long as rust is experimental (or a C version is implemented)
2127 2131 coreconfigitem(
2128 2132 b'storage',
2129 2133 b'revlog.persistent-nodemap.mmap',
2130 2134 default=True,
2131 2135 )
2132 2136 # experimental as long as format.use-persistent-nodemap is.
2133 2137 coreconfigitem(
2134 2138 b'storage',
2135 2139 b'revlog.persistent-nodemap.slow-path',
2136 2140 default=b"abort",
2137 2141 )
2138 2142
2139 2143 coreconfigitem(
2140 2144 b'storage',
2141 2145 b'revlog.reuse-external-delta',
2142 2146 default=True,
2143 2147 )
2144 2148 # This option is True unless `format.generaldelta` is set.
2145 2149 coreconfigitem(
2146 2150 b'storage',
2147 2151 b'revlog.reuse-external-delta-parent',
2148 2152 default=None,
2149 2153 )
2150 2154 coreconfigitem(
2151 2155 b'storage',
2152 2156 b'revlog.zlib.level',
2153 2157 default=None,
2154 2158 )
2155 2159 coreconfigitem(
2156 2160 b'storage',
2157 2161 b'revlog.zstd.level',
2158 2162 default=None,
2159 2163 )
2160 2164 coreconfigitem(
2161 2165 b'server',
2162 2166 b'bookmarks-pushkey-compat',
2163 2167 default=True,
2164 2168 )
2165 2169 coreconfigitem(
2166 2170 b'server',
2167 2171 b'bundle1',
2168 2172 default=True,
2169 2173 )
2170 2174 coreconfigitem(
2171 2175 b'server',
2172 2176 b'bundle1gd',
2173 2177 default=None,
2174 2178 )
2175 2179 coreconfigitem(
2176 2180 b'server',
2177 2181 b'bundle1.pull',
2178 2182 default=None,
2179 2183 )
2180 2184 coreconfigitem(
2181 2185 b'server',
2182 2186 b'bundle1gd.pull',
2183 2187 default=None,
2184 2188 )
2185 2189 coreconfigitem(
2186 2190 b'server',
2187 2191 b'bundle1.push',
2188 2192 default=None,
2189 2193 )
2190 2194 coreconfigitem(
2191 2195 b'server',
2192 2196 b'bundle1gd.push',
2193 2197 default=None,
2194 2198 )
2195 2199 coreconfigitem(
2196 2200 b'server',
2197 2201 b'bundle2.stream',
2198 2202 default=True,
2199 2203 alias=[(b'experimental', b'bundle2.stream')],
2200 2204 )
2201 2205 coreconfigitem(
2202 2206 b'server',
2203 2207 b'compressionengines',
2204 2208 default=list,
2205 2209 )
2206 2210 coreconfigitem(
2207 2211 b'server',
2208 2212 b'concurrent-push-mode',
2209 2213 default=b'check-related',
2210 2214 )
2211 2215 coreconfigitem(
2212 2216 b'server',
2213 2217 b'disablefullbundle',
2214 2218 default=False,
2215 2219 )
2216 2220 coreconfigitem(
2217 2221 b'server',
2218 2222 b'maxhttpheaderlen',
2219 2223 default=1024,
2220 2224 )
2221 2225 coreconfigitem(
2222 2226 b'server',
2223 2227 b'pullbundle',
2224 2228 default=True,
2225 2229 )
2226 2230 coreconfigitem(
2227 2231 b'server',
2228 2232 b'preferuncompressed',
2229 2233 default=False,
2230 2234 )
2231 2235 coreconfigitem(
2232 2236 b'server',
2233 2237 b'streamunbundle',
2234 2238 default=False,
2235 2239 )
2236 2240 coreconfigitem(
2237 2241 b'server',
2238 2242 b'uncompressed',
2239 2243 default=True,
2240 2244 )
2241 2245 coreconfigitem(
2242 2246 b'server',
2243 2247 b'uncompressedallowsecret',
2244 2248 default=False,
2245 2249 )
2246 2250 coreconfigitem(
2247 2251 b'server',
2248 2252 b'view',
2249 2253 default=b'served',
2250 2254 )
2251 2255 coreconfigitem(
2252 2256 b'server',
2253 2257 b'validate',
2254 2258 default=False,
2255 2259 )
2256 2260 coreconfigitem(
2257 2261 b'server',
2258 2262 b'zliblevel',
2259 2263 default=-1,
2260 2264 )
2261 2265 coreconfigitem(
2262 2266 b'server',
2263 2267 b'zstdlevel',
2264 2268 default=3,
2265 2269 )
2266 2270 coreconfigitem(
2267 2271 b'share',
2268 2272 b'pool',
2269 2273 default=None,
2270 2274 )
2271 2275 coreconfigitem(
2272 2276 b'share',
2273 2277 b'poolnaming',
2274 2278 default=b'identity',
2275 2279 )
2276 2280 coreconfigitem(
2277 2281 b'share',
2278 2282 b'safe-mismatch.source-not-safe',
2279 2283 default=b'abort',
2280 2284 )
2281 2285 coreconfigitem(
2282 2286 b'share',
2283 2287 b'safe-mismatch.source-safe',
2284 2288 default=b'abort',
2285 2289 )
2286 2290 coreconfigitem(
2287 2291 b'share',
2288 2292 b'safe-mismatch.source-not-safe.warn',
2289 2293 default=True,
2290 2294 )
2291 2295 coreconfigitem(
2292 2296 b'share',
2293 2297 b'safe-mismatch.source-safe.warn',
2294 2298 default=True,
2295 2299 )
2296 2300 coreconfigitem(
2297 2301 b'share',
2298 2302 b'safe-mismatch.source-not-safe:verbose-upgrade',
2299 2303 default=True,
2300 2304 )
2301 2305 coreconfigitem(
2302 2306 b'share',
2303 2307 b'safe-mismatch.source-safe:verbose-upgrade',
2304 2308 default=True,
2305 2309 )
2306 2310 coreconfigitem(
2307 2311 b'shelve',
2308 2312 b'maxbackups',
2309 2313 default=10,
2310 2314 )
2311 2315 coreconfigitem(
2312 2316 b'smtp',
2313 2317 b'host',
2314 2318 default=None,
2315 2319 )
2316 2320 coreconfigitem(
2317 2321 b'smtp',
2318 2322 b'local_hostname',
2319 2323 default=None,
2320 2324 )
2321 2325 coreconfigitem(
2322 2326 b'smtp',
2323 2327 b'password',
2324 2328 default=None,
2325 2329 )
2326 2330 coreconfigitem(
2327 2331 b'smtp',
2328 2332 b'port',
2329 2333 default=dynamicdefault,
2330 2334 )
2331 2335 coreconfigitem(
2332 2336 b'smtp',
2333 2337 b'tls',
2334 2338 default=b'none',
2335 2339 )
2336 2340 coreconfigitem(
2337 2341 b'smtp',
2338 2342 b'username',
2339 2343 default=None,
2340 2344 )
2341 2345 coreconfigitem(
2342 2346 b'sparse',
2343 2347 b'missingwarning',
2344 2348 default=True,
2345 2349 experimental=True,
2346 2350 )
2347 2351 coreconfigitem(
2348 2352 b'subrepos',
2349 2353 b'allowed',
2350 2354 default=dynamicdefault, # to make backporting simpler
2351 2355 )
2352 2356 coreconfigitem(
2353 2357 b'subrepos',
2354 2358 b'hg:allowed',
2355 2359 default=dynamicdefault,
2356 2360 )
2357 2361 coreconfigitem(
2358 2362 b'subrepos',
2359 2363 b'git:allowed',
2360 2364 default=dynamicdefault,
2361 2365 )
2362 2366 coreconfigitem(
2363 2367 b'subrepos',
2364 2368 b'svn:allowed',
2365 2369 default=dynamicdefault,
2366 2370 )
2367 2371 coreconfigitem(
2368 2372 b'templates',
2369 2373 b'.*',
2370 2374 default=None,
2371 2375 generic=True,
2372 2376 )
2373 2377 coreconfigitem(
2374 2378 b'templateconfig',
2375 2379 b'.*',
2376 2380 default=dynamicdefault,
2377 2381 generic=True,
2378 2382 )
2379 2383 coreconfigitem(
2380 2384 b'trusted',
2381 2385 b'groups',
2382 2386 default=list,
2383 2387 )
2384 2388 coreconfigitem(
2385 2389 b'trusted',
2386 2390 b'users',
2387 2391 default=list,
2388 2392 )
2389 2393 coreconfigitem(
2390 2394 b'ui',
2391 2395 b'_usedassubrepo',
2392 2396 default=False,
2393 2397 )
2394 2398 coreconfigitem(
2395 2399 b'ui',
2396 2400 b'allowemptycommit',
2397 2401 default=False,
2398 2402 )
2399 2403 coreconfigitem(
2400 2404 b'ui',
2401 2405 b'archivemeta',
2402 2406 default=True,
2403 2407 )
2404 2408 coreconfigitem(
2405 2409 b'ui',
2406 2410 b'askusername',
2407 2411 default=False,
2408 2412 )
2409 2413 coreconfigitem(
2410 2414 b'ui',
2411 2415 b'available-memory',
2412 2416 default=None,
2413 2417 )
2414 2418
2415 2419 coreconfigitem(
2416 2420 b'ui',
2417 2421 b'clonebundlefallback',
2418 2422 default=False,
2419 2423 )
2420 2424 coreconfigitem(
2421 2425 b'ui',
2422 2426 b'clonebundleprefers',
2423 2427 default=list,
2424 2428 )
2425 2429 coreconfigitem(
2426 2430 b'ui',
2427 2431 b'clonebundles',
2428 2432 default=True,
2429 2433 )
2430 2434 coreconfigitem(
2431 2435 b'ui',
2432 2436 b'color',
2433 2437 default=b'auto',
2434 2438 )
2435 2439 coreconfigitem(
2436 2440 b'ui',
2437 2441 b'commitsubrepos',
2438 2442 default=False,
2439 2443 )
2440 2444 coreconfigitem(
2441 2445 b'ui',
2442 2446 b'debug',
2443 2447 default=False,
2444 2448 )
2445 2449 coreconfigitem(
2446 2450 b'ui',
2447 2451 b'debugger',
2448 2452 default=None,
2449 2453 )
2450 2454 coreconfigitem(
2451 2455 b'ui',
2452 2456 b'editor',
2453 2457 default=dynamicdefault,
2454 2458 )
2455 2459 coreconfigitem(
2456 2460 b'ui',
2457 2461 b'detailed-exit-code',
2458 2462 default=False,
2459 2463 experimental=True,
2460 2464 )
2461 2465 coreconfigitem(
2462 2466 b'ui',
2463 2467 b'fallbackencoding',
2464 2468 default=None,
2465 2469 )
2466 2470 coreconfigitem(
2467 2471 b'ui',
2468 2472 b'forcecwd',
2469 2473 default=None,
2470 2474 )
2471 2475 coreconfigitem(
2472 2476 b'ui',
2473 2477 b'forcemerge',
2474 2478 default=None,
2475 2479 )
2476 2480 coreconfigitem(
2477 2481 b'ui',
2478 2482 b'formatdebug',
2479 2483 default=False,
2480 2484 )
2481 2485 coreconfigitem(
2482 2486 b'ui',
2483 2487 b'formatjson',
2484 2488 default=False,
2485 2489 )
2486 2490 coreconfigitem(
2487 2491 b'ui',
2488 2492 b'formatted',
2489 2493 default=None,
2490 2494 )
2491 2495 coreconfigitem(
2492 2496 b'ui',
2493 2497 b'interactive',
2494 2498 default=None,
2495 2499 )
2496 2500 coreconfigitem(
2497 2501 b'ui',
2498 2502 b'interface',
2499 2503 default=None,
2500 2504 )
2501 2505 coreconfigitem(
2502 2506 b'ui',
2503 2507 b'interface.chunkselector',
2504 2508 default=None,
2505 2509 )
2506 2510 coreconfigitem(
2507 2511 b'ui',
2508 2512 b'large-file-limit',
2509 2513 default=10 * (2 ** 20),
2510 2514 )
2511 2515 coreconfigitem(
2512 2516 b'ui',
2513 2517 b'logblockedtimes',
2514 2518 default=False,
2515 2519 )
2516 2520 coreconfigitem(
2517 2521 b'ui',
2518 2522 b'merge',
2519 2523 default=None,
2520 2524 )
2521 2525 coreconfigitem(
2522 2526 b'ui',
2523 2527 b'mergemarkers',
2524 2528 default=b'basic',
2525 2529 )
2526 2530 coreconfigitem(
2527 2531 b'ui',
2528 2532 b'message-output',
2529 2533 default=b'stdio',
2530 2534 )
2531 2535 coreconfigitem(
2532 2536 b'ui',
2533 2537 b'nontty',
2534 2538 default=False,
2535 2539 )
2536 2540 coreconfigitem(
2537 2541 b'ui',
2538 2542 b'origbackuppath',
2539 2543 default=None,
2540 2544 )
2541 2545 coreconfigitem(
2542 2546 b'ui',
2543 2547 b'paginate',
2544 2548 default=True,
2545 2549 )
2546 2550 coreconfigitem(
2547 2551 b'ui',
2548 2552 b'patch',
2549 2553 default=None,
2550 2554 )
2551 2555 coreconfigitem(
2552 2556 b'ui',
2553 2557 b'portablefilenames',
2554 2558 default=b'warn',
2555 2559 )
2556 2560 coreconfigitem(
2557 2561 b'ui',
2558 2562 b'promptecho',
2559 2563 default=False,
2560 2564 )
2561 2565 coreconfigitem(
2562 2566 b'ui',
2563 2567 b'quiet',
2564 2568 default=False,
2565 2569 )
2566 2570 coreconfigitem(
2567 2571 b'ui',
2568 2572 b'quietbookmarkmove',
2569 2573 default=False,
2570 2574 )
2571 2575 coreconfigitem(
2572 2576 b'ui',
2573 2577 b'relative-paths',
2574 2578 default=b'legacy',
2575 2579 )
2576 2580 coreconfigitem(
2577 2581 b'ui',
2578 2582 b'remotecmd',
2579 2583 default=b'hg',
2580 2584 )
2581 2585 coreconfigitem(
2582 2586 b'ui',
2583 2587 b'report_untrusted',
2584 2588 default=True,
2585 2589 )
2586 2590 coreconfigitem(
2587 2591 b'ui',
2588 2592 b'rollback',
2589 2593 default=True,
2590 2594 )
2591 2595 coreconfigitem(
2592 2596 b'ui',
2593 2597 b'signal-safe-lock',
2594 2598 default=True,
2595 2599 )
2596 2600 coreconfigitem(
2597 2601 b'ui',
2598 2602 b'slash',
2599 2603 default=False,
2600 2604 )
2601 2605 coreconfigitem(
2602 2606 b'ui',
2603 2607 b'ssh',
2604 2608 default=b'ssh',
2605 2609 )
2606 2610 coreconfigitem(
2607 2611 b'ui',
2608 2612 b'ssherrorhint',
2609 2613 default=None,
2610 2614 )
2611 2615 coreconfigitem(
2612 2616 b'ui',
2613 2617 b'statuscopies',
2614 2618 default=False,
2615 2619 )
2616 2620 coreconfigitem(
2617 2621 b'ui',
2618 2622 b'strict',
2619 2623 default=False,
2620 2624 )
2621 2625 coreconfigitem(
2622 2626 b'ui',
2623 2627 b'style',
2624 2628 default=b'',
2625 2629 )
2626 2630 coreconfigitem(
2627 2631 b'ui',
2628 2632 b'supportcontact',
2629 2633 default=None,
2630 2634 )
2631 2635 coreconfigitem(
2632 2636 b'ui',
2633 2637 b'textwidth',
2634 2638 default=78,
2635 2639 )
2636 2640 coreconfigitem(
2637 2641 b'ui',
2638 2642 b'timeout',
2639 2643 default=b'600',
2640 2644 )
2641 2645 coreconfigitem(
2642 2646 b'ui',
2643 2647 b'timeout.warn',
2644 2648 default=0,
2645 2649 )
2646 2650 coreconfigitem(
2647 2651 b'ui',
2648 2652 b'timestamp-output',
2649 2653 default=False,
2650 2654 )
2651 2655 coreconfigitem(
2652 2656 b'ui',
2653 2657 b'traceback',
2654 2658 default=False,
2655 2659 )
2656 2660 coreconfigitem(
2657 2661 b'ui',
2658 2662 b'tweakdefaults',
2659 2663 default=False,
2660 2664 )
2661 2665 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2662 2666 coreconfigitem(
2663 2667 b'ui',
2664 2668 b'verbose',
2665 2669 default=False,
2666 2670 )
2667 2671 coreconfigitem(
2668 2672 b'verify',
2669 2673 b'skipflags',
2670 2674 default=0,
2671 2675 )
2672 2676 coreconfigitem(
2673 2677 b'web',
2674 2678 b'allowbz2',
2675 2679 default=False,
2676 2680 )
2677 2681 coreconfigitem(
2678 2682 b'web',
2679 2683 b'allowgz',
2680 2684 default=False,
2681 2685 )
2682 2686 coreconfigitem(
2683 2687 b'web',
2684 2688 b'allow-pull',
2685 2689 alias=[(b'web', b'allowpull')],
2686 2690 default=True,
2687 2691 )
2688 2692 coreconfigitem(
2689 2693 b'web',
2690 2694 b'allow-push',
2691 2695 alias=[(b'web', b'allow_push')],
2692 2696 default=list,
2693 2697 )
2694 2698 coreconfigitem(
2695 2699 b'web',
2696 2700 b'allowzip',
2697 2701 default=False,
2698 2702 )
2699 2703 coreconfigitem(
2700 2704 b'web',
2701 2705 b'archivesubrepos',
2702 2706 default=False,
2703 2707 )
2704 2708 coreconfigitem(
2705 2709 b'web',
2706 2710 b'cache',
2707 2711 default=True,
2708 2712 )
2709 2713 coreconfigitem(
2710 2714 b'web',
2711 2715 b'comparisoncontext',
2712 2716 default=5,
2713 2717 )
2714 2718 coreconfigitem(
2715 2719 b'web',
2716 2720 b'contact',
2717 2721 default=None,
2718 2722 )
2719 2723 coreconfigitem(
2720 2724 b'web',
2721 2725 b'deny_push',
2722 2726 default=list,
2723 2727 )
2724 2728 coreconfigitem(
2725 2729 b'web',
2726 2730 b'guessmime',
2727 2731 default=False,
2728 2732 )
2729 2733 coreconfigitem(
2730 2734 b'web',
2731 2735 b'hidden',
2732 2736 default=False,
2733 2737 )
2734 2738 coreconfigitem(
2735 2739 b'web',
2736 2740 b'labels',
2737 2741 default=list,
2738 2742 )
2739 2743 coreconfigitem(
2740 2744 b'web',
2741 2745 b'logoimg',
2742 2746 default=b'hglogo.png',
2743 2747 )
2744 2748 coreconfigitem(
2745 2749 b'web',
2746 2750 b'logourl',
2747 2751 default=b'https://mercurial-scm.org/',
2748 2752 )
2749 2753 coreconfigitem(
2750 2754 b'web',
2751 2755 b'accesslog',
2752 2756 default=b'-',
2753 2757 )
2754 2758 coreconfigitem(
2755 2759 b'web',
2756 2760 b'address',
2757 2761 default=b'',
2758 2762 )
2759 2763 coreconfigitem(
2760 2764 b'web',
2761 2765 b'allow-archive',
2762 2766 alias=[(b'web', b'allow_archive')],
2763 2767 default=list,
2764 2768 )
2765 2769 coreconfigitem(
2766 2770 b'web',
2767 2771 b'allow_read',
2768 2772 default=list,
2769 2773 )
2770 2774 coreconfigitem(
2771 2775 b'web',
2772 2776 b'baseurl',
2773 2777 default=None,
2774 2778 )
2775 2779 coreconfigitem(
2776 2780 b'web',
2777 2781 b'cacerts',
2778 2782 default=None,
2779 2783 )
2780 2784 coreconfigitem(
2781 2785 b'web',
2782 2786 b'certificate',
2783 2787 default=None,
2784 2788 )
2785 2789 coreconfigitem(
2786 2790 b'web',
2787 2791 b'collapse',
2788 2792 default=False,
2789 2793 )
2790 2794 coreconfigitem(
2791 2795 b'web',
2792 2796 b'csp',
2793 2797 default=None,
2794 2798 )
2795 2799 coreconfigitem(
2796 2800 b'web',
2797 2801 b'deny_read',
2798 2802 default=list,
2799 2803 )
2800 2804 coreconfigitem(
2801 2805 b'web',
2802 2806 b'descend',
2803 2807 default=True,
2804 2808 )
2805 2809 coreconfigitem(
2806 2810 b'web',
2807 2811 b'description',
2808 2812 default=b"",
2809 2813 )
2810 2814 coreconfigitem(
2811 2815 b'web',
2812 2816 b'encoding',
2813 2817 default=lambda: encoding.encoding,
2814 2818 )
2815 2819 coreconfigitem(
2816 2820 b'web',
2817 2821 b'errorlog',
2818 2822 default=b'-',
2819 2823 )
2820 2824 coreconfigitem(
2821 2825 b'web',
2822 2826 b'ipv6',
2823 2827 default=False,
2824 2828 )
2825 2829 coreconfigitem(
2826 2830 b'web',
2827 2831 b'maxchanges',
2828 2832 default=10,
2829 2833 )
2830 2834 coreconfigitem(
2831 2835 b'web',
2832 2836 b'maxfiles',
2833 2837 default=10,
2834 2838 )
2835 2839 coreconfigitem(
2836 2840 b'web',
2837 2841 b'maxshortchanges',
2838 2842 default=60,
2839 2843 )
2840 2844 coreconfigitem(
2841 2845 b'web',
2842 2846 b'motd',
2843 2847 default=b'',
2844 2848 )
2845 2849 coreconfigitem(
2846 2850 b'web',
2847 2851 b'name',
2848 2852 default=dynamicdefault,
2849 2853 )
2850 2854 coreconfigitem(
2851 2855 b'web',
2852 2856 b'port',
2853 2857 default=8000,
2854 2858 )
2855 2859 coreconfigitem(
2856 2860 b'web',
2857 2861 b'prefix',
2858 2862 default=b'',
2859 2863 )
2860 2864 coreconfigitem(
2861 2865 b'web',
2862 2866 b'push_ssl',
2863 2867 default=True,
2864 2868 )
2865 2869 coreconfigitem(
2866 2870 b'web',
2867 2871 b'refreshinterval',
2868 2872 default=20,
2869 2873 )
2870 2874 coreconfigitem(
2871 2875 b'web',
2872 2876 b'server-header',
2873 2877 default=None,
2874 2878 )
2875 2879 coreconfigitem(
2876 2880 b'web',
2877 2881 b'static',
2878 2882 default=None,
2879 2883 )
2880 2884 coreconfigitem(
2881 2885 b'web',
2882 2886 b'staticurl',
2883 2887 default=None,
2884 2888 )
2885 2889 coreconfigitem(
2886 2890 b'web',
2887 2891 b'stripes',
2888 2892 default=1,
2889 2893 )
2890 2894 coreconfigitem(
2891 2895 b'web',
2892 2896 b'style',
2893 2897 default=b'paper',
2894 2898 )
2895 2899 coreconfigitem(
2896 2900 b'web',
2897 2901 b'templates',
2898 2902 default=None,
2899 2903 )
2900 2904 coreconfigitem(
2901 2905 b'web',
2902 2906 b'view',
2903 2907 default=b'served',
2904 2908 experimental=True,
2905 2909 )
2906 2910 coreconfigitem(
2907 2911 b'worker',
2908 2912 b'backgroundclose',
2909 2913 default=dynamicdefault,
2910 2914 )
2911 2915 # Windows defaults to a limit of 512 open files. A buffer of 128
2912 2916 # should give us enough headway.
2913 2917 coreconfigitem(
2914 2918 b'worker',
2915 2919 b'backgroundclosemaxqueue',
2916 2920 default=384,
2917 2921 )
2918 2922 coreconfigitem(
2919 2923 b'worker',
2920 2924 b'backgroundcloseminfilecount',
2921 2925 default=2048,
2922 2926 )
2923 2927 coreconfigitem(
2924 2928 b'worker',
2925 2929 b'backgroundclosethreadcount',
2926 2930 default=4,
2927 2931 )
2928 2932 coreconfigitem(
2929 2933 b'worker',
2930 2934 b'enabled',
2931 2935 default=True,
2932 2936 )
2933 2937 coreconfigitem(
2934 2938 b'worker',
2935 2939 b'numcpus',
2936 2940 default=None,
2937 2941 )
2938 2942
2939 2943 # Rebase related configuration moved to core because other extension are doing
2940 2944 # strange things. For example, shelve import the extensions to reuse some bit
2941 2945 # without formally loading it.
2942 2946 coreconfigitem(
2943 2947 b'commands',
2944 2948 b'rebase.requiredest',
2945 2949 default=False,
2946 2950 )
2947 2951 coreconfigitem(
2948 2952 b'experimental',
2949 2953 b'rebaseskipobsolete',
2950 2954 default=True,
2951 2955 )
2952 2956 coreconfigitem(
2953 2957 b'rebase',
2954 2958 b'singletransaction',
2955 2959 default=False,
2956 2960 )
2957 2961 coreconfigitem(
2958 2962 b'rebase',
2959 2963 b'experimental.inmemory',
2960 2964 default=False,
2961 2965 )
2962 2966
2963 2967 # This setting controls creation of a rebase_source extra field
2964 2968 # during rebase. When False, no such field is created. This is
2965 2969 # useful eg for incrementally converting changesets and then
2966 2970 # rebasing them onto an existing repo.
2967 2971 # WARNING: this is an advanced setting reserved for people who know
2968 2972 # exactly what they are doing. Misuse of this setting can easily
2969 2973 # result in obsmarker cycles and a vivid headache.
2970 2974 coreconfigitem(
2971 2975 b'rebase',
2972 2976 b'store-source',
2973 2977 default=True,
2974 2978 experimental=True,
2975 2979 )
@@ -1,1511 +1,1530 b''
1 1 # revlogdeltas.py - Logic around delta computation for revlog
2 2 #
3 3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 4 # Copyright 2018 Octobus <contact@octobus.net>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8 """Helper class to compute deltas stored inside revlogs"""
9 9
10 10
11 11 import collections
12 12 import struct
13 13
14 14 # import stuff from node for others to import from revlog
15 15 from ..node import nullrev
16 16 from ..i18n import _
17 17 from ..pycompat import getattr
18 18
19 19 from .constants import (
20 20 COMP_MODE_DEFAULT,
21 21 COMP_MODE_INLINE,
22 22 COMP_MODE_PLAIN,
23 23 DELTA_BASE_REUSE_FORCE,
24 24 DELTA_BASE_REUSE_NO,
25 25 KIND_CHANGELOG,
26 26 KIND_FILELOG,
27 27 KIND_MANIFESTLOG,
28 28 REVIDX_ISCENSORED,
29 29 REVIDX_RAWTEXT_CHANGING_FLAGS,
30 30 )
31 31
32 32 from ..thirdparty import attr
33 33
34 34 from .. import (
35 35 error,
36 36 mdiff,
37 37 util,
38 38 )
39 39
40 40 from . import flagutil
41 41
42 42 # maximum <delta-chain-data>/<revision-text-length> ratio
43 43 LIMIT_DELTA2TEXT = 2
44 44
45 45
46 46 class _testrevlog:
47 47 """minimalist fake revlog to use in doctests"""
48 48
49 49 def __init__(self, data, density=0.5, mingap=0, snapshot=()):
50 50 """data is an list of revision payload boundaries"""
51 51 self._data = data
52 52 self._srdensitythreshold = density
53 53 self._srmingapsize = mingap
54 54 self._snapshot = set(snapshot)
55 55 self.index = None
56 56
57 57 def start(self, rev):
58 58 if rev == nullrev:
59 59 return 0
60 60 if rev == 0:
61 61 return 0
62 62 return self._data[rev - 1]
63 63
64 64 def end(self, rev):
65 65 if rev == nullrev:
66 66 return 0
67 67 return self._data[rev]
68 68
69 69 def length(self, rev):
70 70 return self.end(rev) - self.start(rev)
71 71
72 72 def __len__(self):
73 73 return len(self._data)
74 74
75 75 def issnapshot(self, rev):
76 76 if rev == nullrev:
77 77 return True
78 78 return rev in self._snapshot
79 79
80 80
81 81 def slicechunk(revlog, revs, targetsize=None):
82 82 """slice revs to reduce the amount of unrelated data to be read from disk.
83 83
84 84 ``revs`` is sliced into groups that should be read in one time.
85 85 Assume that revs are sorted.
86 86
87 87 The initial chunk is sliced until the overall density (payload/chunks-span
88 88 ratio) is above `revlog._srdensitythreshold`. No gap smaller than
89 89 `revlog._srmingapsize` is skipped.
90 90
91 91 If `targetsize` is set, no chunk larger than `targetsize` will be yield.
92 92 For consistency with other slicing choice, this limit won't go lower than
93 93 `revlog._srmingapsize`.
94 94
95 95 If individual revisions chunk are larger than this limit, they will still
96 96 be raised individually.
97 97
98 98 >>> data = [
99 99 ... 5, #00 (5)
100 100 ... 10, #01 (5)
101 101 ... 12, #02 (2)
102 102 ... 12, #03 (empty)
103 103 ... 27, #04 (15)
104 104 ... 31, #05 (4)
105 105 ... 31, #06 (empty)
106 106 ... 42, #07 (11)
107 107 ... 47, #08 (5)
108 108 ... 47, #09 (empty)
109 109 ... 48, #10 (1)
110 110 ... 51, #11 (3)
111 111 ... 74, #12 (23)
112 112 ... 85, #13 (11)
113 113 ... 86, #14 (1)
114 114 ... 91, #15 (5)
115 115 ... ]
116 116 >>> revlog = _testrevlog(data, snapshot=range(16))
117 117
118 118 >>> list(slicechunk(revlog, list(range(16))))
119 119 [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
120 120 >>> list(slicechunk(revlog, [0, 15]))
121 121 [[0], [15]]
122 122 >>> list(slicechunk(revlog, [0, 11, 15]))
123 123 [[0], [11], [15]]
124 124 >>> list(slicechunk(revlog, [0, 11, 13, 15]))
125 125 [[0], [11, 13, 15]]
126 126 >>> list(slicechunk(revlog, [1, 2, 3, 5, 8, 10, 11, 14]))
127 127 [[1, 2], [5, 8, 10, 11], [14]]
128 128
129 129 Slicing with a maximum chunk size
130 130 >>> list(slicechunk(revlog, [0, 11, 13, 15], targetsize=15))
131 131 [[0], [11], [13], [15]]
132 132 >>> list(slicechunk(revlog, [0, 11, 13, 15], targetsize=20))
133 133 [[0], [11], [13, 15]]
134 134
135 135 Slicing involving nullrev
136 136 >>> list(slicechunk(revlog, [-1, 0, 11, 13, 15], targetsize=20))
137 137 [[-1, 0], [11], [13, 15]]
138 138 >>> list(slicechunk(revlog, [-1, 13, 15], targetsize=5))
139 139 [[-1], [13], [15]]
140 140 """
141 141 if targetsize is not None:
142 142 targetsize = max(targetsize, revlog._srmingapsize)
143 143 # targetsize should not be specified when evaluating delta candidates:
144 144 # * targetsize is used to ensure we stay within specification when reading,
145 145 densityslicing = getattr(revlog.index, 'slicechunktodensity', None)
146 146 if densityslicing is None:
147 147 densityslicing = lambda x, y, z: _slicechunktodensity(revlog, x, y, z)
148 148 for chunk in densityslicing(
149 149 revs, revlog._srdensitythreshold, revlog._srmingapsize
150 150 ):
151 151 for subchunk in _slicechunktosize(revlog, chunk, targetsize):
152 152 yield subchunk
153 153
154 154
155 155 def _slicechunktosize(revlog, revs, targetsize=None):
156 156 """slice revs to match the target size
157 157
158 158 This is intended to be used on chunk that density slicing selected by that
159 159 are still too large compared to the read garantee of revlog. This might
160 160 happens when "minimal gap size" interrupted the slicing or when chain are
161 161 built in a way that create large blocks next to each other.
162 162
163 163 >>> data = [
164 164 ... 3, #0 (3)
165 165 ... 5, #1 (2)
166 166 ... 6, #2 (1)
167 167 ... 8, #3 (2)
168 168 ... 8, #4 (empty)
169 169 ... 11, #5 (3)
170 170 ... 12, #6 (1)
171 171 ... 13, #7 (1)
172 172 ... 14, #8 (1)
173 173 ... ]
174 174
175 175 == All snapshots cases ==
176 176 >>> revlog = _testrevlog(data, snapshot=range(9))
177 177
178 178 Cases where chunk is already small enough
179 179 >>> list(_slicechunktosize(revlog, [0], 3))
180 180 [[0]]
181 181 >>> list(_slicechunktosize(revlog, [6, 7], 3))
182 182 [[6, 7]]
183 183 >>> list(_slicechunktosize(revlog, [0], None))
184 184 [[0]]
185 185 >>> list(_slicechunktosize(revlog, [6, 7], None))
186 186 [[6, 7]]
187 187
188 188 cases where we need actual slicing
189 189 >>> list(_slicechunktosize(revlog, [0, 1], 3))
190 190 [[0], [1]]
191 191 >>> list(_slicechunktosize(revlog, [1, 3], 3))
192 192 [[1], [3]]
193 193 >>> list(_slicechunktosize(revlog, [1, 2, 3], 3))
194 194 [[1, 2], [3]]
195 195 >>> list(_slicechunktosize(revlog, [3, 5], 3))
196 196 [[3], [5]]
197 197 >>> list(_slicechunktosize(revlog, [3, 4, 5], 3))
198 198 [[3], [5]]
199 199 >>> list(_slicechunktosize(revlog, [5, 6, 7, 8], 3))
200 200 [[5], [6, 7, 8]]
201 201 >>> list(_slicechunktosize(revlog, [0, 1, 2, 3, 4, 5, 6, 7, 8], 3))
202 202 [[0], [1, 2], [3], [5], [6, 7, 8]]
203 203
204 204 Case with too large individual chunk (must return valid chunk)
205 205 >>> list(_slicechunktosize(revlog, [0, 1], 2))
206 206 [[0], [1]]
207 207 >>> list(_slicechunktosize(revlog, [1, 3], 1))
208 208 [[1], [3]]
209 209 >>> list(_slicechunktosize(revlog, [3, 4, 5], 2))
210 210 [[3], [5]]
211 211
212 212 == No Snapshot cases ==
213 213 >>> revlog = _testrevlog(data)
214 214
215 215 Cases where chunk is already small enough
216 216 >>> list(_slicechunktosize(revlog, [0], 3))
217 217 [[0]]
218 218 >>> list(_slicechunktosize(revlog, [6, 7], 3))
219 219 [[6, 7]]
220 220 >>> list(_slicechunktosize(revlog, [0], None))
221 221 [[0]]
222 222 >>> list(_slicechunktosize(revlog, [6, 7], None))
223 223 [[6, 7]]
224 224
225 225 cases where we need actual slicing
226 226 >>> list(_slicechunktosize(revlog, [0, 1], 3))
227 227 [[0], [1]]
228 228 >>> list(_slicechunktosize(revlog, [1, 3], 3))
229 229 [[1], [3]]
230 230 >>> list(_slicechunktosize(revlog, [1, 2, 3], 3))
231 231 [[1], [2, 3]]
232 232 >>> list(_slicechunktosize(revlog, [3, 5], 3))
233 233 [[3], [5]]
234 234 >>> list(_slicechunktosize(revlog, [3, 4, 5], 3))
235 235 [[3], [4, 5]]
236 236 >>> list(_slicechunktosize(revlog, [5, 6, 7, 8], 3))
237 237 [[5], [6, 7, 8]]
238 238 >>> list(_slicechunktosize(revlog, [0, 1, 2, 3, 4, 5, 6, 7, 8], 3))
239 239 [[0], [1, 2], [3], [5], [6, 7, 8]]
240 240
241 241 Case with too large individual chunk (must return valid chunk)
242 242 >>> list(_slicechunktosize(revlog, [0, 1], 2))
243 243 [[0], [1]]
244 244 >>> list(_slicechunktosize(revlog, [1, 3], 1))
245 245 [[1], [3]]
246 246 >>> list(_slicechunktosize(revlog, [3, 4, 5], 2))
247 247 [[3], [5]]
248 248
249 249 == mixed case ==
250 250 >>> revlog = _testrevlog(data, snapshot=[0, 1, 2])
251 251 >>> list(_slicechunktosize(revlog, list(range(9)), 5))
252 252 [[0, 1], [2], [3, 4, 5], [6, 7, 8]]
253 253 """
254 254 assert targetsize is None or 0 <= targetsize
255 255 startdata = revlog.start(revs[0])
256 256 enddata = revlog.end(revs[-1])
257 257 fullspan = enddata - startdata
258 258 if targetsize is None or fullspan <= targetsize:
259 259 yield revs
260 260 return
261 261
262 262 startrevidx = 0
263 263 endrevidx = 1
264 264 iterrevs = enumerate(revs)
265 265 next(iterrevs) # skip first rev.
266 266 # first step: get snapshots out of the way
267 267 for idx, r in iterrevs:
268 268 span = revlog.end(r) - startdata
269 269 snapshot = revlog.issnapshot(r)
270 270 if span <= targetsize and snapshot:
271 271 endrevidx = idx + 1
272 272 else:
273 273 chunk = _trimchunk(revlog, revs, startrevidx, endrevidx)
274 274 if chunk:
275 275 yield chunk
276 276 startrevidx = idx
277 277 startdata = revlog.start(r)
278 278 endrevidx = idx + 1
279 279 if not snapshot:
280 280 break
281 281
282 282 # for the others, we use binary slicing to quickly converge toward valid
283 283 # chunks (otherwise, we might end up looking for start/end of many
284 284 # revisions). This logic is not looking for the perfect slicing point, it
285 285 # focuses on quickly converging toward valid chunks.
286 286 nbitem = len(revs)
287 287 while (enddata - startdata) > targetsize:
288 288 endrevidx = nbitem
289 289 if nbitem - startrevidx <= 1:
290 290 break # protect against individual chunk larger than limit
291 291 localenddata = revlog.end(revs[endrevidx - 1])
292 292 span = localenddata - startdata
293 293 while span > targetsize:
294 294 if endrevidx - startrevidx <= 1:
295 295 break # protect against individual chunk larger than limit
296 296 endrevidx -= (endrevidx - startrevidx) // 2
297 297 localenddata = revlog.end(revs[endrevidx - 1])
298 298 span = localenddata - startdata
299 299 chunk = _trimchunk(revlog, revs, startrevidx, endrevidx)
300 300 if chunk:
301 301 yield chunk
302 302 startrevidx = endrevidx
303 303 startdata = revlog.start(revs[startrevidx])
304 304
305 305 chunk = _trimchunk(revlog, revs, startrevidx)
306 306 if chunk:
307 307 yield chunk
308 308
309 309
310 310 def _slicechunktodensity(revlog, revs, targetdensity=0.5, mingapsize=0):
311 311 """slice revs to reduce the amount of unrelated data to be read from disk.
312 312
313 313 ``revs`` is sliced into groups that should be read in one time.
314 314 Assume that revs are sorted.
315 315
316 316 The initial chunk is sliced until the overall density (payload/chunks-span
317 317 ratio) is above `targetdensity`. No gap smaller than `mingapsize` is
318 318 skipped.
319 319
320 320 >>> revlog = _testrevlog([
321 321 ... 5, #00 (5)
322 322 ... 10, #01 (5)
323 323 ... 12, #02 (2)
324 324 ... 12, #03 (empty)
325 325 ... 27, #04 (15)
326 326 ... 31, #05 (4)
327 327 ... 31, #06 (empty)
328 328 ... 42, #07 (11)
329 329 ... 47, #08 (5)
330 330 ... 47, #09 (empty)
331 331 ... 48, #10 (1)
332 332 ... 51, #11 (3)
333 333 ... 74, #12 (23)
334 334 ... 85, #13 (11)
335 335 ... 86, #14 (1)
336 336 ... 91, #15 (5)
337 337 ... ])
338 338
339 339 >>> list(_slicechunktodensity(revlog, list(range(16))))
340 340 [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
341 341 >>> list(_slicechunktodensity(revlog, [0, 15]))
342 342 [[0], [15]]
343 343 >>> list(_slicechunktodensity(revlog, [0, 11, 15]))
344 344 [[0], [11], [15]]
345 345 >>> list(_slicechunktodensity(revlog, [0, 11, 13, 15]))
346 346 [[0], [11, 13, 15]]
347 347 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14]))
348 348 [[1, 2], [5, 8, 10, 11], [14]]
349 349 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
350 350 ... mingapsize=20))
351 351 [[1, 2, 3, 5, 8, 10, 11], [14]]
352 352 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
353 353 ... targetdensity=0.95))
354 354 [[1, 2], [5], [8, 10, 11], [14]]
355 355 >>> list(_slicechunktodensity(revlog, [1, 2, 3, 5, 8, 10, 11, 14],
356 356 ... targetdensity=0.95, mingapsize=12))
357 357 [[1, 2], [5, 8, 10, 11], [14]]
358 358 """
359 359 start = revlog.start
360 360 length = revlog.length
361 361
362 362 if len(revs) <= 1:
363 363 yield revs
364 364 return
365 365
366 366 deltachainspan = segmentspan(revlog, revs)
367 367
368 368 if deltachainspan < mingapsize:
369 369 yield revs
370 370 return
371 371
372 372 readdata = deltachainspan
373 373 chainpayload = sum(length(r) for r in revs)
374 374
375 375 if deltachainspan:
376 376 density = chainpayload / float(deltachainspan)
377 377 else:
378 378 density = 1.0
379 379
380 380 if density >= targetdensity:
381 381 yield revs
382 382 return
383 383
384 384 # Store the gaps in a heap to have them sorted by decreasing size
385 385 gaps = []
386 386 prevend = None
387 387 for i, rev in enumerate(revs):
388 388 revstart = start(rev)
389 389 revlen = length(rev)
390 390
391 391 # Skip empty revisions to form larger holes
392 392 if revlen == 0:
393 393 continue
394 394
395 395 if prevend is not None:
396 396 gapsize = revstart - prevend
397 397 # only consider holes that are large enough
398 398 if gapsize > mingapsize:
399 399 gaps.append((gapsize, i))
400 400
401 401 prevend = revstart + revlen
402 402 # sort the gaps to pop them from largest to small
403 403 gaps.sort()
404 404
405 405 # Collect the indices of the largest holes until the density is acceptable
406 406 selected = []
407 407 while gaps and density < targetdensity:
408 408 gapsize, gapidx = gaps.pop()
409 409
410 410 selected.append(gapidx)
411 411
412 412 # the gap sizes are stored as negatives to be sorted decreasingly
413 413 # by the heap
414 414 readdata -= gapsize
415 415 if readdata > 0:
416 416 density = chainpayload / float(readdata)
417 417 else:
418 418 density = 1.0
419 419 selected.sort()
420 420
421 421 # Cut the revs at collected indices
422 422 previdx = 0
423 423 for idx in selected:
424 424
425 425 chunk = _trimchunk(revlog, revs, previdx, idx)
426 426 if chunk:
427 427 yield chunk
428 428
429 429 previdx = idx
430 430
431 431 chunk = _trimchunk(revlog, revs, previdx)
432 432 if chunk:
433 433 yield chunk
434 434
435 435
436 436 def _trimchunk(revlog, revs, startidx, endidx=None):
437 437 """returns revs[startidx:endidx] without empty trailing revs
438 438
439 439 Doctest Setup
440 440 >>> revlog = _testrevlog([
441 441 ... 5, #0
442 442 ... 10, #1
443 443 ... 12, #2
444 444 ... 12, #3 (empty)
445 445 ... 17, #4
446 446 ... 21, #5
447 447 ... 21, #6 (empty)
448 448 ... ])
449 449
450 450 Contiguous cases:
451 451 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0)
452 452 [0, 1, 2, 3, 4, 5]
453 453 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0, 5)
454 454 [0, 1, 2, 3, 4]
455 455 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 0, 4)
456 456 [0, 1, 2]
457 457 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 2, 4)
458 458 [2]
459 459 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 3)
460 460 [3, 4, 5]
461 461 >>> _trimchunk(revlog, [0, 1, 2, 3, 4, 5, 6], 3, 5)
462 462 [3, 4]
463 463
464 464 Discontiguous cases:
465 465 >>> _trimchunk(revlog, [1, 3, 5, 6], 0)
466 466 [1, 3, 5]
467 467 >>> _trimchunk(revlog, [1, 3, 5, 6], 0, 2)
468 468 [1]
469 469 >>> _trimchunk(revlog, [1, 3, 5, 6], 1, 3)
470 470 [3, 5]
471 471 >>> _trimchunk(revlog, [1, 3, 5, 6], 1)
472 472 [3, 5]
473 473 """
474 474 length = revlog.length
475 475
476 476 if endidx is None:
477 477 endidx = len(revs)
478 478
479 479 # If we have a non-emtpy delta candidate, there are nothing to trim
480 480 if revs[endidx - 1] < len(revlog):
481 481 # Trim empty revs at the end, except the very first revision of a chain
482 482 while (
483 483 endidx > 1 and endidx > startidx and length(revs[endidx - 1]) == 0
484 484 ):
485 485 endidx -= 1
486 486
487 487 return revs[startidx:endidx]
488 488
489 489
490 490 def segmentspan(revlog, revs):
491 491 """Get the byte span of a segment of revisions
492 492
493 493 revs is a sorted array of revision numbers
494 494
495 495 >>> revlog = _testrevlog([
496 496 ... 5, #0
497 497 ... 10, #1
498 498 ... 12, #2
499 499 ... 12, #3 (empty)
500 500 ... 17, #4
501 501 ... ])
502 502
503 503 >>> segmentspan(revlog, [0, 1, 2, 3, 4])
504 504 17
505 505 >>> segmentspan(revlog, [0, 4])
506 506 17
507 507 >>> segmentspan(revlog, [3, 4])
508 508 5
509 509 >>> segmentspan(revlog, [1, 2, 3,])
510 510 7
511 511 >>> segmentspan(revlog, [1, 3])
512 512 7
513 513 """
514 514 if not revs:
515 515 return 0
516 516 end = revlog.end(revs[-1])
517 517 return end - revlog.start(revs[0])
518 518
519 519
520 520 def _textfromdelta(fh, revlog, baserev, delta, p1, p2, flags, expectednode):
521 521 """build full text from a (base, delta) pair and other metadata"""
522 522 # special case deltas which replace entire base; no need to decode
523 523 # base revision. this neatly avoids censored bases, which throw when
524 524 # they're decoded.
525 525 hlen = struct.calcsize(b">lll")
526 526 if delta[:hlen] == mdiff.replacediffheader(
527 527 revlog.rawsize(baserev), len(delta) - hlen
528 528 ):
529 529 fulltext = delta[hlen:]
530 530 else:
531 531 # deltabase is rawtext before changed by flag processors, which is
532 532 # equivalent to non-raw text
533 533 basetext = revlog.revision(baserev, _df=fh)
534 534 fulltext = mdiff.patch(basetext, delta)
535 535
536 536 try:
537 537 validatehash = flagutil.processflagsraw(revlog, fulltext, flags)
538 538 if validatehash:
539 539 revlog.checkhash(fulltext, expectednode, p1=p1, p2=p2)
540 540 if flags & REVIDX_ISCENSORED:
541 541 raise error.StorageError(
542 542 _(b'node %s is not censored') % expectednode
543 543 )
544 544 except error.CensoredNodeError:
545 545 # must pass the censored index flag to add censored revisions
546 546 if not flags & REVIDX_ISCENSORED:
547 547 raise
548 548 return fulltext
549 549
550 550
551 551 @attr.s(slots=True, frozen=True)
552 552 class _deltainfo:
553 553 distance = attr.ib()
554 554 deltalen = attr.ib()
555 555 data = attr.ib()
556 556 base = attr.ib()
557 557 chainbase = attr.ib()
558 558 chainlen = attr.ib()
559 559 compresseddeltalen = attr.ib()
560 560 snapshotdepth = attr.ib()
561 561
562 562
563 563 def drop_u_compression(delta):
564 564 """turn into a "u" (no-compression) into no-compression without header
565 565
566 566 This is useful for revlog format that has better compression method.
567 567 """
568 568 assert delta.data[0] == b'u', delta.data[0]
569 569 return _deltainfo(
570 570 delta.distance,
571 571 delta.deltalen - 1,
572 572 (b'', delta.data[1]),
573 573 delta.base,
574 574 delta.chainbase,
575 575 delta.chainlen,
576 576 delta.compresseddeltalen,
577 577 delta.snapshotdepth,
578 578 )
579 579
580 580
581 581 def is_good_delta_info(revlog, deltainfo, revinfo):
582 582 """Returns True if the given delta is good. Good means that it is within
583 583 the disk span, disk size, and chain length bounds that we know to be
584 584 performant."""
585 585 if deltainfo is None:
586 586 return False
587 587
588 588 if (
589 589 revinfo.cachedelta is not None
590 590 and deltainfo.base == revinfo.cachedelta[0]
591 591 and revinfo.cachedelta[2] == DELTA_BASE_REUSE_FORCE
592 592 ):
593 593 return True
594 594
595 595 # - 'deltainfo.distance' is the distance from the base revision --
596 596 # bounding it limits the amount of I/O we need to do.
597 597 # - 'deltainfo.compresseddeltalen' is the sum of the total size of
598 598 # deltas we need to apply -- bounding it limits the amount of CPU
599 599 # we consume.
600 600
601 601 textlen = revinfo.textlen
602 602 defaultmax = textlen * 4
603 603 maxdist = revlog._maxdeltachainspan
604 604 if not maxdist:
605 605 maxdist = deltainfo.distance # ensure the conditional pass
606 606 maxdist = max(maxdist, defaultmax)
607 607
608 608 # Bad delta from read span:
609 609 #
610 610 # If the span of data read is larger than the maximum allowed.
611 611 #
612 612 # In the sparse-revlog case, we rely on the associated "sparse reading"
613 613 # to avoid issue related to the span of data. In theory, it would be
614 614 # possible to build pathological revlog where delta pattern would lead
615 615 # to too many reads. However, they do not happen in practice at all. So
616 616 # we skip the span check entirely.
617 617 if not revlog._sparserevlog and maxdist < deltainfo.distance:
618 618 return False
619 619
620 620 # Bad delta from new delta size:
621 621 #
622 622 # If the delta size is larger than the target text, storing the
623 623 # delta will be inefficient.
624 624 if textlen < deltainfo.deltalen:
625 625 return False
626 626
627 627 # Bad delta from cumulated payload size:
628 628 #
629 629 # If the sum of delta get larger than K * target text length.
630 630 if textlen * LIMIT_DELTA2TEXT < deltainfo.compresseddeltalen:
631 631 return False
632 632
633 633 # Bad delta from chain length:
634 634 #
635 635 # If the number of delta in the chain gets too high.
636 636 if revlog._maxchainlen and revlog._maxchainlen < deltainfo.chainlen:
637 637 return False
638 638
639 639 # bad delta from intermediate snapshot size limit
640 640 #
641 641 # If an intermediate snapshot size is higher than the limit. The
642 642 # limit exist to prevent endless chain of intermediate delta to be
643 643 # created.
644 644 if (
645 645 deltainfo.snapshotdepth is not None
646 646 and (textlen >> deltainfo.snapshotdepth) < deltainfo.deltalen
647 647 ):
648 648 return False
649 649
650 650 # bad delta if new intermediate snapshot is larger than the previous
651 651 # snapshot
652 652 if (
653 653 deltainfo.snapshotdepth
654 654 and revlog.length(deltainfo.base) < deltainfo.deltalen
655 655 ):
656 656 return False
657 657
658 658 return True
659 659
660 660
661 661 # If a revision's full text is that much bigger than a base candidate full
662 662 # text's, it is very unlikely that it will produce a valid delta. We no longer
663 663 # consider these candidates.
664 664 LIMIT_BASE2TEXT = 500
665 665
666 666
667 667 def _candidategroups(
668 668 revlog,
669 669 textlen,
670 670 p1,
671 671 p2,
672 672 cachedelta,
673 673 excluded_bases=None,
674 674 target_rev=None,
675 675 snapshot_cache=None,
676 676 ):
677 677 """Provides group of revision to be tested as delta base
678 678
679 679 This top level function focus on emitting groups with unique and worthwhile
680 680 content. See _raw_candidate_groups for details about the group order.
681 681 """
682 682 # should we try to build a delta?
683 683 if not (len(revlog) and revlog._storedeltachains):
684 684 yield None
685 685 return
686 686
687 if target_rev is None:
688 target_rev = len(revlog)
689
690 if not revlog._generaldelta:
691 # before general delta, there is only one possible delta base
692 yield (target_rev - 1,)
693 yield None
694 return
695
687 696 if (
688 697 cachedelta is not None
689 698 and nullrev == cachedelta[0]
690 699 and cachedelta[2] == DELTA_BASE_REUSE_FORCE
691 700 ):
692 701 # instruction are to forcibly do a full snapshot
693 702 yield None
694 703 return
695 704
696 705 deltalength = revlog.length
697 706 deltaparent = revlog.deltaparent
698 707 sparse = revlog._sparserevlog
699 708 good = None
700 709
701 710 deltas_limit = textlen * LIMIT_DELTA2TEXT
702 711 group_chunk_size = revlog._candidate_group_chunk_size
703 712
704 713 tested = {nullrev}
705 714 candidates = _refinedgroups(
706 715 revlog,
707 716 p1,
708 717 p2,
709 718 cachedelta,
710 719 snapshot_cache=snapshot_cache,
711 720 )
712 721 while True:
713 722 temptative = candidates.send(good)
714 723 if temptative is None:
715 724 break
716 725 group = []
717 726 for rev in temptative:
718 727 # skip over empty delta (no need to include them in a chain)
719 while revlog._generaldelta and not (
720 rev == nullrev or rev in tested or deltalength(rev)
721 ):
728 while not (rev == nullrev or rev in tested or deltalength(rev)):
722 729 tested.add(rev)
723 730 rev = deltaparent(rev)
724 731 # no need to try a delta against nullrev, this will be done as a
725 732 # last resort.
726 733 if rev == nullrev:
727 734 continue
728 735 # filter out revision we tested already
729 736 if rev in tested:
730 737 continue
731 738
732 739 if (
733 740 cachedelta is not None
734 741 and rev == cachedelta[0]
735 742 and cachedelta[2] == DELTA_BASE_REUSE_FORCE
736 743 ):
737 744 # instructions are to forcibly consider/use this delta base
738 745 group.append(rev)
739 746 continue
740 747
741 748 # an higher authority deamed the base unworthy (e.g. censored)
742 749 if excluded_bases is not None and rev in excluded_bases:
743 750 tested.add(rev)
744 751 continue
745 752 # We are in some recomputation cases and that rev is too high in
746 753 # the revlog
747 754 if target_rev is not None and rev >= target_rev:
748 755 tested.add(rev)
749 756 continue
750 757 # filter out delta base that will never produce good delta
751 758 if deltas_limit < revlog.length(rev):
752 759 tested.add(rev)
753 760 continue
754 761 if sparse and revlog.rawsize(rev) < (textlen // LIMIT_BASE2TEXT):
755 762 tested.add(rev)
756 763 continue
757 764 # no delta for rawtext-changing revs (see "candelta" for why)
758 765 if revlog.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS:
759 766 tested.add(rev)
760 767 continue
761 768
762 769 # If we reach here, we are about to build and test a delta.
763 770 # The delta building process will compute the chaininfo in all
764 771 # case, since that computation is cached, it is fine to access it
765 772 # here too.
766 773 chainlen, chainsize = revlog._chaininfo(rev)
767 774 # if chain will be too long, skip base
768 775 if revlog._maxchainlen and chainlen >= revlog._maxchainlen:
769 776 tested.add(rev)
770 777 continue
771 778 # if chain already have too much data, skip base
772 779 if deltas_limit < chainsize:
773 780 tested.add(rev)
774 781 continue
775 782 if sparse and revlog.upperboundcomp is not None:
776 783 maxcomp = revlog.upperboundcomp
777 784 basenotsnap = (p1, p2, nullrev)
778 785 if rev not in basenotsnap and revlog.issnapshot(rev):
779 786 snapshotdepth = revlog.snapshotdepth(rev)
780 787 # If text is significantly larger than the base, we can
781 788 # expect the resulting delta to be proportional to the size
782 789 # difference
783 790 revsize = revlog.rawsize(rev)
784 791 rawsizedistance = max(textlen - revsize, 0)
785 792 # use an estimate of the compression upper bound.
786 793 lowestrealisticdeltalen = rawsizedistance // maxcomp
787 794
788 795 # check the absolute constraint on the delta size
789 796 snapshotlimit = textlen >> snapshotdepth
790 797 if snapshotlimit < lowestrealisticdeltalen:
791 798 # delta lower bound is larger than accepted upper bound
792 799 tested.add(rev)
793 800 continue
794 801
795 802 # check the relative constraint on the delta size
796 803 revlength = revlog.length(rev)
797 804 if revlength < lowestrealisticdeltalen:
798 805 # delta probable lower bound is larger than target base
799 806 tested.add(rev)
800 807 continue
801 808
802 809 group.append(rev)
803 810 if group:
804 811 # When the size of the candidate group is big, it can result in a
805 812 # quite significant performance impact. To reduce this, we can send
806 813 # them in smaller batches until the new batch does not provide any
807 814 # improvements.
808 815 #
809 816 # This might reduce the overall efficiency of the compression in
810 817 # some corner cases, but that should also prevent very pathological
811 818 # cases from being an issue. (eg. 20 000 candidates).
812 819 #
813 820 # XXX note that the ordering of the group becomes important as it
814 821 # now impacts the final result. The current order is unprocessed
815 822 # and can be improved.
816 823 if group_chunk_size == 0:
817 824 tested.update(group)
818 825 good = yield tuple(group)
819 826 else:
820 827 prev_good = good
821 828 for start in range(0, len(group), group_chunk_size):
822 829 sub_group = group[start : start + group_chunk_size]
823 830 tested.update(sub_group)
824 831 good = yield tuple(sub_group)
825 832 if prev_good == good:
826 833 break
827 834
828 835 yield None
829 836
830 837
831 838 def _refinedgroups(revlog, p1, p2, cachedelta, snapshot_cache=None):
832 839 good = None
833 840 # First we try to reuse a the delta contained in the bundle.
834 841 # (or from the source revlog)
835 842 #
836 843 # This logic only applies to general delta repositories and can be disabled
837 844 # through configuration. Disabling reuse source delta is useful when
838 845 # we want to make sure we recomputed "optimal" deltas.
839 846 debug_info = None
840 847 if cachedelta is not None and cachedelta[2] > DELTA_BASE_REUSE_NO:
841 848 # Assume what we received from the server is a good choice
842 849 # build delta will reuse the cache
843 850 if debug_info is not None:
844 851 debug_info['cached-delta.tested'] += 1
845 852 good = yield (cachedelta[0],)
846 853 if good is not None:
847 854 if debug_info is not None:
848 855 debug_info['cached-delta.accepted'] += 1
849 856 yield None
850 857 return
851 858 if snapshot_cache is None:
852 859 snapshot_cache = SnapshotCache()
853 860 groups = _rawgroups(
854 861 revlog,
855 862 p1,
856 863 p2,
857 864 cachedelta,
858 865 snapshot_cache,
859 866 )
860 867 for candidates in groups:
861 868 good = yield candidates
862 869 if good is not None:
863 870 break
864 871
865 872 # If sparse revlog is enabled, we can try to refine the available deltas
866 873 if not revlog._sparserevlog:
867 874 yield None
868 875 return
869 876
870 877 # if we have a refinable value, try to refine it
871 878 if good is not None and good not in (p1, p2) and revlog.issnapshot(good):
872 879 # refine snapshot down
873 880 previous = None
874 881 while previous != good:
875 882 previous = good
876 883 base = revlog.deltaparent(good)
877 884 if base == nullrev:
878 885 break
879 886 good = yield (base,)
880 887 # refine snapshot up
881 888 if not snapshot_cache.snapshots:
882 889 snapshot_cache.update(revlog, good + 1)
883 890 previous = None
884 891 while good != previous:
885 892 previous = good
886 893 children = tuple(sorted(c for c in snapshot_cache.snapshots[good]))
887 894 good = yield children
888 895
889 896 if debug_info is not None:
890 897 if good is None:
891 898 debug_info['no-solution'] += 1
892 899
893 900 yield None
894 901
895 902
896 903 def _rawgroups(revlog, p1, p2, cachedelta, snapshot_cache=None):
897 904 """Provides group of revision to be tested as delta base
898 905
899 906 This lower level function focus on emitting delta theorically interresting
900 907 without looking it any practical details.
901 908
902 909 The group order aims at providing fast or small candidates first.
903 910 """
904 gdelta = revlog._generaldelta
905 # gate sparse behind general-delta because of issue6056
906 sparse = gdelta and revlog._sparserevlog
911 # Why search for delta base if we cannot use a delta base ?
912 assert revlog._generaldelta
913 # also see issue6056
914 sparse = revlog._sparserevlog
907 915 curr = len(revlog)
908 916 prev = curr - 1
909 917 deltachain = lambda rev: revlog._deltachain(rev)[0]
910 918
911 if gdelta:
912 # exclude already lazy tested base if any
913 parents = [p for p in (p1, p2) if p != nullrev]
919 # exclude already lazy tested base if any
920 parents = [p for p in (p1, p2) if p != nullrev]
914 921
915 if not revlog._deltabothparents and len(parents) == 2:
916 parents.sort()
917 # To minimize the chance of having to build a fulltext,
918 # pick first whichever parent is closest to us (max rev)
919 yield (parents[1],)
920 # then the other one (min rev) if the first did not fit
921 yield (parents[0],)
922 elif len(parents) > 0:
923 # Test all parents (1 or 2), and keep the best candidate
924 yield parents
922 if not revlog._deltabothparents and len(parents) == 2:
923 parents.sort()
924 # To minimize the chance of having to build a fulltext,
925 # pick first whichever parent is closest to us (max rev)
926 yield (parents[1],)
927 # then the other one (min rev) if the first did not fit
928 yield (parents[0],)
929 elif len(parents) > 0:
930 # Test all parents (1 or 2), and keep the best candidate
931 yield parents
925 932
926 933 if sparse and parents:
927 934 if snapshot_cache is None:
928 935 # map: base-rev: [snapshot-revs]
929 936 snapshot_cache = SnapshotCache()
930 937 # See if we can use an existing snapshot in the parent chains to use as
931 938 # a base for a new intermediate-snapshot
932 939 #
933 940 # search for snapshot in parents delta chain
934 941 # map: snapshot-level: snapshot-rev
935 942 parents_snaps = collections.defaultdict(set)
936 943 candidate_chains = [deltachain(p) for p in parents]
937 944 for chain in candidate_chains:
938 945 for idx, s in enumerate(chain):
939 946 if not revlog.issnapshot(s):
940 947 break
941 948 parents_snaps[idx].add(s)
942 949 snapfloor = min(parents_snaps[0]) + 1
943 950 snapshot_cache.update(revlog, snapfloor)
944 951 # search for the highest "unrelated" revision
945 952 #
946 953 # Adding snapshots used by "unrelated" revision increase the odd we
947 954 # reuse an independant, yet better snapshot chain.
948 955 #
949 956 # XXX instead of building a set of revisions, we could lazily enumerate
950 957 # over the chains. That would be more efficient, however we stick to
951 958 # simple code for now.
952 959 all_revs = set()
953 960 for chain in candidate_chains:
954 961 all_revs.update(chain)
955 962 other = None
956 963 for r in revlog.revs(prev, snapfloor):
957 964 if r not in all_revs:
958 965 other = r
959 966 break
960 967 if other is not None:
961 968 # To avoid unfair competition, we won't use unrelated intermediate
962 969 # snapshot that are deeper than the ones from the parent delta
963 970 # chain.
964 971 max_depth = max(parents_snaps.keys())
965 972 chain = deltachain(other)
966 973 for depth, s in enumerate(chain):
967 974 if s < snapfloor:
968 975 continue
969 976 if max_depth < depth:
970 977 break
971 978 if not revlog.issnapshot(s):
972 979 break
973 980 parents_snaps[depth].add(s)
974 981 # Test them as possible intermediate snapshot base
975 982 # We test them from highest to lowest level. High level one are more
976 983 # likely to result in small delta
977 984 floor = None
978 985 for idx, snaps in sorted(parents_snaps.items(), reverse=True):
979 986 siblings = set()
980 987 for s in snaps:
981 988 siblings.update(snapshot_cache.snapshots[s])
982 989 # Before considering making a new intermediate snapshot, we check
983 990 # if an existing snapshot, children of base we consider, would be
984 991 # suitable.
985 992 #
986 993 # It give a change to reuse a delta chain "unrelated" to the
987 994 # current revision instead of starting our own. Without such
988 995 # re-use, topological branches would keep reopening new chains.
989 996 # Creating more and more snapshot as the repository grow.
990 997
991 998 if floor is not None:
992 999 # We only do this for siblings created after the one in our
993 1000 # parent's delta chain. Those created before has less chances
994 1001 # to be valid base since our ancestors had to create a new
995 1002 # snapshot.
996 1003 siblings = [r for r in siblings if floor < r]
997 1004 yield tuple(sorted(siblings))
998 1005 # then test the base from our parent's delta chain.
999 1006 yield tuple(sorted(snaps))
1000 1007 floor = min(snaps)
1001 1008 # No suitable base found in the parent chain, search if any full
1002 1009 # snapshots emitted since parent's base would be a suitable base for an
1003 1010 # intermediate snapshot.
1004 1011 #
1005 1012 # It give a chance to reuse a delta chain unrelated to the current
1006 1013 # revisions instead of starting our own. Without such re-use,
1007 1014 # topological branches would keep reopening new full chains. Creating
1008 1015 # more and more snapshot as the repository grow.
1009 1016 full = [r for r in snapshot_cache.snapshots[nullrev] if snapfloor <= r]
1010 1017 yield tuple(sorted(full))
1011 1018
1012 1019 if not sparse:
1013 1020 # other approach failed try against prev to hopefully save us a
1014 1021 # fulltext.
1015 1022 yield (prev,)
1016 1023
1017 1024
1018 1025 class SnapshotCache:
1019 1026 __slots__ = ('snapshots', '_start_rev', '_end_rev')
1020 1027
1021 1028 def __init__(self):
1022 1029 self.snapshots = collections.defaultdict(set)
1023 1030 self._start_rev = None
1024 1031 self._end_rev = None
1025 1032
1026 1033 def update(self, revlog, start_rev=0):
1027 1034 """find snapshots from start_rev to tip"""
1028 1035 nb_revs = len(revlog)
1029 1036 end_rev = nb_revs - 1
1030 1037 if start_rev > end_rev:
1031 1038 return # range is empty
1032 1039
1033 1040 if self._start_rev is None:
1034 1041 assert self._end_rev is None
1035 1042 self._update(revlog, start_rev, end_rev)
1036 1043 elif not (self._start_rev <= start_rev and end_rev <= self._end_rev):
1037 1044 if start_rev < self._start_rev:
1038 1045 self._update(revlog, start_rev, self._start_rev - 1)
1039 1046 if self._end_rev < end_rev:
1040 1047 self._update(revlog, self._end_rev + 1, end_rev)
1041 1048
1042 1049 if self._start_rev is None:
1043 1050 assert self._end_rev is None
1044 1051 self._end_rev = end_rev
1045 1052 self._start_rev = start_rev
1046 1053 else:
1047 1054 self._start_rev = min(self._start_rev, start_rev)
1048 1055 self._end_rev = max(self._end_rev, end_rev)
1049 1056 assert self._start_rev <= self._end_rev, (
1050 1057 self._start_rev,
1051 1058 self._end_rev,
1052 1059 )
1053 1060
1054 1061 def _update(self, revlog, start_rev, end_rev):
1055 1062 """internal method that actually do update content"""
1056 1063 assert self._start_rev is None or (
1057 1064 start_rev < self._start_rev or start_rev > self._end_rev
1058 1065 ), (self._start_rev, self._end_rev, start_rev, end_rev)
1059 1066 assert self._start_rev is None or (
1060 1067 end_rev < self._start_rev or end_rev > self._end_rev
1061 1068 ), (self._start_rev, self._end_rev, start_rev, end_rev)
1062 1069 cache = self.snapshots
1063 1070 if util.safehasattr(revlog.index, b'findsnapshots'):
1064 1071 revlog.index.findsnapshots(cache, start_rev, end_rev)
1065 1072 else:
1066 1073 deltaparent = revlog.deltaparent
1067 1074 issnapshot = revlog.issnapshot
1068 1075 for rev in revlog.revs(start_rev, end_rev):
1069 1076 if issnapshot(rev):
1070 1077 cache[deltaparent(rev)].add(rev)
1071 1078
1072 1079
1073 1080 class deltacomputer:
1074 1081 def __init__(
1075 1082 self,
1076 1083 revlog,
1077 1084 write_debug=None,
1078 1085 debug_search=False,
1079 1086 debug_info=None,
1080 1087 ):
1081 1088 self.revlog = revlog
1082 1089 self._write_debug = write_debug
1083 1090 self._debug_search = debug_search
1084 1091 self._debug_info = debug_info
1085 1092 self._snapshot_cache = SnapshotCache()
1086 1093
1087 1094 def buildtext(self, revinfo, fh):
1088 1095 """Builds a fulltext version of a revision
1089 1096
1090 1097 revinfo: revisioninfo instance that contains all needed info
1091 1098 fh: file handle to either the .i or the .d revlog file,
1092 1099 depending on whether it is inlined or not
1093 1100 """
1094 1101 btext = revinfo.btext
1095 1102 if btext[0] is not None:
1096 1103 return btext[0]
1097 1104
1098 1105 revlog = self.revlog
1099 1106 cachedelta = revinfo.cachedelta
1100 1107 baserev = cachedelta[0]
1101 1108 delta = cachedelta[1]
1102 1109
1103 1110 fulltext = btext[0] = _textfromdelta(
1104 1111 fh,
1105 1112 revlog,
1106 1113 baserev,
1107 1114 delta,
1108 1115 revinfo.p1,
1109 1116 revinfo.p2,
1110 1117 revinfo.flags,
1111 1118 revinfo.node,
1112 1119 )
1113 1120 return fulltext
1114 1121
1115 1122 def _builddeltadiff(self, base, revinfo, fh):
1116 1123 revlog = self.revlog
1117 1124 t = self.buildtext(revinfo, fh)
1118 1125 if revlog.iscensored(base):
1119 1126 # deltas based on a censored revision must replace the
1120 1127 # full content in one patch, so delta works everywhere
1121 1128 header = mdiff.replacediffheader(revlog.rawsize(base), len(t))
1122 1129 delta = header + t
1123 1130 else:
1124 1131 ptext = revlog.rawdata(base, _df=fh)
1125 1132 delta = mdiff.textdiff(ptext, t)
1126 1133
1127 1134 return delta
1128 1135
1129 def _builddeltainfo(self, revinfo, base, fh):
1136 def _builddeltainfo(self, revinfo, base, fh, target_rev=None):
1130 1137 # can we use the cached delta?
1131 1138 revlog = self.revlog
1132 1139 debug_search = self._write_debug is not None and self._debug_search
1133 1140 chainbase = revlog.chainbase(base)
1134 1141 if revlog._generaldelta:
1135 1142 deltabase = base
1136 1143 else:
1144 if target_rev is not None and base != target_rev - 1:
1145 msg = (
1146 b'general delta cannot use delta for something else '
1147 b'than `prev`: %d<-%d'
1148 )
1149 msg %= (base, target_rev)
1150 raise error.ProgrammingError(msg)
1137 1151 deltabase = chainbase
1138 1152 snapshotdepth = None
1139 1153 if revlog._sparserevlog and deltabase == nullrev:
1140 1154 snapshotdepth = 0
1141 1155 elif revlog._sparserevlog and revlog.issnapshot(deltabase):
1142 1156 # A delta chain should always be one full snapshot,
1143 1157 # zero or more semi-snapshots, and zero or more deltas
1144 1158 p1, p2 = revlog.rev(revinfo.p1), revlog.rev(revinfo.p2)
1145 1159 if deltabase not in (p1, p2) and revlog.issnapshot(deltabase):
1146 1160 snapshotdepth = len(revlog._deltachain(deltabase)[0])
1147 1161 delta = None
1148 1162 if revinfo.cachedelta:
1149 1163 cachebase = revinfo.cachedelta[0]
1150 1164 # check if the diff still apply
1151 1165 currentbase = cachebase
1152 1166 while (
1153 1167 currentbase != nullrev
1154 1168 and currentbase != base
1155 1169 and self.revlog.length(currentbase) == 0
1156 1170 ):
1157 1171 currentbase = self.revlog.deltaparent(currentbase)
1158 1172 if self.revlog._lazydelta and currentbase == base:
1159 1173 delta = revinfo.cachedelta[1]
1160 1174 if delta is None:
1161 1175 delta = self._builddeltadiff(base, revinfo, fh)
1162 1176 if debug_search:
1163 1177 msg = b"DBG-DELTAS-SEARCH: uncompressed-delta-size=%d\n"
1164 1178 msg %= len(delta)
1165 1179 self._write_debug(msg)
1166 1180 # snapshotdept need to be neither None nor 0 level snapshot
1167 1181 if revlog.upperboundcomp is not None and snapshotdepth:
1168 1182 lowestrealisticdeltalen = len(delta) // revlog.upperboundcomp
1169 1183 snapshotlimit = revinfo.textlen >> snapshotdepth
1170 1184 if debug_search:
1171 1185 msg = b"DBG-DELTAS-SEARCH: projected-lower-size=%d\n"
1172 1186 msg %= lowestrealisticdeltalen
1173 1187 self._write_debug(msg)
1174 1188 if snapshotlimit < lowestrealisticdeltalen:
1175 1189 if debug_search:
1176 1190 msg = b"DBG-DELTAS-SEARCH: DISCARDED (snapshot limit)\n"
1177 1191 self._write_debug(msg)
1178 1192 return None
1179 1193 if revlog.length(base) < lowestrealisticdeltalen:
1180 1194 if debug_search:
1181 1195 msg = b"DBG-DELTAS-SEARCH: DISCARDED (prev size)\n"
1182 1196 self._write_debug(msg)
1183 1197 return None
1184 1198 header, data = revlog.compress(delta)
1185 1199 deltalen = len(header) + len(data)
1186 1200 offset = revlog.end(len(revlog) - 1)
1187 1201 dist = deltalen + offset - revlog.start(chainbase)
1188 1202 chainlen, compresseddeltalen = revlog._chaininfo(base)
1189 1203 chainlen += 1
1190 1204 compresseddeltalen += deltalen
1191 1205
1192 1206 return _deltainfo(
1193 1207 dist,
1194 1208 deltalen,
1195 1209 (header, data),
1196 1210 deltabase,
1197 1211 chainbase,
1198 1212 chainlen,
1199 1213 compresseddeltalen,
1200 1214 snapshotdepth,
1201 1215 )
1202 1216
1203 1217 def _fullsnapshotinfo(self, fh, revinfo, curr):
1204 1218 rawtext = self.buildtext(revinfo, fh)
1205 1219 data = self.revlog.compress(rawtext)
1206 1220 compresseddeltalen = deltalen = dist = len(data[1]) + len(data[0])
1207 1221 deltabase = chainbase = curr
1208 1222 snapshotdepth = 0
1209 1223 chainlen = 1
1210 1224
1211 1225 return _deltainfo(
1212 1226 dist,
1213 1227 deltalen,
1214 1228 data,
1215 1229 deltabase,
1216 1230 chainbase,
1217 1231 chainlen,
1218 1232 compresseddeltalen,
1219 1233 snapshotdepth,
1220 1234 )
1221 1235
1222 1236 def finddeltainfo(self, revinfo, fh, excluded_bases=None, target_rev=None):
1223 1237 """Find an acceptable delta against a candidate revision
1224 1238
1225 1239 revinfo: information about the revision (instance of _revisioninfo)
1226 1240 fh: file handle to either the .i or the .d revlog file,
1227 1241 depending on whether it is inlined or not
1228 1242
1229 1243 Returns the first acceptable candidate revision, as ordered by
1230 1244 _candidategroups
1231 1245
1232 1246 If no suitable deltabase is found, we return delta info for a full
1233 1247 snapshot.
1234 1248
1235 1249 `excluded_bases` is an optional set of revision that cannot be used as
1236 1250 a delta base. Use this to recompute delta suitable in censor or strip
1237 1251 context.
1238 1252 """
1239 1253 if target_rev is None:
1240 1254 target_rev = len(self.revlog)
1241 1255
1242 1256 if not revinfo.textlen:
1243 1257 return self._fullsnapshotinfo(fh, revinfo, target_rev)
1244 1258
1245 1259 if excluded_bases is None:
1246 1260 excluded_bases = set()
1247 1261
1248 1262 # no delta for flag processor revision (see "candelta" for why)
1249 1263 # not calling candelta since only one revision needs test, also to
1250 1264 # avoid overhead fetching flags again.
1251 1265 if revinfo.flags & REVIDX_RAWTEXT_CHANGING_FLAGS:
1252 1266 return self._fullsnapshotinfo(fh, revinfo, target_rev)
1253 1267
1254 1268 gather_debug = (
1255 1269 self._write_debug is not None or self._debug_info is not None
1256 1270 )
1257 1271 debug_search = self._write_debug is not None and self._debug_search
1258 1272
1259 1273 if gather_debug:
1260 1274 start = util.timer()
1261 1275
1262 1276 # count the number of different delta we tried (for debug purpose)
1263 1277 dbg_try_count = 0
1264 1278 # count the number of "search round" we did. (for debug purpose)
1265 1279 dbg_try_rounds = 0
1266 1280 dbg_type = b'unknown'
1267 1281
1268 1282 cachedelta = revinfo.cachedelta
1269 1283 p1 = revinfo.p1
1270 1284 p2 = revinfo.p2
1271 1285 revlog = self.revlog
1272 1286
1273 1287 deltainfo = None
1274 1288 p1r, p2r = revlog.rev(p1), revlog.rev(p2)
1275 1289
1276 1290 if gather_debug:
1277 1291 if p1r != nullrev:
1278 1292 p1_chain_len = revlog._chaininfo(p1r)[0]
1279 1293 else:
1280 1294 p1_chain_len = -1
1281 1295 if p2r != nullrev:
1282 1296 p2_chain_len = revlog._chaininfo(p2r)[0]
1283 1297 else:
1284 1298 p2_chain_len = -1
1285 1299 if debug_search:
1286 1300 msg = b"DBG-DELTAS-SEARCH: SEARCH rev=%d\n"
1287 1301 msg %= target_rev
1288 1302 self._write_debug(msg)
1289 1303
1290 1304 groups = _candidategroups(
1291 1305 self.revlog,
1292 1306 revinfo.textlen,
1293 1307 p1r,
1294 1308 p2r,
1295 1309 cachedelta,
1296 1310 excluded_bases,
1297 1311 target_rev,
1298 1312 snapshot_cache=self._snapshot_cache,
1299 1313 )
1300 1314 candidaterevs = next(groups)
1301 1315 while candidaterevs is not None:
1302 1316 dbg_try_rounds += 1
1303 1317 if debug_search:
1304 1318 prev = None
1305 1319 if deltainfo is not None:
1306 1320 prev = deltainfo.base
1307 1321
1308 1322 if (
1309 1323 cachedelta is not None
1310 1324 and len(candidaterevs) == 1
1311 1325 and cachedelta[0] in candidaterevs
1312 1326 ):
1313 1327 round_type = b"cached-delta"
1314 1328 elif p1 in candidaterevs or p2 in candidaterevs:
1315 1329 round_type = b"parents"
1316 1330 elif prev is not None and all(c < prev for c in candidaterevs):
1317 1331 round_type = b"refine-down"
1318 1332 elif prev is not None and all(c > prev for c in candidaterevs):
1319 1333 round_type = b"refine-up"
1320 1334 else:
1321 1335 round_type = b"search-down"
1322 1336 msg = b"DBG-DELTAS-SEARCH: ROUND #%d - %d candidates - %s\n"
1323 1337 msg %= (dbg_try_rounds, len(candidaterevs), round_type)
1324 1338 self._write_debug(msg)
1325 1339 nominateddeltas = []
1326 1340 if deltainfo is not None:
1327 1341 if debug_search:
1328 1342 msg = (
1329 1343 b"DBG-DELTAS-SEARCH: CONTENDER: rev=%d - length=%d\n"
1330 1344 )
1331 1345 msg %= (deltainfo.base, deltainfo.deltalen)
1332 1346 self._write_debug(msg)
1333 1347 # if we already found a good delta,
1334 1348 # challenge it against refined candidates
1335 1349 nominateddeltas.append(deltainfo)
1336 1350 for candidaterev in candidaterevs:
1337 1351 if debug_search:
1338 1352 msg = b"DBG-DELTAS-SEARCH: CANDIDATE: rev=%d\n"
1339 1353 msg %= candidaterev
1340 1354 self._write_debug(msg)
1341 1355 candidate_type = None
1342 1356 if candidaterev == p1:
1343 1357 candidate_type = b"p1"
1344 1358 elif candidaterev == p2:
1345 1359 candidate_type = b"p2"
1346 1360 elif self.revlog.issnapshot(candidaterev):
1347 1361 candidate_type = b"snapshot-%d"
1348 1362 candidate_type %= self.revlog.snapshotdepth(
1349 1363 candidaterev
1350 1364 )
1351 1365
1352 1366 if candidate_type is not None:
1353 1367 msg = b"DBG-DELTAS-SEARCH: type=%s\n"
1354 1368 msg %= candidate_type
1355 1369 self._write_debug(msg)
1356 1370 msg = b"DBG-DELTAS-SEARCH: size=%d\n"
1357 1371 msg %= self.revlog.length(candidaterev)
1358 1372 self._write_debug(msg)
1359 1373 msg = b"DBG-DELTAS-SEARCH: base=%d\n"
1360 1374 msg %= self.revlog.deltaparent(candidaterev)
1361 1375 self._write_debug(msg)
1362 1376
1363 1377 dbg_try_count += 1
1364 1378
1365 1379 if debug_search:
1366 1380 delta_start = util.timer()
1367 candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
1381 candidatedelta = self._builddeltainfo(
1382 revinfo,
1383 candidaterev,
1384 fh,
1385 target_rev=target_rev,
1386 )
1368 1387 if debug_search:
1369 1388 delta_end = util.timer()
1370 1389 msg = b"DBG-DELTAS-SEARCH: delta-search-time=%f\n"
1371 1390 msg %= delta_end - delta_start
1372 1391 self._write_debug(msg)
1373 1392 if candidatedelta is not None:
1374 1393 if is_good_delta_info(self.revlog, candidatedelta, revinfo):
1375 1394 if debug_search:
1376 1395 msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (GOOD)\n"
1377 1396 msg %= candidatedelta.deltalen
1378 1397 self._write_debug(msg)
1379 1398 nominateddeltas.append(candidatedelta)
1380 1399 elif debug_search:
1381 1400 msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (BAD)\n"
1382 1401 msg %= candidatedelta.deltalen
1383 1402 self._write_debug(msg)
1384 1403 elif debug_search:
1385 1404 msg = b"DBG-DELTAS-SEARCH: NO-DELTA\n"
1386 1405 self._write_debug(msg)
1387 1406 if nominateddeltas:
1388 1407 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen)
1389 1408 if deltainfo is not None:
1390 1409 candidaterevs = groups.send(deltainfo.base)
1391 1410 else:
1392 1411 candidaterevs = next(groups)
1393 1412
1394 1413 if deltainfo is None:
1395 1414 dbg_type = b"full"
1396 1415 deltainfo = self._fullsnapshotinfo(fh, revinfo, target_rev)
1397 1416 elif deltainfo.snapshotdepth: # pytype: disable=attribute-error
1398 1417 dbg_type = b"snapshot"
1399 1418 else:
1400 1419 dbg_type = b"delta"
1401 1420
1402 1421 if gather_debug:
1403 1422 end = util.timer()
1404 1423 if dbg_type == b'full':
1405 1424 used_cached = (
1406 1425 cachedelta is not None
1407 1426 and dbg_try_rounds == 0
1408 1427 and dbg_try_count == 0
1409 1428 and cachedelta[0] == nullrev
1410 1429 )
1411 1430 else:
1412 1431 used_cached = (
1413 1432 cachedelta is not None
1414 1433 and dbg_try_rounds == 1
1415 1434 and dbg_try_count == 1
1416 1435 and deltainfo.base == cachedelta[0]
1417 1436 )
1418 1437 dbg = {
1419 1438 'duration': end - start,
1420 1439 'revision': target_rev,
1421 1440 'delta-base': deltainfo.base, # pytype: disable=attribute-error
1422 1441 'search_round_count': dbg_try_rounds,
1423 1442 'using-cached-base': used_cached,
1424 1443 'delta_try_count': dbg_try_count,
1425 1444 'type': dbg_type,
1426 1445 'p1-chain-len': p1_chain_len,
1427 1446 'p2-chain-len': p2_chain_len,
1428 1447 }
1429 1448 if (
1430 1449 deltainfo.snapshotdepth # pytype: disable=attribute-error
1431 1450 is not None
1432 1451 ):
1433 1452 dbg[
1434 1453 'snapshot-depth'
1435 1454 ] = deltainfo.snapshotdepth # pytype: disable=attribute-error
1436 1455 else:
1437 1456 dbg['snapshot-depth'] = 0
1438 1457 target_revlog = b"UNKNOWN"
1439 1458 target_type = self.revlog.target[0]
1440 1459 target_key = self.revlog.target[1]
1441 1460 if target_type == KIND_CHANGELOG:
1442 1461 target_revlog = b'CHANGELOG:'
1443 1462 elif target_type == KIND_MANIFESTLOG:
1444 1463 target_revlog = b'MANIFESTLOG:'
1445 1464 if target_key:
1446 1465 target_revlog += b'%s:' % target_key
1447 1466 elif target_type == KIND_FILELOG:
1448 1467 target_revlog = b'FILELOG:'
1449 1468 if target_key:
1450 1469 target_revlog += b'%s:' % target_key
1451 1470 dbg['target-revlog'] = target_revlog
1452 1471
1453 1472 if self._debug_info is not None:
1454 1473 self._debug_info.append(dbg)
1455 1474
1456 1475 if self._write_debug is not None:
1457 1476 msg = (
1458 1477 b"DBG-DELTAS:"
1459 1478 b" %-12s"
1460 1479 b" rev=%d:"
1461 1480 b" delta-base=%d"
1462 1481 b" is-cached=%d"
1463 1482 b" - search-rounds=%d"
1464 1483 b" try-count=%d"
1465 1484 b" - delta-type=%-6s"
1466 1485 b" snap-depth=%d"
1467 1486 b" - p1-chain-length=%d"
1468 1487 b" p2-chain-length=%d"
1469 1488 b" - duration=%f"
1470 1489 b"\n"
1471 1490 )
1472 1491 msg %= (
1473 1492 dbg["target-revlog"],
1474 1493 dbg["revision"],
1475 1494 dbg["delta-base"],
1476 1495 dbg["using-cached-base"],
1477 1496 dbg["search_round_count"],
1478 1497 dbg["delta_try_count"],
1479 1498 dbg["type"],
1480 1499 dbg["snapshot-depth"],
1481 1500 dbg["p1-chain-len"],
1482 1501 dbg["p2-chain-len"],
1483 1502 dbg["duration"],
1484 1503 )
1485 1504 self._write_debug(msg)
1486 1505 return deltainfo
1487 1506
1488 1507
1489 1508 def delta_compression(default_compression_header, deltainfo):
1490 1509 """return (COMPRESSION_MODE, deltainfo)
1491 1510
1492 1511 used by revlog v2+ format to dispatch between PLAIN and DEFAULT
1493 1512 compression.
1494 1513 """
1495 1514 h, d = deltainfo.data
1496 1515 compression_mode = COMP_MODE_INLINE
1497 1516 if not h and not d:
1498 1517 # not data to store at all... declare them uncompressed
1499 1518 compression_mode = COMP_MODE_PLAIN
1500 1519 elif not h:
1501 1520 t = d[0:1]
1502 1521 if t == b'\0':
1503 1522 compression_mode = COMP_MODE_PLAIN
1504 1523 elif t == default_compression_header:
1505 1524 compression_mode = COMP_MODE_DEFAULT
1506 1525 elif h == b'u':
1507 1526 # we have a more efficient way to declare uncompressed
1508 1527 h = b''
1509 1528 compression_mode = COMP_MODE_PLAIN
1510 1529 deltainfo = drop_u_compression(deltainfo)
1511 1530 return compression_mode, deltainfo
@@ -1,955 +1,960 b''
1 1 # transaction.py - simple journaling scheme for mercurial
2 2 #
3 3 # This transaction scheme is intended to gracefully handle program
4 4 # errors and interruptions. More serious failures like system crashes
5 5 # can be recovered with an fsck-like tool. As the whole repository is
6 6 # effectively log-structured, this should amount to simply truncating
7 7 # anything that isn't referenced in the changelog.
8 8 #
9 9 # Copyright 2005, 2006 Olivia Mackall <olivia@selenic.com>
10 10 #
11 11 # This software may be used and distributed according to the terms of the
12 12 # GNU General Public License version 2 or any later version.
13 13
14 14 import errno
15 15 import os
16 16
17 17 from .i18n import _
18 18 from . import (
19 19 error,
20 20 pycompat,
21 21 util,
22 22 )
23 23 from .utils import stringutil
24 24
25 25 version = 2
26 26
27 27 GEN_GROUP_ALL = b'all'
28 28 GEN_GROUP_PRE_FINALIZE = b'prefinalize'
29 29 GEN_GROUP_POST_FINALIZE = b'postfinalize'
30 30
31 31
32 32 def active(func):
33 33 def _active(self, *args, **kwds):
34 34 if self._count == 0:
35 35 raise error.ProgrammingError(
36 36 b'cannot use transaction when it is already committed/aborted'
37 37 )
38 38 return func(self, *args, **kwds)
39 39
40 40 return _active
41 41
42 42
43 43 UNDO_BACKUP = b'%s.backupfiles'
44 44
45 45 UNDO_FILES_MAY_NEED_CLEANUP = [
46 46 # legacy entries that might exists on disk from previous version:
47 47 (b'store', b'%s.narrowspec'),
48 48 (b'plain', b'%s.narrowspec.dirstate'),
49 49 (b'plain', b'%s.branch'),
50 50 (b'plain', b'%s.bookmarks'),
51 51 (b'store', b'%s.phaseroots'),
52 52 (b'plain', b'%s.dirstate'),
53 53 # files actually in uses today:
54 54 (b'plain', b'%s.desc'),
55 55 # Always delete undo last to make sure we detect that a clean up is needed if
56 56 # the process is interrupted.
57 57 (b'store', b'%s'),
58 58 ]
59 59
60 60
61 61 def cleanup_undo_files(report, vfsmap, undo_prefix=b'undo'):
62 62 """remove "undo" files used by the rollback logic
63 63
64 64 This is useful to prevent rollback running in situation were it does not
65 65 make sense. For example after a strip.
66 66 """
67 67 backup_listing = UNDO_BACKUP % undo_prefix
68 68
69 69 backup_entries = []
70 70 undo_files = []
71 71 svfs = vfsmap[b'store']
72 72 try:
73 73 with svfs(backup_listing) as f:
74 74 backup_entries = read_backup_files(report, f)
75 75 except OSError as e:
76 76 if e.errno != errno.ENOENT:
77 77 msg = _(b'could not read %s: %s\n')
78 78 msg %= (svfs.join(backup_listing), stringutil.forcebytestr(e))
79 79 report(msg)
80 80
81 81 for location, f, backup_path, c in backup_entries:
82 82 if location in vfsmap and backup_path:
83 83 undo_files.append((vfsmap[location], backup_path))
84 84
85 85 undo_files.append((svfs, backup_listing))
86 86 for location, undo_path in UNDO_FILES_MAY_NEED_CLEANUP:
87 87 undo_files.append((vfsmap[location], undo_path % undo_prefix))
88 88 for undovfs, undofile in undo_files:
89 89 try:
90 90 undovfs.unlink(undofile)
91 91 except OSError as e:
92 92 if e.errno != errno.ENOENT:
93 93 msg = _(b'error removing %s: %s\n')
94 94 msg %= (undovfs.join(undofile), stringutil.forcebytestr(e))
95 95 report(msg)
96 96
97 97
98 98 def _playback(
99 99 journal,
100 100 report,
101 101 opener,
102 102 vfsmap,
103 103 entries,
104 104 backupentries,
105 105 unlink=True,
106 106 checkambigfiles=None,
107 107 ):
108 108 """rollback a transaction :
109 109 - truncate files that have been appended to
110 110 - restore file backups
111 111 - delete temporary files
112 112 """
113 113 backupfiles = []
114 114
115 115 def restore_one_backup(vfs, f, b, checkambig):
116 116 filepath = vfs.join(f)
117 117 backuppath = vfs.join(b)
118 118 try:
119 119 util.copyfile(backuppath, filepath, checkambig=checkambig)
120 120 backupfiles.append((vfs, b))
121 121 except IOError as exc:
122 122 e_msg = stringutil.forcebytestr(exc)
123 123 report(_(b"failed to recover %s (%s)\n") % (f, e_msg))
124 124 raise
125 125
126 126 # gather all backup files that impact the store
127 127 # (we need this to detect files that are both backed up and truncated)
128 128 store_backup = {}
129 129 for entry in backupentries:
130 130 location, file_path, backup_path, cache = entry
131 131 vfs = vfsmap[location]
132 132 is_store = vfs.join(b'') == opener.join(b'')
133 133 if is_store and file_path and backup_path:
134 134 store_backup[file_path] = entry
135 135 copy_done = set()
136 136
137 137 # truncate all file `f` to offset `o`
138 138 for f, o in sorted(dict(entries).items()):
139 139 # if we have a backup for `f`, we should restore it first and truncate
140 140 # the restored file
141 141 bck_entry = store_backup.get(f)
142 142 if bck_entry is not None:
143 143 location, file_path, backup_path, cache = bck_entry
144 144 checkambig = False
145 145 if checkambigfiles:
146 146 checkambig = (file_path, location) in checkambigfiles
147 147 restore_one_backup(opener, file_path, backup_path, checkambig)
148 148 copy_done.add(bck_entry)
149 149 # truncate the file to its pre-transaction size
150 150 if o or not unlink:
151 151 checkambig = checkambigfiles and (f, b'') in checkambigfiles
152 152 try:
153 153 fp = opener(f, b'a', checkambig=checkambig)
154 154 if fp.tell() < o:
155 155 raise error.Abort(
156 156 _(
157 157 b"attempted to truncate %s to %d bytes, but it was "
158 158 b"already %d bytes\n"
159 159 )
160 160 % (f, o, fp.tell())
161 161 )
162 162 fp.truncate(o)
163 163 fp.close()
164 164 except IOError:
165 165 report(_(b"failed to truncate %s\n") % f)
166 166 raise
167 167 else:
168 168 # delete empty file
169 169 try:
170 170 opener.unlink(f)
171 171 except FileNotFoundError:
172 172 pass
173 173 # restore backed up files and clean up temporary files
174 174 for entry in backupentries:
175 175 if entry in copy_done:
176 176 continue
177 177 l, f, b, c = entry
178 178 if l not in vfsmap and c:
179 179 report(b"couldn't handle %s: unknown cache location %s\n" % (b, l))
180 180 vfs = vfsmap[l]
181 181 try:
182 182 checkambig = checkambigfiles and (f, l) in checkambigfiles
183 183 if f and b:
184 184 restore_one_backup(vfs, f, b, checkambig)
185 185 else:
186 186 target = f or b
187 187 try:
188 188 vfs.unlink(target)
189 189 except FileNotFoundError:
190 190 # This is fine because
191 191 #
192 192 # either we are trying to delete the main file, and it is
193 193 # already deleted.
194 194 #
195 195 # or we are trying to delete a temporary file and it is
196 196 # already deleted.
197 197 #
198 198 # in both case, our target result (delete the file) is
199 199 # already achieved.
200 200 pass
201 201 except (IOError, OSError, error.Abort):
202 202 if not c:
203 203 raise
204 204
205 205 # cleanup transaction state file and the backups file
206 206 backuppath = b"%s.backupfiles" % journal
207 207 if opener.exists(backuppath):
208 208 opener.unlink(backuppath)
209 209 opener.unlink(journal)
210 210 try:
211 211 for vfs, f in backupfiles:
212 212 if vfs.exists(f):
213 213 vfs.unlink(f)
214 214 except (IOError, OSError, error.Abort):
215 215 # only pure backup file remains, it is sage to ignore any error
216 216 pass
217 217
218 218
219 219 class transaction(util.transactional):
220 220 def __init__(
221 221 self,
222 222 report,
223 223 opener,
224 224 vfsmap,
225 225 journalname,
226 226 undoname=None,
227 227 after=None,
228 228 createmode=None,
229 229 validator=None,
230 230 releasefn=None,
231 231 checkambigfiles=None,
232 232 name='<unnamed>',
233 233 ):
234 234 """Begin a new transaction
235 235
236 236 Begins a new transaction that allows rolling back writes in the event of
237 237 an exception.
238 238
239 239 * `after`: called after the transaction has been committed
240 240 * `createmode`: the mode of the journal file that will be created
241 241 * `releasefn`: called after releasing (with transaction and result)
242 242
243 243 `checkambigfiles` is a set of (path, vfs-location) tuples,
244 244 which determine whether file stat ambiguity should be avoided
245 245 for corresponded files.
246 246 """
247 247 self._count = 1
248 248 self._usages = 1
249 249 self._report = report
250 250 # a vfs to the store content
251 251 self._opener = opener
252 252 # a map to access file in various {location -> vfs}
253 253 vfsmap = vfsmap.copy()
254 254 vfsmap[b''] = opener # set default value
255 255 self._vfsmap = vfsmap
256 256 self._after = after
257 257 self._offsetmap = {}
258 258 self._newfiles = set()
259 259 self._journal = journalname
260 260 self._journal_files = []
261 261 self._undoname = undoname
262 262 self._queue = []
263 263 # A callback to do something just after releasing transaction.
264 264 if releasefn is None:
265 265 releasefn = lambda tr, success: None
266 266 self._releasefn = releasefn
267 267
268 268 self._checkambigfiles = set()
269 269 if checkambigfiles:
270 270 self._checkambigfiles.update(checkambigfiles)
271 271
272 272 self._names = [name]
273 273
274 274 # A dict dedicated to precisely tracking the changes introduced in the
275 275 # transaction.
276 276 self.changes = {}
277 277
278 278 # a dict of arguments to be passed to hooks
279 279 self.hookargs = {}
280 280 self._file = opener.open(self._journal, b"w+")
281 281
282 282 # a list of ('location', 'path', 'backuppath', cache) entries.
283 283 # - if 'backuppath' is empty, no file existed at backup time
284 284 # - if 'path' is empty, this is a temporary transaction file
285 285 # - if 'location' is not empty, the path is outside main opener reach.
286 286 # use 'location' value as a key in a vfsmap to find the right 'vfs'
287 287 # (cache is currently unused)
288 288 self._backupentries = []
289 289 self._backupmap = {}
290 290 self._backupjournal = b"%s.backupfiles" % self._journal
291 291 self._backupsfile = opener.open(self._backupjournal, b'w')
292 292 self._backupsfile.write(b'%d\n' % version)
293 293
294 294 if createmode is not None:
295 295 opener.chmod(self._journal, createmode & 0o666)
296 296 opener.chmod(self._backupjournal, createmode & 0o666)
297 297
298 298 # hold file generations to be performed on commit
299 299 self._filegenerators = {}
300 300 # hold callback to write pending data for hooks
301 301 self._pendingcallback = {}
302 302 # True is any pending data have been written ever
303 303 self._anypending = False
304 304 # holds callback to call when writing the transaction
305 305 self._finalizecallback = {}
306 306 # holds callback to call when validating the transaction
307 307 # should raise exception if anything is wrong
308 308 self._validatecallback = {}
309 309 if validator is not None:
310 310 self._validatecallback[b'001-userhooks'] = validator
311 311 # hold callback for post transaction close
312 312 self._postclosecallback = {}
313 313 # holds callbacks to call during abort
314 314 self._abortcallback = {}
315 315
316 316 def __repr__(self):
317 317 name = b'/'.join(self._names)
318 318 return '<transaction name=%s, count=%d, usages=%d>' % (
319 319 name,
320 320 self._count,
321 321 self._usages,
322 322 )
323 323
324 324 def __del__(self):
325 325 if self._journal:
326 326 self._abort()
327 327
328 328 @property
329 329 def finalized(self):
330 330 return self._finalizecallback is None
331 331
332 332 @active
333 333 def startgroup(self):
334 334 """delay registration of file entry
335 335
336 336 This is used by strip to delay vision of strip offset. The transaction
337 337 sees either none or all of the strip actions to be done."""
338 338 self._queue.append([])
339 339
340 340 @active
341 341 def endgroup(self):
342 342 """apply delayed registration of file entry.
343 343
344 344 This is used by strip to delay vision of strip offset. The transaction
345 345 sees either none or all of the strip actions to be done."""
346 346 q = self._queue.pop()
347 347 for f, o in q:
348 348 self._addentry(f, o)
349 349
350 350 @active
351 351 def add(self, file, offset):
352 352 """record the state of an append-only file before update"""
353 353 if (
354 354 file in self._newfiles
355 355 or file in self._offsetmap
356 356 or file in self._backupmap
357 357 ):
358 358 return
359 359 if self._queue:
360 360 self._queue[-1].append((file, offset))
361 361 return
362 362
363 363 self._addentry(file, offset)
364 364
365 365 def _addentry(self, file, offset):
366 366 """add a append-only entry to memory and on-disk state"""
367 367 if (
368 368 file in self._newfiles
369 369 or file in self._offsetmap
370 370 or file in self._backupmap
371 371 ):
372 372 return
373 373 if offset:
374 374 self._offsetmap[file] = offset
375 375 else:
376 376 self._newfiles.add(file)
377 377 # add enough data to the journal to do the truncate
378 378 self._file.write(b"%s\0%d\n" % (file, offset))
379 379 self._file.flush()
380 380
381 381 @active
382 382 def addbackup(self, file, hardlink=True, location=b'', for_offset=False):
383 383 """Adds a backup of the file to the transaction
384 384
385 385 Calling addbackup() creates a hardlink backup of the specified file
386 386 that is used to recover the file in the event of the transaction
387 387 aborting.
388 388
389 389 * `file`: the file path, relative to .hg/store
390 390 * `hardlink`: use a hardlink to quickly create the backup
391 391
392 392 If `for_offset` is set, we expect a offset for this file to have been previously recorded
393 393 """
394 394 if self._queue:
395 395 msg = b'cannot use transaction.addbackup inside "group"'
396 396 raise error.ProgrammingError(msg)
397 397
398 398 if file in self._newfiles or file in self._backupmap:
399 399 return
400 400 elif file in self._offsetmap and not for_offset:
401 401 return
402 402 elif for_offset and file not in self._offsetmap:
403 403 msg = (
404 404 'calling `addbackup` with `for_offmap=True`, '
405 405 'but no offset recorded: [%r] %r'
406 406 )
407 407 msg %= (location, file)
408 408 raise error.ProgrammingError(msg)
409 409
410 410 vfs = self._vfsmap[location]
411 411 dirname, filename = vfs.split(file)
412 412 backupfilename = b"%s.backup.%s" % (self._journal, filename)
413 413 backupfile = vfs.reljoin(dirname, backupfilename)
414 414 if vfs.exists(file):
415 415 filepath = vfs.join(file)
416 416 backuppath = vfs.join(backupfile)
417 # store encoding may result in different directory here.
418 # so we have to ensure the destination directory exist
419 final_dir_name = os.path.dirname(backuppath)
420 util.makedirs(final_dir_name, mode=vfs.createmode, notindexed=True)
421 # then we can copy the backup
417 422 util.copyfile(filepath, backuppath, hardlink=hardlink)
418 423 else:
419 424 backupfile = b''
420 425
421 426 self._addbackupentry((location, file, backupfile, False))
422 427
423 428 def _addbackupentry(self, entry):
424 429 """register a new backup entry and write it to disk"""
425 430 self._backupentries.append(entry)
426 431 self._backupmap[entry[1]] = len(self._backupentries) - 1
427 432 self._backupsfile.write(b"%s\0%s\0%s\0%d\n" % entry)
428 433 self._backupsfile.flush()
429 434
430 435 @active
431 436 def registertmp(self, tmpfile, location=b''):
432 437 """register a temporary transaction file
433 438
434 439 Such files will be deleted when the transaction exits (on both
435 440 failure and success).
436 441 """
437 442 self._addbackupentry((location, b'', tmpfile, False))
438 443
439 444 @active
440 445 def addfilegenerator(
441 446 self,
442 447 genid,
443 448 filenames,
444 449 genfunc,
445 450 order=0,
446 451 location=b'',
447 452 post_finalize=False,
448 453 ):
449 454 """add a function to generates some files at transaction commit
450 455
451 456 The `genfunc` argument is a function capable of generating proper
452 457 content of each entry in the `filename` tuple.
453 458
454 459 At transaction close time, `genfunc` will be called with one file
455 460 object argument per entries in `filenames`.
456 461
457 462 The transaction itself is responsible for the backup, creation and
458 463 final write of such file.
459 464
460 465 The `genid` argument is used to ensure the same set of file is only
461 466 generated once. Call to `addfilegenerator` for a `genid` already
462 467 present will overwrite the old entry.
463 468
464 469 The `order` argument may be used to control the order in which multiple
465 470 generator will be executed.
466 471
467 472 The `location` arguments may be used to indicate the files are located
468 473 outside of the the standard directory for transaction. It should match
469 474 one of the key of the `transaction.vfsmap` dictionary.
470 475
471 476 The `post_finalize` argument can be set to `True` for file generation
472 477 that must be run after the transaction has been finalized.
473 478 """
474 479 # For now, we are unable to do proper backup and restore of custom vfs
475 480 # but for bookmarks that are handled outside this mechanism.
476 481 entry = (order, filenames, genfunc, location, post_finalize)
477 482 self._filegenerators[genid] = entry
478 483
479 484 @active
480 485 def removefilegenerator(self, genid):
481 486 """reverse of addfilegenerator, remove a file generator function"""
482 487 if genid in self._filegenerators:
483 488 del self._filegenerators[genid]
484 489
485 490 def _generatefiles(self, suffix=b'', group=GEN_GROUP_ALL):
486 491 # write files registered for generation
487 492 any = False
488 493
489 494 if group == GEN_GROUP_ALL:
490 495 skip_post = skip_pre = False
491 496 else:
492 497 skip_pre = group == GEN_GROUP_POST_FINALIZE
493 498 skip_post = group == GEN_GROUP_PRE_FINALIZE
494 499
495 500 for id, entry in sorted(self._filegenerators.items()):
496 501 any = True
497 502 order, filenames, genfunc, location, post_finalize = entry
498 503
499 504 # for generation at closing, check if it's before or after finalize
500 505 if skip_post and post_finalize:
501 506 continue
502 507 elif skip_pre and not post_finalize:
503 508 continue
504 509
505 510 vfs = self._vfsmap[location]
506 511 files = []
507 512 try:
508 513 for name in filenames:
509 514 name += suffix
510 515 if suffix:
511 516 self.registertmp(name, location=location)
512 517 checkambig = False
513 518 else:
514 519 self.addbackup(name, location=location)
515 520 checkambig = (name, location) in self._checkambigfiles
516 521 files.append(
517 522 vfs(name, b'w', atomictemp=True, checkambig=checkambig)
518 523 )
519 524 genfunc(*files)
520 525 for f in files:
521 526 f.close()
522 527 # skip discard() loop since we're sure no open file remains
523 528 del files[:]
524 529 finally:
525 530 for f in files:
526 531 f.discard()
527 532 return any
528 533
529 534 @active
530 535 def findoffset(self, file):
531 536 if file in self._newfiles:
532 537 return 0
533 538 return self._offsetmap.get(file)
534 539
535 540 @active
536 541 def readjournal(self):
537 542 self._file.seek(0)
538 543 entries = []
539 544 for l in self._file.readlines():
540 545 file, troffset = l.split(b'\0')
541 546 entries.append((file, int(troffset)))
542 547 return entries
543 548
544 549 @active
545 550 def replace(self, file, offset):
546 551 """
547 552 replace can only replace already committed entries
548 553 that are not pending in the queue
549 554 """
550 555 if file in self._newfiles:
551 556 if not offset:
552 557 return
553 558 self._newfiles.remove(file)
554 559 self._offsetmap[file] = offset
555 560 elif file in self._offsetmap:
556 561 if not offset:
557 562 del self._offsetmap[file]
558 563 self._newfiles.add(file)
559 564 else:
560 565 self._offsetmap[file] = offset
561 566 else:
562 567 raise KeyError(file)
563 568 self._file.write(b"%s\0%d\n" % (file, offset))
564 569 self._file.flush()
565 570
566 571 @active
567 572 def nest(self, name='<unnamed>'):
568 573 self._count += 1
569 574 self._usages += 1
570 575 self._names.append(name)
571 576 return self
572 577
573 578 def release(self):
574 579 if self._count > 0:
575 580 self._usages -= 1
576 581 if self._names:
577 582 self._names.pop()
578 583 # if the transaction scopes are left without being closed, fail
579 584 if self._count > 0 and self._usages == 0:
580 585 self._abort()
581 586
582 587 def running(self):
583 588 return self._count > 0
584 589
585 590 def addpending(self, category, callback):
586 591 """add a callback to be called when the transaction is pending
587 592
588 593 The transaction will be given as callback's first argument.
589 594
590 595 Category is a unique identifier to allow overwriting an old callback
591 596 with a newer callback.
592 597 """
593 598 self._pendingcallback[category] = callback
594 599
595 600 @active
596 601 def writepending(self):
597 602 """write pending file to temporary version
598 603
599 604 This is used to allow hooks to view a transaction before commit"""
600 605 categories = sorted(self._pendingcallback)
601 606 for cat in categories:
602 607 # remove callback since the data will have been flushed
603 608 any = self._pendingcallback.pop(cat)(self)
604 609 self._anypending = self._anypending or any
605 610 self._anypending |= self._generatefiles(suffix=b'.pending')
606 611 return self._anypending
607 612
608 613 @active
609 614 def hasfinalize(self, category):
610 615 """check is a callback already exist for a category"""
611 616 return category in self._finalizecallback
612 617
613 618 @active
614 619 def addfinalize(self, category, callback):
615 620 """add a callback to be called when the transaction is closed
616 621
617 622 The transaction will be given as callback's first argument.
618 623
619 624 Category is a unique identifier to allow overwriting old callbacks with
620 625 newer callbacks.
621 626 """
622 627 self._finalizecallback[category] = callback
623 628
624 629 @active
625 630 def addpostclose(self, category, callback):
626 631 """add or replace a callback to be called after the transaction closed
627 632
628 633 The transaction will be given as callback's first argument.
629 634
630 635 Category is a unique identifier to allow overwriting an old callback
631 636 with a newer callback.
632 637 """
633 638 self._postclosecallback[category] = callback
634 639
635 640 @active
636 641 def getpostclose(self, category):
637 642 """return a postclose callback added before, or None"""
638 643 return self._postclosecallback.get(category, None)
639 644
640 645 @active
641 646 def addabort(self, category, callback):
642 647 """add a callback to be called when the transaction is aborted.
643 648
644 649 The transaction will be given as the first argument to the callback.
645 650
646 651 Category is a unique identifier to allow overwriting an old callback
647 652 with a newer callback.
648 653 """
649 654 self._abortcallback[category] = callback
650 655
651 656 @active
652 657 def addvalidator(self, category, callback):
653 658 """adds a callback to be called when validating the transaction.
654 659
655 660 The transaction will be given as the first argument to the callback.
656 661
657 662 callback should raise exception if to abort transaction"""
658 663 self._validatecallback[category] = callback
659 664
660 665 @active
661 666 def close(self):
662 667 '''commit the transaction'''
663 668 if self._count == 1:
664 669 for category in sorted(self._validatecallback):
665 670 self._validatecallback[category](self)
666 671 self._validatecallback = None # Help prevent cycles.
667 672 self._generatefiles(group=GEN_GROUP_PRE_FINALIZE)
668 673 while self._finalizecallback:
669 674 callbacks = self._finalizecallback
670 675 self._finalizecallback = {}
671 676 categories = sorted(callbacks)
672 677 for cat in categories:
673 678 callbacks[cat](self)
674 679 # Prevent double usage and help clear cycles.
675 680 self._finalizecallback = None
676 681 self._generatefiles(group=GEN_GROUP_POST_FINALIZE)
677 682
678 683 self._count -= 1
679 684 if self._count != 0:
680 685 return
681 686 self._file.close()
682 687 self._backupsfile.close()
683 688 # cleanup temporary files
684 689 for l, f, b, c in self._backupentries:
685 690 if l not in self._vfsmap and c:
686 691 self._report(
687 692 b"couldn't remove %s: unknown cache location %s\n" % (b, l)
688 693 )
689 694 continue
690 695 vfs = self._vfsmap[l]
691 696 if not f and b and vfs.exists(b):
692 697 try:
693 698 vfs.unlink(b)
694 699 except (IOError, OSError, error.Abort) as inst:
695 700 if not c:
696 701 raise
697 702 # Abort may be raise by read only opener
698 703 self._report(
699 704 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
700 705 )
701 706 self._offsetmap = {}
702 707 self._newfiles = set()
703 708 self._writeundo()
704 709 if self._after:
705 710 self._after()
706 711 self._after = None # Help prevent cycles.
707 712 if self._opener.isfile(self._backupjournal):
708 713 self._opener.unlink(self._backupjournal)
709 714 if self._opener.isfile(self._journal):
710 715 self._opener.unlink(self._journal)
711 716 for l, _f, b, c in self._backupentries:
712 717 if l not in self._vfsmap and c:
713 718 self._report(
714 719 b"couldn't remove %s: unknown cache location"
715 720 b"%s\n" % (b, l)
716 721 )
717 722 continue
718 723 vfs = self._vfsmap[l]
719 724 if b and vfs.exists(b):
720 725 try:
721 726 vfs.unlink(b)
722 727 except (IOError, OSError, error.Abort) as inst:
723 728 if not c:
724 729 raise
725 730 # Abort may be raise by read only opener
726 731 self._report(
727 732 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
728 733 )
729 734 self._backupentries = []
730 735 self._journal = None
731 736
732 737 self._releasefn(self, True) # notify success of closing transaction
733 738 self._releasefn = None # Help prevent cycles.
734 739
735 740 # run post close action
736 741 categories = sorted(self._postclosecallback)
737 742 for cat in categories:
738 743 self._postclosecallback[cat](self)
739 744 # Prevent double usage and help clear cycles.
740 745 self._postclosecallback = None
741 746
742 747 @active
743 748 def abort(self):
744 749 """abort the transaction (generally called on error, or when the
745 750 transaction is not explicitly committed before going out of
746 751 scope)"""
747 752 self._abort()
748 753
749 754 @active
750 755 def add_journal(self, vfs_id, path):
751 756 self._journal_files.append((vfs_id, path))
752 757
753 758 def _writeundo(self):
754 759 """write transaction data for possible future undo call"""
755 760 if self._undoname is None:
756 761 return
757 762 cleanup_undo_files(
758 763 self._report,
759 764 self._vfsmap,
760 765 undo_prefix=self._undoname,
761 766 )
762 767
763 768 def undoname(fn: bytes) -> bytes:
764 769 base, name = os.path.split(fn)
765 770 assert name.startswith(self._journal)
766 771 new_name = name.replace(self._journal, self._undoname, 1)
767 772 return os.path.join(base, new_name)
768 773
769 774 undo_backup_path = b"%s.backupfiles" % self._undoname
770 775 undobackupfile = self._opener.open(undo_backup_path, b'w')
771 776 undobackupfile.write(b'%d\n' % version)
772 777 for l, f, b, c in self._backupentries:
773 778 if not f: # temporary file
774 779 continue
775 780 if not b:
776 781 u = b''
777 782 else:
778 783 if l not in self._vfsmap and c:
779 784 self._report(
780 785 b"couldn't remove %s: unknown cache location"
781 786 b"%s\n" % (b, l)
782 787 )
783 788 continue
784 789 vfs = self._vfsmap[l]
785 790 u = undoname(b)
786 791 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True)
787 792 undobackupfile.write(b"%s\0%s\0%s\0%d\n" % (l, f, u, c))
788 793 undobackupfile.close()
789 794 for vfs, src in self._journal_files:
790 795 dest = undoname(src)
791 796 # if src and dest refer to a same file, vfs.rename is a no-op,
792 797 # leaving both src and dest on disk. delete dest to make sure
793 798 # the rename couldn't be such a no-op.
794 799 vfs.tryunlink(dest)
795 800 try:
796 801 vfs.rename(src, dest)
797 802 except FileNotFoundError: # journal file does not yet exist
798 803 pass
799 804
800 805 def _abort(self):
801 806 entries = self.readjournal()
802 807 self._count = 0
803 808 self._usages = 0
804 809 self._file.close()
805 810 self._backupsfile.close()
806 811
807 812 quick = self._can_quick_abort(entries)
808 813 try:
809 814 if not quick:
810 815 self._report(_(b"transaction abort!\n"))
811 816 for cat in sorted(self._abortcallback):
812 817 self._abortcallback[cat](self)
813 818 # Prevent double usage and help clear cycles.
814 819 self._abortcallback = None
815 820 if quick:
816 821 self._do_quick_abort(entries)
817 822 else:
818 823 self._do_full_abort(entries)
819 824 finally:
820 825 self._journal = None
821 826 self._releasefn(self, False) # notify failure of transaction
822 827 self._releasefn = None # Help prevent cycles.
823 828
824 829 def _can_quick_abort(self, entries):
825 830 """False if any semantic content have been written on disk
826 831
827 832 True if nothing, except temporary files has been writen on disk."""
828 833 if entries:
829 834 return False
830 835 for e in self._backupentries:
831 836 if e[1]:
832 837 return False
833 838 return True
834 839
835 840 def _do_quick_abort(self, entries):
836 841 """(Silently) do a quick cleanup (see _can_quick_abort)"""
837 842 assert self._can_quick_abort(entries)
838 843 tmp_files = [e for e in self._backupentries if not e[1]]
839 844 for vfs_id, old_path, tmp_path, xxx in tmp_files:
840 845 vfs = self._vfsmap[vfs_id]
841 846 try:
842 847 vfs.unlink(tmp_path)
843 848 except FileNotFoundError:
844 849 pass
845 850 if self._backupjournal:
846 851 self._opener.unlink(self._backupjournal)
847 852 if self._journal:
848 853 self._opener.unlink(self._journal)
849 854
850 855 def _do_full_abort(self, entries):
851 856 """(Noisily) rollback all the change introduced by the transaction"""
852 857 try:
853 858 _playback(
854 859 self._journal,
855 860 self._report,
856 861 self._opener,
857 862 self._vfsmap,
858 863 entries,
859 864 self._backupentries,
860 865 False,
861 866 checkambigfiles=self._checkambigfiles,
862 867 )
863 868 self._report(_(b"rollback completed\n"))
864 869 except BaseException as exc:
865 870 self._report(_(b"rollback failed - please run hg recover\n"))
866 871 self._report(
867 872 _(b"(failure reason: %s)\n") % stringutil.forcebytestr(exc)
868 873 )
869 874
870 875
871 876 BAD_VERSION_MSG = _(
872 877 b"journal was created by a different version of Mercurial\n"
873 878 )
874 879
875 880
876 881 def read_backup_files(report, fp):
877 882 """parse an (already open) backup file an return contained backup entries
878 883
879 884 entries are in the form: (location, file, backupfile, xxx)
880 885
881 886 :location: the vfs identifier (vfsmap's key)
882 887 :file: original file path (in the vfs)
883 888 :backupfile: path of the backup (in the vfs)
884 889 :cache: a boolean currently always set to False
885 890 """
886 891 lines = fp.readlines()
887 892 backupentries = []
888 893 if lines:
889 894 ver = lines[0][:-1]
890 895 if ver != (b'%d' % version):
891 896 report(BAD_VERSION_MSG)
892 897 else:
893 898 for line in lines[1:]:
894 899 if line:
895 900 # Shave off the trailing newline
896 901 line = line[:-1]
897 902 l, f, b, c = line.split(b'\0')
898 903 backupentries.append((l, f, b, bool(c)))
899 904 return backupentries
900 905
901 906
902 907 def rollback(
903 908 opener,
904 909 vfsmap,
905 910 file,
906 911 report,
907 912 checkambigfiles=None,
908 913 skip_journal_pattern=None,
909 914 ):
910 915 """Rolls back the transaction contained in the given file
911 916
912 917 Reads the entries in the specified file, and the corresponding
913 918 '*.backupfiles' file, to recover from an incomplete transaction.
914 919
915 920 * `file`: a file containing a list of entries, specifying where
916 921 to truncate each file. The file should contain a list of
917 922 file\0offset pairs, delimited by newlines. The corresponding
918 923 '*.backupfiles' file should contain a list of file\0backupfile
919 924 pairs, delimited by \0.
920 925
921 926 `checkambigfiles` is a set of (path, vfs-location) tuples,
922 927 which determine whether file stat ambiguity should be avoided at
923 928 restoring corresponded files.
924 929 """
925 930 entries = []
926 931 backupentries = []
927 932
928 933 with opener.open(file) as fp:
929 934 lines = fp.readlines()
930 935 for l in lines:
931 936 try:
932 937 f, o = l.split(b'\0')
933 938 entries.append((f, int(o)))
934 939 except ValueError:
935 940 report(
936 941 _(b"couldn't read journal entry %r!\n") % pycompat.bytestr(l)
937 942 )
938 943
939 944 backupjournal = b"%s.backupfiles" % file
940 945 if opener.exists(backupjournal):
941 946 with opener.open(backupjournal) as fp:
942 947 backupentries = read_backup_files(report, fp)
943 948 if skip_journal_pattern is not None:
944 949 keep = lambda x: not skip_journal_pattern.match(x[1])
945 950 backupentries = [x for x in backupentries if keep(x)]
946 951
947 952 _playback(
948 953 file,
949 954 report,
950 955 opener,
951 956 vfsmap,
952 957 entries,
953 958 backupentries,
954 959 checkambigfiles=checkambigfiles,
955 960 )
@@ -1,683 +1,689 b''
1 1 # upgrade.py - functions for in place upgrade of Mercurial repository
2 2 #
3 3 # Copyright (c) 2016-present, Gregory Szorc
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8
9 9 import stat
10 10
11 11 from ..i18n import _
12 12 from ..pycompat import getattr
13 13 from .. import (
14 14 changelog,
15 15 error,
16 16 filelog,
17 17 manifest,
18 18 metadata,
19 19 pycompat,
20 20 requirements,
21 21 scmutil,
22 22 store,
23 23 util,
24 24 vfs as vfsmod,
25 25 )
26 26 from ..revlogutils import (
27 27 constants as revlogconst,
28 28 flagutil,
29 29 nodemap,
30 30 sidedata as sidedatamod,
31 31 )
32 32 from . import actions as upgrade_actions
33 33
34 34
35 35 def get_sidedata_helpers(srcrepo, dstrepo):
36 36 use_w = srcrepo.ui.configbool(b'experimental', b'worker.repository-upgrade')
37 37 sequential = pycompat.iswindows or not use_w
38 38 if not sequential:
39 39 srcrepo.register_sidedata_computer(
40 40 revlogconst.KIND_CHANGELOG,
41 41 sidedatamod.SD_FILES,
42 42 (sidedatamod.SD_FILES,),
43 43 metadata._get_worker_sidedata_adder(srcrepo, dstrepo),
44 44 flagutil.REVIDX_HASCOPIESINFO,
45 45 replace=True,
46 46 )
47 47 return sidedatamod.get_sidedata_helpers(srcrepo, dstrepo._wanted_sidedata)
48 48
49 49
50 50 def _revlogfrompath(repo, rl_type, path):
51 51 """Obtain a revlog from a repo path.
52 52
53 53 An instance of the appropriate class is returned.
54 54 """
55 55 if rl_type & store.FILEFLAGS_CHANGELOG:
56 56 return changelog.changelog(repo.svfs)
57 57 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
58 58 mandir = b''
59 59 if b'/' in path:
60 60 mandir = path.rsplit(b'/', 1)[0]
61 61 return manifest.manifestrevlog(
62 62 repo.nodeconstants, repo.svfs, tree=mandir
63 63 )
64 64 else:
65 65 # drop the extension and the `data/` prefix
66 66 path_part = path.rsplit(b'.', 1)[0].split(b'/', 1)
67 67 if len(path_part) < 2:
68 68 msg = _(b'cannot recognize revlog from filename: %s')
69 69 msg %= path
70 70 raise error.Abort(msg)
71 71 path = path_part[1]
72 72 return filelog.filelog(repo.svfs, path)
73 73
74 74
75 75 def _copyrevlog(tr, destrepo, oldrl, rl_type, unencodedname):
76 76 """copy all relevant files for `oldrl` into `destrepo` store
77 77
78 78 Files are copied "as is" without any transformation. The copy is performed
79 79 without extra checks. Callers are responsible for making sure the copied
80 80 content is compatible with format of the destination repository.
81 81 """
82 82 oldrl = getattr(oldrl, '_revlog', oldrl)
83 83 newrl = _revlogfrompath(destrepo, rl_type, unencodedname)
84 84 newrl = getattr(newrl, '_revlog', newrl)
85 85
86 86 oldvfs = oldrl.opener
87 87 newvfs = newrl.opener
88 88 oldindex = oldvfs.join(oldrl._indexfile)
89 89 newindex = newvfs.join(newrl._indexfile)
90 90 olddata = oldvfs.join(oldrl._datafile)
91 91 newdata = newvfs.join(newrl._datafile)
92 92
93 93 with newvfs(newrl._indexfile, b'w'):
94 94 pass # create all the directories
95 95
96 96 util.copyfile(oldindex, newindex)
97 97 copydata = oldrl.opener.exists(oldrl._datafile)
98 98 if copydata:
99 99 util.copyfile(olddata, newdata)
100 100
101 101 if rl_type & store.FILEFLAGS_FILELOG:
102 102 destrepo.svfs.fncache.add(unencodedname)
103 103 if copydata:
104 104 destrepo.svfs.fncache.add(unencodedname[:-2] + b'.d')
105 105
106 106
107 107 UPGRADE_CHANGELOG = b"changelog"
108 108 UPGRADE_MANIFEST = b"manifest"
109 109 UPGRADE_FILELOGS = b"all-filelogs"
110 110
111 111 UPGRADE_ALL_REVLOGS = frozenset(
112 112 [UPGRADE_CHANGELOG, UPGRADE_MANIFEST, UPGRADE_FILELOGS]
113 113 )
114 114
115 115
116 116 def matchrevlog(revlogfilter, rl_type):
117 117 """check if a revlog is selected for cloning.
118 118
119 119 In other words, are there any updates which need to be done on revlog
120 120 or it can be blindly copied.
121 121
122 122 The store entry is checked against the passed filter"""
123 123 if rl_type & store.FILEFLAGS_CHANGELOG:
124 124 return UPGRADE_CHANGELOG in revlogfilter
125 125 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
126 126 return UPGRADE_MANIFEST in revlogfilter
127 127 assert rl_type & store.FILEFLAGS_FILELOG
128 128 return UPGRADE_FILELOGS in revlogfilter
129 129
130 130
131 131 def _perform_clone(
132 132 ui,
133 133 dstrepo,
134 134 tr,
135 135 old_revlog,
136 136 rl_type,
137 137 unencoded,
138 138 upgrade_op,
139 139 sidedata_helpers,
140 140 oncopiedrevision,
141 141 ):
142 142 """returns the new revlog object created"""
143 143 newrl = None
144 144 if matchrevlog(upgrade_op.revlogs_to_process, rl_type):
145 145 ui.note(
146 146 _(b'cloning %d revisions from %s\n') % (len(old_revlog), unencoded)
147 147 )
148 148 newrl = _revlogfrompath(dstrepo, rl_type, unencoded)
149 149 old_revlog.clone(
150 150 tr,
151 151 newrl,
152 152 addrevisioncb=oncopiedrevision,
153 153 deltareuse=upgrade_op.delta_reuse_mode,
154 154 forcedeltabothparents=upgrade_op.force_re_delta_both_parents,
155 155 sidedata_helpers=sidedata_helpers,
156 156 )
157 157 else:
158 158 msg = _(b'blindly copying %s containing %i revisions\n')
159 159 ui.note(msg % (unencoded, len(old_revlog)))
160 160 _copyrevlog(tr, dstrepo, old_revlog, rl_type, unencoded)
161 161
162 162 newrl = _revlogfrompath(dstrepo, rl_type, unencoded)
163 163 return newrl
164 164
165 165
166 166 def _clonerevlogs(
167 167 ui,
168 168 srcrepo,
169 169 dstrepo,
170 170 tr,
171 171 upgrade_op,
172 172 ):
173 173 """Copy revlogs between 2 repos."""
174 174 revcount = 0
175 175 srcsize = 0
176 176 srcrawsize = 0
177 177 dstsize = 0
178 178 fcount = 0
179 179 frevcount = 0
180 180 fsrcsize = 0
181 181 frawsize = 0
182 182 fdstsize = 0
183 183 mcount = 0
184 184 mrevcount = 0
185 185 msrcsize = 0
186 186 mrawsize = 0
187 187 mdstsize = 0
188 188 crevcount = 0
189 189 csrcsize = 0
190 190 crawsize = 0
191 191 cdstsize = 0
192 192
193 193 alldatafiles = list(srcrepo.store.walk())
194 194 # mapping of data files which needs to be cloned
195 195 # key is unencoded filename
196 196 # value is revlog_object_from_srcrepo
197 197 manifests = {}
198 198 changelogs = {}
199 199 filelogs = {}
200 200
201 201 # Perform a pass to collect metadata. This validates we can open all
202 202 # source files and allows a unified progress bar to be displayed.
203 203 for rl_type, unencoded, size in alldatafiles:
204 204 if not rl_type & store.FILEFLAGS_REVLOG_MAIN:
205 205 continue
206 206
207 207 # the store.walk function will wrongly pickup transaction backup and
208 208 # get confused. As a quick fix for 5.9 release, we ignore those.
209 209 # (this is not a module constants because it seems better to keep the
210 210 # hack together)
211 211 skip_undo = (
212 212 b'undo.backup.00changelog.i',
213 213 b'undo.backup.00manifest.i',
214 214 )
215 215 if unencoded in skip_undo:
216 216 continue
217 217
218 218 rl = _revlogfrompath(srcrepo, rl_type, unencoded)
219 219
220 220 info = rl.storageinfo(
221 221 exclusivefiles=True,
222 222 revisionscount=True,
223 223 trackedsize=True,
224 224 storedsize=True,
225 225 )
226 226
227 227 revcount += info[b'revisionscount'] or 0
228 228 datasize = info[b'storedsize'] or 0
229 229 rawsize = info[b'trackedsize'] or 0
230 230
231 231 srcsize += datasize
232 232 srcrawsize += rawsize
233 233
234 234 # This is for the separate progress bars.
235 235 if rl_type & store.FILEFLAGS_CHANGELOG:
236 236 changelogs[unencoded] = rl_type
237 237 crevcount += len(rl)
238 238 csrcsize += datasize
239 239 crawsize += rawsize
240 240 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
241 241 manifests[unencoded] = rl_type
242 242 mcount += 1
243 243 mrevcount += len(rl)
244 244 msrcsize += datasize
245 245 mrawsize += rawsize
246 246 elif rl_type & store.FILEFLAGS_FILELOG:
247 247 filelogs[unencoded] = rl_type
248 248 fcount += 1
249 249 frevcount += len(rl)
250 250 fsrcsize += datasize
251 251 frawsize += rawsize
252 252 else:
253 253 error.ProgrammingError(b'unknown revlog type')
254 254
255 255 if not revcount:
256 256 return
257 257
258 258 ui.status(
259 259 _(
260 260 b'migrating %d total revisions (%d in filelogs, %d in manifests, '
261 261 b'%d in changelog)\n'
262 262 )
263 263 % (revcount, frevcount, mrevcount, crevcount)
264 264 )
265 265 ui.status(
266 266 _(b'migrating %s in store; %s tracked data\n')
267 267 % ((util.bytecount(srcsize), util.bytecount(srcrawsize)))
268 268 )
269 269
270 270 # Used to keep track of progress.
271 271 progress = None
272 272
273 273 def oncopiedrevision(rl, rev, node):
274 274 progress.increment()
275 275
276 276 sidedata_helpers = get_sidedata_helpers(srcrepo, dstrepo)
277 277
278 278 # Migrating filelogs
279 279 ui.status(
280 280 _(
281 281 b'migrating %d filelogs containing %d revisions '
282 282 b'(%s in store; %s tracked data)\n'
283 283 )
284 284 % (
285 285 fcount,
286 286 frevcount,
287 287 util.bytecount(fsrcsize),
288 288 util.bytecount(frawsize),
289 289 )
290 290 )
291 291 progress = srcrepo.ui.makeprogress(_(b'file revisions'), total=frevcount)
292 292 for unencoded, rl_type in sorted(filelogs.items()):
293 293 oldrl = _revlogfrompath(srcrepo, rl_type, unencoded)
294 294
295 295 newrl = _perform_clone(
296 296 ui,
297 297 dstrepo,
298 298 tr,
299 299 oldrl,
300 300 rl_type,
301 301 unencoded,
302 302 upgrade_op,
303 303 sidedata_helpers,
304 304 oncopiedrevision,
305 305 )
306 306 info = newrl.storageinfo(storedsize=True)
307 307 fdstsize += info[b'storedsize'] or 0
308 308 ui.status(
309 309 _(
310 310 b'finished migrating %d filelog revisions across %d '
311 311 b'filelogs; change in size: %s\n'
312 312 )
313 313 % (frevcount, fcount, util.bytecount(fdstsize - fsrcsize))
314 314 )
315 315
316 316 # Migrating manifests
317 317 ui.status(
318 318 _(
319 319 b'migrating %d manifests containing %d revisions '
320 320 b'(%s in store; %s tracked data)\n'
321 321 )
322 322 % (
323 323 mcount,
324 324 mrevcount,
325 325 util.bytecount(msrcsize),
326 326 util.bytecount(mrawsize),
327 327 )
328 328 )
329 329 if progress:
330 330 progress.complete()
331 331 progress = srcrepo.ui.makeprogress(
332 332 _(b'manifest revisions'), total=mrevcount
333 333 )
334 334 for unencoded, rl_type in sorted(manifests.items()):
335 335 oldrl = _revlogfrompath(srcrepo, rl_type, unencoded)
336 336 newrl = _perform_clone(
337 337 ui,
338 338 dstrepo,
339 339 tr,
340 340 oldrl,
341 341 rl_type,
342 342 unencoded,
343 343 upgrade_op,
344 344 sidedata_helpers,
345 345 oncopiedrevision,
346 346 )
347 347 info = newrl.storageinfo(storedsize=True)
348 348 mdstsize += info[b'storedsize'] or 0
349 349 ui.status(
350 350 _(
351 351 b'finished migrating %d manifest revisions across %d '
352 352 b'manifests; change in size: %s\n'
353 353 )
354 354 % (mrevcount, mcount, util.bytecount(mdstsize - msrcsize))
355 355 )
356 356
357 357 # Migrating changelog
358 358 ui.status(
359 359 _(
360 360 b'migrating changelog containing %d revisions '
361 361 b'(%s in store; %s tracked data)\n'
362 362 )
363 363 % (
364 364 crevcount,
365 365 util.bytecount(csrcsize),
366 366 util.bytecount(crawsize),
367 367 )
368 368 )
369 369 if progress:
370 370 progress.complete()
371 371 progress = srcrepo.ui.makeprogress(
372 372 _(b'changelog revisions'), total=crevcount
373 373 )
374 374 for unencoded, rl_type in sorted(changelogs.items()):
375 375 oldrl = _revlogfrompath(srcrepo, rl_type, unencoded)
376 376 newrl = _perform_clone(
377 377 ui,
378 378 dstrepo,
379 379 tr,
380 380 oldrl,
381 381 rl_type,
382 382 unencoded,
383 383 upgrade_op,
384 384 sidedata_helpers,
385 385 oncopiedrevision,
386 386 )
387 387 info = newrl.storageinfo(storedsize=True)
388 388 cdstsize += info[b'storedsize'] or 0
389 389 progress.complete()
390 390 ui.status(
391 391 _(
392 392 b'finished migrating %d changelog revisions; change in size: '
393 393 b'%s\n'
394 394 )
395 395 % (crevcount, util.bytecount(cdstsize - csrcsize))
396 396 )
397 397
398 398 dstsize = fdstsize + mdstsize + cdstsize
399 399 ui.status(
400 400 _(
401 401 b'finished migrating %d total revisions; total change in store '
402 402 b'size: %s\n'
403 403 )
404 404 % (revcount, util.bytecount(dstsize - srcsize))
405 405 )
406 406
407 407
408 408 def _files_to_copy_post_revlog_clone(srcrepo):
409 409 """yields files which should be copied to destination after revlogs
410 410 are cloned"""
411 411 for path, kind, st in sorted(srcrepo.store.vfs.readdir(b'', stat=True)):
412 412 # don't copy revlogs as they are already cloned
413 413 if store.revlog_type(path) is not None:
414 414 continue
415 415 # Skip transaction related files.
416 416 if path.startswith(b'undo'):
417 417 continue
418 418 # Only copy regular files.
419 419 if kind != stat.S_IFREG:
420 420 continue
421 421 # Skip other skipped files.
422 422 if path in (b'lock', b'fncache'):
423 423 continue
424 424 # TODO: should we skip cache too?
425 425
426 426 yield path
427 427
428 428
429 429 def _replacestores(currentrepo, upgradedrepo, backupvfs, upgrade_op):
430 430 """Replace the stores after current repository is upgraded
431 431
432 432 Creates a backup of current repository store at backup path
433 433 Replaces upgraded store files in current repo from upgraded one
434 434
435 435 Arguments:
436 436 currentrepo: repo object of current repository
437 437 upgradedrepo: repo object of the upgraded data
438 438 backupvfs: vfs object for the backup path
439 439 upgrade_op: upgrade operation object
440 440 to be used to decide what all is upgraded
441 441 """
442 442 # TODO: don't blindly rename everything in store
443 443 # There can be upgrades where store is not touched at all
444 444 if upgrade_op.backup_store:
445 445 util.rename(currentrepo.spath, backupvfs.join(b'store'))
446 446 else:
447 447 currentrepo.vfs.rmtree(b'store', forcibly=True)
448 448 util.rename(upgradedrepo.spath, currentrepo.spath)
449 449
450 450
451 451 def finishdatamigration(ui, srcrepo, dstrepo, requirements):
452 452 """Hook point for extensions to perform additional actions during upgrade.
453 453
454 454 This function is called after revlogs and store files have been copied but
455 455 before the new store is swapped into the original location.
456 456 """
457 457
458 458
459 459 def upgrade(ui, srcrepo, dstrepo, upgrade_op):
460 460 """Do the low-level work of upgrading a repository.
461 461
462 462 The upgrade is effectively performed as a copy between a source
463 463 repository and a temporary destination repository.
464 464
465 465 The source repository is unmodified for as long as possible so the
466 466 upgrade can abort at any time without causing loss of service for
467 467 readers and without corrupting the source repository.
468 468 """
469 469 assert srcrepo.currentwlock()
470 470 assert dstrepo.currentwlock()
471 471 backuppath = None
472 472 backupvfs = None
473 473
474 474 ui.status(
475 475 _(
476 476 b'(it is safe to interrupt this process any time before '
477 477 b'data migration completes)\n'
478 478 )
479 479 )
480 480
481 481 if upgrade_actions.dirstatev2 in upgrade_op.upgrade_actions:
482 482 ui.status(_(b'upgrading to dirstate-v2 from v1\n'))
483 483 upgrade_dirstate(ui, srcrepo, upgrade_op, b'v1', b'v2')
484 484 upgrade_op.upgrade_actions.remove(upgrade_actions.dirstatev2)
485 485
486 486 if upgrade_actions.dirstatev2 in upgrade_op.removed_actions:
487 487 ui.status(_(b'downgrading from dirstate-v2 to v1\n'))
488 488 upgrade_dirstate(ui, srcrepo, upgrade_op, b'v2', b'v1')
489 489 upgrade_op.removed_actions.remove(upgrade_actions.dirstatev2)
490 490
491 491 if upgrade_actions.dirstatetrackedkey in upgrade_op.upgrade_actions:
492 492 ui.status(_(b'create dirstate-tracked-hint file\n'))
493 493 upgrade_tracked_hint(ui, srcrepo, upgrade_op, add=True)
494 494 upgrade_op.upgrade_actions.remove(upgrade_actions.dirstatetrackedkey)
495 495 elif upgrade_actions.dirstatetrackedkey in upgrade_op.removed_actions:
496 496 ui.status(_(b'remove dirstate-tracked-hint file\n'))
497 497 upgrade_tracked_hint(ui, srcrepo, upgrade_op, add=False)
498 498 upgrade_op.removed_actions.remove(upgrade_actions.dirstatetrackedkey)
499 499
500 500 if not (upgrade_op.upgrade_actions or upgrade_op.removed_actions):
501 501 return
502 502
503 503 if upgrade_op.requirements_only:
504 504 ui.status(_(b'upgrading repository requirements\n'))
505 505 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
506 506 # if there is only one action and that is persistent nodemap upgrade
507 507 # directly write the nodemap file and update requirements instead of going
508 508 # through the whole cloning process
509 509 elif (
510 510 len(upgrade_op.upgrade_actions) == 1
511 511 and b'persistent-nodemap' in upgrade_op.upgrade_actions_names
512 512 and not upgrade_op.removed_actions
513 513 ):
514 514 ui.status(
515 515 _(b'upgrading repository to use persistent nodemap feature\n')
516 516 )
517 517 with srcrepo.transaction(b'upgrade') as tr:
518 518 unfi = srcrepo.unfiltered()
519 519 cl = unfi.changelog
520 520 nodemap.persist_nodemap(tr, cl, force=True)
521 521 # we want to directly operate on the underlying revlog to force
522 522 # create a nodemap file. This is fine since this is upgrade code
523 523 # and it heavily relies on repository being revlog based
524 524 # hence accessing private attributes can be justified
525 525 nodemap.persist_nodemap(
526 526 tr, unfi.manifestlog._rootstore._revlog, force=True
527 527 )
528 528 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
529 529 elif (
530 530 len(upgrade_op.removed_actions) == 1
531 531 and [
532 532 x
533 533 for x in upgrade_op.removed_actions
534 534 if x.name == b'persistent-nodemap'
535 535 ]
536 536 and not upgrade_op.upgrade_actions
537 537 ):
538 538 ui.status(
539 539 _(b'downgrading repository to not use persistent nodemap feature\n')
540 540 )
541 541 with srcrepo.transaction(b'upgrade') as tr:
542 542 unfi = srcrepo.unfiltered()
543 543 cl = unfi.changelog
544 544 nodemap.delete_nodemap(tr, srcrepo, cl)
545 545 # check comment 20 lines above for accessing private attributes
546 546 nodemap.delete_nodemap(
547 547 tr, srcrepo, unfi.manifestlog._rootstore._revlog
548 548 )
549 549 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
550 550 else:
551 551 with dstrepo.transaction(b'upgrade') as tr:
552 552 _clonerevlogs(
553 553 ui,
554 554 srcrepo,
555 555 dstrepo,
556 556 tr,
557 557 upgrade_op,
558 558 )
559 559
560 560 # Now copy other files in the store directory.
561 561 for p in _files_to_copy_post_revlog_clone(srcrepo):
562 562 srcrepo.ui.status(_(b'copying %s\n') % p)
563 563 src = srcrepo.store.rawvfs.join(p)
564 564 dst = dstrepo.store.rawvfs.join(p)
565 565 util.copyfile(src, dst, copystat=True)
566 566
567 567 finishdatamigration(ui, srcrepo, dstrepo, requirements)
568 568
569 569 ui.status(_(b'data fully upgraded in a temporary repository\n'))
570 570
571 571 if upgrade_op.backup_store:
572 572 backuppath = pycompat.mkdtemp(
573 573 prefix=b'upgradebackup.', dir=srcrepo.path
574 574 )
575 575 backupvfs = vfsmod.vfs(backuppath)
576 576
577 577 # Make a backup of requires file first, as it is the first to be modified.
578 578 util.copyfile(
579 579 srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires')
580 580 )
581 581
582 582 # We install an arbitrary requirement that clients must not support
583 583 # as a mechanism to lock out new clients during the data swap. This is
584 584 # better than allowing a client to continue while the repository is in
585 585 # an inconsistent state.
586 586 ui.status(
587 587 _(
588 588 b'marking source repository as being upgraded; clients will be '
589 589 b'unable to read from repository\n'
590 590 )
591 591 )
592 592 scmutil.writereporequirements(
593 593 srcrepo, srcrepo.requirements | {b'upgradeinprogress'}
594 594 )
595 595
596 596 ui.status(_(b'starting in-place swap of repository data\n'))
597 597 if upgrade_op.backup_store:
598 598 ui.status(
599 599 _(b'replaced files will be backed up at %s\n') % backuppath
600 600 )
601 601
602 602 # Now swap in the new store directory. Doing it as a rename should make
603 603 # the operation nearly instantaneous and atomic (at least in well-behaved
604 604 # environments).
605 605 ui.status(_(b'replacing store...\n'))
606 606 tstart = util.timer()
607 607 _replacestores(srcrepo, dstrepo, backupvfs, upgrade_op)
608 608 elapsed = util.timer() - tstart
609 609 ui.status(
610 610 _(
611 611 b'store replacement complete; repository was inconsistent for '
612 612 b'%0.1fs\n'
613 613 )
614 614 % elapsed
615 615 )
616 616
617 617 # We first write the requirements file. Any new requirements will lock
618 618 # out legacy clients.
619 619 ui.status(
620 620 _(
621 621 b'finalizing requirements file and making repository readable '
622 622 b'again\n'
623 623 )
624 624 )
625 625 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
626 626
627 627 if upgrade_op.backup_store:
628 628 # The lock file from the old store won't be removed because nothing has a
629 629 # reference to its new location. So clean it up manually. Alternatively, we
630 630 # could update srcrepo.svfs and other variables to point to the new
631 631 # location. This is simpler.
632 632 assert backupvfs is not None # help pytype
633 633 backupvfs.unlink(b'store/lock')
634 634
635 635 return backuppath
636 636
637 637
638 638 def upgrade_dirstate(ui, srcrepo, upgrade_op, old, new):
639 639 if upgrade_op.backup_store:
640 640 backuppath = pycompat.mkdtemp(
641 641 prefix=b'upgradebackup.', dir=srcrepo.path
642 642 )
643 643 ui.status(_(b'replaced files will be backed up at %s\n') % backuppath)
644 644 backupvfs = vfsmod.vfs(backuppath)
645 645 util.copyfile(
646 646 srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires')
647 647 )
648 648 try:
649 649 util.copyfile(
650 650 srcrepo.vfs.join(b'dirstate'), backupvfs.join(b'dirstate')
651 651 )
652 652 except FileNotFoundError:
653 653 # The dirstate does not exist on an empty repo or a repo with no
654 654 # revision checked out
655 655 pass
656 656
657 657 assert srcrepo.dirstate._use_dirstate_v2 == (old == b'v2')
658 use_v2 = new == b'v2'
659 if use_v2:
660 # Write the requirements *before* upgrading
661 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
662
658 663 srcrepo.dirstate._map.preload()
659 srcrepo.dirstate._use_dirstate_v2 = new == b'v2'
660 srcrepo.dirstate._map._use_dirstate_v2 = srcrepo.dirstate._use_dirstate_v2
664 srcrepo.dirstate._use_dirstate_v2 = use_v2
665 srcrepo.dirstate._map._use_dirstate_v2 = use_v2
661 666 srcrepo.dirstate._dirty = True
662 667 try:
663 668 srcrepo.vfs.unlink(b'dirstate')
664 669 except FileNotFoundError:
665 670 # The dirstate does not exist on an empty repo or a repo with no
666 671 # revision checked out
667 672 pass
668 673
669 674 srcrepo.dirstate.write(None)
670
671 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
675 if not use_v2:
676 # Remove the v2 requirement *after* downgrading
677 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
672 678
673 679
674 680 def upgrade_tracked_hint(ui, srcrepo, upgrade_op, add):
675 681 if add:
676 682 srcrepo.dirstate._use_tracked_hint = True
677 683 srcrepo.dirstate._dirty = True
678 684 srcrepo.dirstate._dirty_tracked_set = True
679 685 srcrepo.dirstate.write(None)
680 686 if not add:
681 687 srcrepo.dirstate.delete_tracked_hint()
682 688
683 689 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
@@ -1,813 +1,817 b''
1 1 # vfs.py - Mercurial 'vfs' classes
2 2 #
3 3 # Copyright Olivia Mackall <olivia@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import contextlib
9 9 import os
10 10 import shutil
11 11 import stat
12 12 import threading
13 13
14 14 from typing import (
15 15 Optional,
16 16 )
17 17
18 18 from .i18n import _
19 19 from .pycompat import (
20 20 delattr,
21 21 getattr,
22 22 setattr,
23 23 )
24 24 from . import (
25 25 encoding,
26 26 error,
27 27 pathutil,
28 28 pycompat,
29 29 util,
30 30 )
31 31
32 32
33 33 def _avoidambig(path: bytes, oldstat):
34 34 """Avoid file stat ambiguity forcibly
35 35
36 36 This function causes copying ``path`` file, if it is owned by
37 37 another (see issue5418 and issue5584 for detail).
38 38 """
39 39
40 40 def checkandavoid():
41 41 newstat = util.filestat.frompath(path)
42 42 # return whether file stat ambiguity is (already) avoided
43 43 return not newstat.isambig(oldstat) or newstat.avoidambig(path, oldstat)
44 44
45 45 if not checkandavoid():
46 46 # simply copy to change owner of path to get privilege to
47 47 # advance mtime (see issue5418)
48 48 util.rename(util.mktempcopy(path), path)
49 49 checkandavoid()
50 50
51 51
52 52 class abstractvfs:
53 53 """Abstract base class; cannot be instantiated"""
54 54
55 55 # default directory separator for vfs
56 56 #
57 57 # Other vfs code always use `/` and this works fine because python file API
58 58 # abstract the use of `/` and make it work transparently. For consistency
59 59 # vfs will always use `/` when joining. This avoid some confusion in
60 60 # encoded vfs (see issue6546)
61 61 _dir_sep = b'/'
62 62
63 63 def __init__(self, *args, **kwargs):
64 64 '''Prevent instantiation; don't call this from subclasses.'''
65 65 raise NotImplementedError('attempted instantiating ' + str(type(self)))
66 66
67 67 # TODO: type return, which is util.posixfile wrapped by a proxy
68 68 def __call__(self, path: bytes, mode: bytes = b'rb', **kwargs):
69 69 raise NotImplementedError
70 70
71 71 def _auditpath(self, path: bytes, mode: bytes):
72 72 raise NotImplementedError
73 73
74 74 def join(self, path: Optional[bytes], *insidef: bytes) -> bytes:
75 75 raise NotImplementedError
76 76
77 77 def tryread(self, path: bytes) -> bytes:
78 78 '''gracefully return an empty string for missing files'''
79 79 try:
80 80 return self.read(path)
81 81 except FileNotFoundError:
82 82 pass
83 83 return b""
84 84
85 85 def tryreadlines(self, path: bytes, mode: bytes = b'rb'):
86 86 '''gracefully return an empty array for missing files'''
87 87 try:
88 88 return self.readlines(path, mode=mode)
89 89 except FileNotFoundError:
90 90 pass
91 91 return []
92 92
93 93 @util.propertycache
94 94 def open(self):
95 95 """Open ``path`` file, which is relative to vfs root.
96 96
97 97 Newly created directories are marked as "not to be indexed by
98 98 the content indexing service", if ``notindexed`` is specified
99 99 for "write" mode access.
100 100 """
101 101 return self.__call__
102 102
103 103 def read(self, path: bytes) -> bytes:
104 104 with self(path, b'rb') as fp:
105 105 return fp.read()
106 106
107 107 def readlines(self, path: bytes, mode: bytes = b'rb'):
108 108 with self(path, mode=mode) as fp:
109 109 return fp.readlines()
110 110
111 111 def write(
112 112 self, path: bytes, data: bytes, backgroundclose=False, **kwargs
113 113 ) -> int:
114 114 with self(path, b'wb', backgroundclose=backgroundclose, **kwargs) as fp:
115 115 return fp.write(data)
116 116
117 117 def writelines(
118 118 self, path: bytes, data: bytes, mode: bytes = b'wb', notindexed=False
119 119 ) -> None:
120 120 with self(path, mode=mode, notindexed=notindexed) as fp:
121 121 return fp.writelines(data)
122 122
123 123 def append(self, path: bytes, data: bytes) -> int:
124 124 with self(path, b'ab') as fp:
125 125 return fp.write(data)
126 126
127 127 def basename(self, path: bytes) -> bytes:
128 128 """return base element of a path (as os.path.basename would do)
129 129
130 130 This exists to allow handling of strange encoding if needed."""
131 131 return os.path.basename(path)
132 132
133 133 def chmod(self, path: bytes, mode: int) -> None:
134 134 return os.chmod(self.join(path), mode)
135 135
136 136 def dirname(self, path: bytes) -> bytes:
137 137 """return dirname element of a path (as os.path.dirname would do)
138 138
139 139 This exists to allow handling of strange encoding if needed."""
140 140 return os.path.dirname(path)
141 141
142 142 def exists(self, path: Optional[bytes] = None) -> bool:
143 143 return os.path.exists(self.join(path))
144 144
145 145 def fstat(self, fp):
146 146 return util.fstat(fp)
147 147
148 148 def isdir(self, path: Optional[bytes] = None) -> bool:
149 149 return os.path.isdir(self.join(path))
150 150
151 151 def isfile(self, path: Optional[bytes] = None) -> bool:
152 152 return os.path.isfile(self.join(path))
153 153
154 154 def islink(self, path: Optional[bytes] = None) -> bool:
155 155 return os.path.islink(self.join(path))
156 156
157 157 def isfileorlink(self, path: Optional[bytes] = None) -> bool:
158 158 """return whether path is a regular file or a symlink
159 159
160 160 Unlike isfile, this doesn't follow symlinks."""
161 161 try:
162 162 st = self.lstat(path)
163 163 except OSError:
164 164 return False
165 165 mode = st.st_mode
166 166 return stat.S_ISREG(mode) or stat.S_ISLNK(mode)
167 167
168 168 def _join(self, *paths: bytes) -> bytes:
169 169 root_idx = 0
170 170 for idx, p in enumerate(paths):
171 171 if os.path.isabs(p) or p.startswith(self._dir_sep):
172 172 root_idx = idx
173 173 if root_idx != 0:
174 174 paths = paths[root_idx:]
175 175 paths = [p for p in paths if p]
176 176 return self._dir_sep.join(paths)
177 177
178 178 def reljoin(self, *paths: bytes) -> bytes:
179 179 """join various elements of a path together (as os.path.join would do)
180 180
181 181 The vfs base is not injected so that path stay relative. This exists
182 182 to allow handling of strange encoding if needed."""
183 183 return self._join(*paths)
184 184
185 185 def split(self, path: bytes):
186 186 """split top-most element of a path (as os.path.split would do)
187 187
188 188 This exists to allow handling of strange encoding if needed."""
189 189 return os.path.split(path)
190 190
191 191 def lexists(self, path: Optional[bytes] = None) -> bool:
192 192 return os.path.lexists(self.join(path))
193 193
194 194 def lstat(self, path: Optional[bytes] = None):
195 195 return os.lstat(self.join(path))
196 196
197 197 def listdir(self, path: Optional[bytes] = None):
198 198 return os.listdir(self.join(path))
199 199
200 200 def makedir(self, path: Optional[bytes] = None, notindexed=True):
201 201 return util.makedir(self.join(path), notindexed)
202 202
203 203 def makedirs(
204 204 self, path: Optional[bytes] = None, mode: Optional[int] = None
205 205 ):
206 206 return util.makedirs(self.join(path), mode)
207 207
208 208 def makelock(self, info, path: bytes):
209 209 return util.makelock(info, self.join(path))
210 210
211 211 def mkdir(self, path: Optional[bytes] = None):
212 212 return os.mkdir(self.join(path))
213 213
214 214 def mkstemp(
215 215 self,
216 216 suffix: bytes = b'',
217 217 prefix: bytes = b'tmp',
218 218 dir: Optional[bytes] = None,
219 219 ):
220 220 fd, name = pycompat.mkstemp(
221 221 suffix=suffix, prefix=prefix, dir=self.join(dir)
222 222 )
223 223 dname, fname = util.split(name)
224 224 if dir:
225 225 return fd, os.path.join(dir, fname)
226 226 else:
227 227 return fd, fname
228 228
229 229 def readdir(self, path: Optional[bytes] = None, stat=None, skip=None):
230 230 return util.listdir(self.join(path), stat, skip)
231 231
232 232 def readlock(self, path: bytes) -> bytes:
233 233 return util.readlock(self.join(path))
234 234
235 235 def rename(self, src: bytes, dst: bytes, checkambig=False):
236 236 """Rename from src to dst
237 237
238 238 checkambig argument is used with util.filestat, and is useful
239 239 only if destination file is guarded by any lock
240 240 (e.g. repo.lock or repo.wlock).
241 241
242 242 To avoid file stat ambiguity forcibly, checkambig=True involves
243 243 copying ``src`` file, if it is owned by another. Therefore, use
244 244 checkambig=True only in limited cases (see also issue5418 and
245 245 issue5584 for detail).
246 246 """
247 247 self._auditpath(dst, b'w')
248 248 srcpath = self.join(src)
249 249 dstpath = self.join(dst)
250 250 oldstat = checkambig and util.filestat.frompath(dstpath)
251 251 if oldstat and oldstat.stat:
252 252 ret = util.rename(srcpath, dstpath)
253 253 _avoidambig(dstpath, oldstat)
254 254 return ret
255 255 return util.rename(srcpath, dstpath)
256 256
257 257 def readlink(self, path: bytes) -> bytes:
258 258 return util.readlink(self.join(path))
259 259
260 260 def removedirs(self, path: Optional[bytes] = None):
261 261 """Remove a leaf directory and all empty intermediate ones"""
262 262 return util.removedirs(self.join(path))
263 263
264 264 def rmdir(self, path: Optional[bytes] = None):
265 265 """Remove an empty directory."""
266 266 return os.rmdir(self.join(path))
267 267
268 268 def rmtree(
269 269 self, path: Optional[bytes] = None, ignore_errors=False, forcibly=False
270 270 ):
271 271 """Remove a directory tree recursively
272 272
273 273 If ``forcibly``, this tries to remove READ-ONLY files, too.
274 274 """
275 275 if forcibly:
276 276
277 277 def onerror(function, path, excinfo):
278 278 if function is not os.remove:
279 279 raise
280 280 # read-only files cannot be unlinked under Windows
281 281 s = os.stat(path)
282 282 if (s.st_mode & stat.S_IWRITE) != 0:
283 283 raise
284 284 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
285 285 os.remove(path)
286 286
287 287 else:
288 288 onerror = None
289 289 return shutil.rmtree(
290 290 self.join(path), ignore_errors=ignore_errors, onerror=onerror
291 291 )
292 292
293 293 def setflags(self, path: bytes, l: bool, x: bool):
294 294 return util.setflags(self.join(path), l, x)
295 295
296 296 def stat(self, path: Optional[bytes] = None):
297 297 return os.stat(self.join(path))
298 298
299 299 def unlink(self, path: Optional[bytes] = None):
300 300 return util.unlink(self.join(path))
301 301
302 302 def tryunlink(self, path: Optional[bytes] = None):
303 303 """Attempt to remove a file, ignoring missing file errors."""
304 304 util.tryunlink(self.join(path))
305 305
306 306 def unlinkpath(
307 307 self, path: Optional[bytes] = None, ignoremissing=False, rmdir=True
308 308 ):
309 309 return util.unlinkpath(
310 310 self.join(path), ignoremissing=ignoremissing, rmdir=rmdir
311 311 )
312 312
313 313 def utime(self, path: Optional[bytes] = None, t=None):
314 314 return os.utime(self.join(path), t)
315 315
316 316 def walk(self, path: Optional[bytes] = None, onerror=None):
317 317 """Yield (dirpath, dirs, files) tuple for each directories under path
318 318
319 319 ``dirpath`` is relative one from the root of this vfs. This
320 320 uses ``os.sep`` as path separator, even you specify POSIX
321 321 style ``path``.
322 322
323 323 "The root of this vfs" is represented as empty ``dirpath``.
324 324 """
325 325 root = os.path.normpath(self.join(None))
326 326 # when dirpath == root, dirpath[prefixlen:] becomes empty
327 327 # because len(dirpath) < prefixlen.
328 328 prefixlen = len(pathutil.normasprefix(root))
329 329 for dirpath, dirs, files in os.walk(self.join(path), onerror=onerror):
330 330 yield (dirpath[prefixlen:], dirs, files)
331 331
332 332 @contextlib.contextmanager
333 333 def backgroundclosing(self, ui, expectedcount=-1):
334 334 """Allow files to be closed asynchronously.
335 335
336 336 When this context manager is active, ``backgroundclose`` can be passed
337 337 to ``__call__``/``open`` to result in the file possibly being closed
338 338 asynchronously, on a background thread.
339 339 """
340 340 # Sharing backgroundfilecloser between threads is complex and using
341 341 # multiple instances puts us at risk of running out of file descriptors
342 342 # only allow to use backgroundfilecloser when in main thread.
343 343 if not isinstance(
344 344 threading.current_thread(),
345 345 threading._MainThread, # pytype: disable=module-attr
346 346 ):
347 347 yield
348 348 return
349 349 vfs = getattr(self, 'vfs', self)
350 350 if getattr(vfs, '_backgroundfilecloser', None):
351 351 raise error.Abort(
352 352 _(b'can only have 1 active background file closer')
353 353 )
354 354
355 355 with backgroundfilecloser(ui, expectedcount=expectedcount) as bfc:
356 356 try:
357 357 vfs._backgroundfilecloser = (
358 358 bfc # pytype: disable=attribute-error
359 359 )
360 360 yield bfc
361 361 finally:
362 362 vfs._backgroundfilecloser = (
363 363 None # pytype: disable=attribute-error
364 364 )
365 365
366 366 def register_file(self, path):
367 367 """generic hook point to lets fncache steer its stew"""
368 368
369 369
370 370 class vfs(abstractvfs):
371 371 """Operate files relative to a base directory
372 372
373 373 This class is used to hide the details of COW semantics and
374 374 remote file access from higher level code.
375 375
376 376 'cacheaudited' should be enabled only if (a) vfs object is short-lived, or
377 377 (b) the base directory is managed by hg and considered sort-of append-only.
378 378 See pathutil.pathauditor() for details.
379 379 """
380 380
381 381 def __init__(
382 382 self,
383 383 base: bytes,
384 384 audit=True,
385 385 cacheaudited=False,
386 386 expandpath=False,
387 387 realpath=False,
388 388 ):
389 389 if expandpath:
390 390 base = util.expandpath(base)
391 391 if realpath:
392 392 base = os.path.realpath(base)
393 393 self.base = base
394 394 self._audit = audit
395 395 if audit:
396 396 self.audit = pathutil.pathauditor(self.base, cached=cacheaudited)
397 397 else:
398 398 self.audit = lambda path, mode=None: True
399 399 self.createmode = None
400 400 self._trustnlink = None
401 401 self.options = {}
402 402
403 403 @util.propertycache
404 404 def _cansymlink(self) -> bool:
405 405 return util.checklink(self.base)
406 406
407 407 @util.propertycache
408 408 def _chmod(self):
409 409 return util.checkexec(self.base)
410 410
411 411 def _fixfilemode(self, name):
412 412 if self.createmode is None or not self._chmod:
413 413 return
414 414 os.chmod(name, self.createmode & 0o666)
415 415
416 416 def _auditpath(self, path, mode) -> None:
417 417 if self._audit:
418 418 if os.path.isabs(path) and path.startswith(self.base):
419 419 path = os.path.relpath(path, self.base)
420 420 r = util.checkosfilename(path)
421 421 if r:
422 422 raise error.Abort(b"%s: %r" % (r, path))
423 423 self.audit(path, mode=mode)
424 424
425 425 def isfileorlink_checkdir(
426 426 self, dircache, path: Optional[bytes] = None
427 427 ) -> bool:
428 428 """return True if the path is a regular file or a symlink and
429 429 the directories along the path are "normal", that is
430 430 not symlinks or nested hg repositories.
431 431
432 432 Ignores the `_audit` setting, and checks the directories regardless.
433 433 `dircache` is used to cache the directory checks.
434 434 """
435 435 try:
436 436 for prefix in pathutil.finddirs_rev_noroot(util.localpath(path)):
437 437 if prefix in dircache:
438 438 res = dircache[prefix]
439 439 else:
440 440 res = pathutil.pathauditor._checkfs_exists(
441 441 self.base, prefix, path
442 442 )
443 443 dircache[prefix] = res
444 444 if not res:
445 445 return False
446 446 except (OSError, error.Abort):
447 447 return False
448 448 return self.isfileorlink(path)
449 449
450 450 def __call__(
451 451 self,
452 452 path: bytes,
453 453 mode: bytes = b"rb",
454 454 atomictemp=False,
455 455 notindexed=False,
456 456 backgroundclose=False,
457 457 checkambig=False,
458 458 auditpath=True,
459 459 makeparentdirs=True,
460 460 ):
461 461 """Open ``path`` file, which is relative to vfs root.
462 462
463 463 By default, parent directories are created as needed. Newly created
464 464 directories are marked as "not to be indexed by the content indexing
465 465 service", if ``notindexed`` is specified for "write" mode access.
466 466 Set ``makeparentdirs=False`` to not create directories implicitly.
467 467
468 468 If ``backgroundclose`` is passed, the file may be closed asynchronously.
469 469 It can only be used if the ``self.backgroundclosing()`` context manager
470 470 is active. This should only be specified if the following criteria hold:
471 471
472 472 1. There is a potential for writing thousands of files. Unless you
473 473 are writing thousands of files, the performance benefits of
474 474 asynchronously closing files is not realized.
475 475 2. Files are opened exactly once for the ``backgroundclosing``
476 476 active duration and are therefore free of race conditions between
477 477 closing a file on a background thread and reopening it. (If the
478 478 file were opened multiple times, there could be unflushed data
479 479 because the original file handle hasn't been flushed/closed yet.)
480 480
481 481 ``checkambig`` argument is passed to atomictempfile (valid
482 482 only for writing), and is useful only if target file is
483 483 guarded by any lock (e.g. repo.lock or repo.wlock).
484 484
485 485 To avoid file stat ambiguity forcibly, checkambig=True involves
486 486 copying ``path`` file opened in "append" mode (e.g. for
487 487 truncation), if it is owned by another. Therefore, use
488 488 combination of append mode and checkambig=True only in limited
489 489 cases (see also issue5418 and issue5584 for detail).
490 490 """
491 491 if auditpath:
492 492 self._auditpath(path, mode)
493 493 f = self.join(path)
494 494
495 495 if b"b" not in mode:
496 496 mode += b"b" # for that other OS
497 497
498 498 nlink = -1
499 499 if mode not in (b'r', b'rb'):
500 500 dirname, basename = util.split(f)
501 501 # If basename is empty, then the path is malformed because it points
502 502 # to a directory. Let the posixfile() call below raise IOError.
503 503 if basename:
504 504 if atomictemp:
505 505 if makeparentdirs:
506 506 util.makedirs(dirname, self.createmode, notindexed)
507 507 return util.atomictempfile(
508 508 f, mode, self.createmode, checkambig=checkambig
509 509 )
510 510 try:
511 511 if b'w' in mode:
512 512 util.unlink(f)
513 513 nlink = 0
514 514 else:
515 515 # nlinks() may behave differently for files on Windows
516 516 # shares if the file is open.
517 517 with util.posixfile(f):
518 518 nlink = util.nlinks(f)
519 519 if nlink < 1:
520 520 nlink = 2 # force mktempcopy (issue1922)
521 521 except FileNotFoundError:
522 522 nlink = 0
523 523 if makeparentdirs:
524 524 util.makedirs(dirname, self.createmode, notindexed)
525 525 if nlink > 0:
526 526 if self._trustnlink is None:
527 527 self._trustnlink = nlink > 1 or util.checknlink(f)
528 528 if nlink > 1 or not self._trustnlink:
529 529 util.rename(util.mktempcopy(f), f)
530 530 fp = util.posixfile(f, mode)
531 531 if nlink == 0:
532 532 self._fixfilemode(f)
533 533
534 534 if checkambig:
535 535 if mode in (b'r', b'rb'):
536 536 raise error.Abort(
537 537 _(
538 538 b'implementation error: mode %s is not'
539 539 b' valid for checkambig=True'
540 540 )
541 541 % mode
542 542 )
543 543 fp = checkambigatclosing(fp)
544 544
545 545 if backgroundclose and isinstance(
546 546 threading.current_thread(),
547 547 threading._MainThread, # pytype: disable=module-attr
548 548 ):
549 549 if (
550 550 not self._backgroundfilecloser # pytype: disable=attribute-error
551 551 ):
552 552 raise error.Abort(
553 553 _(
554 554 b'backgroundclose can only be used when a '
555 555 b'backgroundclosing context manager is active'
556 556 )
557 557 )
558 558
559 559 fp = delayclosedfile(
560 560 fp,
561 561 self._backgroundfilecloser, # pytype: disable=attribute-error
562 562 )
563 563
564 564 return fp
565 565
566 566 def symlink(self, src: bytes, dst: bytes) -> None:
567 567 self.audit(dst)
568 568 linkname = self.join(dst)
569 569 util.tryunlink(linkname)
570 570
571 571 util.makedirs(os.path.dirname(linkname), self.createmode)
572 572
573 573 if self._cansymlink:
574 574 try:
575 575 os.symlink(src, linkname)
576 576 except OSError as err:
577 577 raise OSError(
578 578 err.errno,
579 579 _(b'could not symlink to %r: %s')
580 580 % (src, encoding.strtolocal(err.strerror)),
581 581 linkname,
582 582 )
583 583 else:
584 584 self.write(dst, src)
585 585
586 586 def join(self, path: Optional[bytes], *insidef: bytes) -> bytes:
587 587 if path:
588 588 parts = [self.base, path]
589 589 parts.extend(insidef)
590 590 return self._join(*parts)
591 591 else:
592 592 return self.base
593 593
594 594
595 595 opener = vfs
596 596
597 597
598 598 class proxyvfs(abstractvfs):
599 599 def __init__(self, vfs: "vfs"):
600 600 self.vfs = vfs
601 601
602 @property
603 def createmode(self):
604 return self.vfs.createmode
605
602 606 def _auditpath(self, path, mode):
603 607 return self.vfs._auditpath(path, mode)
604 608
605 609 @property
606 610 def options(self):
607 611 return self.vfs.options
608 612
609 613 @options.setter
610 614 def options(self, value):
611 615 self.vfs.options = value
612 616
613 617
614 618 class filtervfs(proxyvfs, abstractvfs):
615 619 '''Wrapper vfs for filtering filenames with a function.'''
616 620
617 621 def __init__(self, vfs: "vfs", filter):
618 622 proxyvfs.__init__(self, vfs)
619 623 self._filter = filter
620 624
621 625 def __call__(self, path: bytes, *args, **kwargs):
622 626 return self.vfs(self._filter(path), *args, **kwargs)
623 627
624 628 def join(self, path: Optional[bytes], *insidef: bytes) -> bytes:
625 629 if path:
626 630 return self.vfs.join(self._filter(self.vfs.reljoin(path, *insidef)))
627 631 else:
628 632 return self.vfs.join(path)
629 633
630 634
631 635 filteropener = filtervfs
632 636
633 637
634 638 class readonlyvfs(proxyvfs):
635 639 '''Wrapper vfs preventing any writing.'''
636 640
637 641 def __init__(self, vfs: "vfs"):
638 642 proxyvfs.__init__(self, vfs)
639 643
640 644 def __call__(self, path: bytes, mode: bytes = b'rb', *args, **kw):
641 645 if mode not in (b'r', b'rb'):
642 646 raise error.Abort(_(b'this vfs is read only'))
643 647 return self.vfs(path, mode, *args, **kw)
644 648
645 649 def join(self, path: Optional[bytes], *insidef: bytes) -> bytes:
646 650 return self.vfs.join(path, *insidef)
647 651
648 652
649 653 class closewrapbase:
650 654 """Base class of wrapper, which hooks closing
651 655
652 656 Do not instantiate outside of the vfs layer.
653 657 """
654 658
655 659 def __init__(self, fh):
656 660 object.__setattr__(self, '_origfh', fh)
657 661
658 662 def __getattr__(self, attr):
659 663 return getattr(self._origfh, attr)
660 664
661 665 def __setattr__(self, attr, value):
662 666 return setattr(self._origfh, attr, value)
663 667
664 668 def __delattr__(self, attr):
665 669 return delattr(self._origfh, attr)
666 670
667 671 def __enter__(self):
668 672 self._origfh.__enter__()
669 673 return self
670 674
671 675 def __exit__(self, exc_type, exc_value, exc_tb):
672 676 raise NotImplementedError('attempted instantiating ' + str(type(self)))
673 677
674 678 def close(self):
675 679 raise NotImplementedError('attempted instantiating ' + str(type(self)))
676 680
677 681
678 682 class delayclosedfile(closewrapbase):
679 683 """Proxy for a file object whose close is delayed.
680 684
681 685 Do not instantiate outside of the vfs layer.
682 686 """
683 687
684 688 def __init__(self, fh, closer):
685 689 super(delayclosedfile, self).__init__(fh)
686 690 object.__setattr__(self, '_closer', closer)
687 691
688 692 def __exit__(self, exc_type, exc_value, exc_tb):
689 693 self._closer.close(self._origfh)
690 694
691 695 def close(self):
692 696 self._closer.close(self._origfh)
693 697
694 698
695 699 class backgroundfilecloser:
696 700 """Coordinates background closing of file handles on multiple threads."""
697 701
698 702 def __init__(self, ui, expectedcount=-1):
699 703 self._running = False
700 704 self._entered = False
701 705 self._threads = []
702 706 self._threadexception = None
703 707
704 708 # Only Windows/NTFS has slow file closing. So only enable by default
705 709 # on that platform. But allow to be enabled elsewhere for testing.
706 710 defaultenabled = pycompat.iswindows
707 711 enabled = ui.configbool(b'worker', b'backgroundclose', defaultenabled)
708 712
709 713 if not enabled:
710 714 return
711 715
712 716 # There is overhead to starting and stopping the background threads.
713 717 # Don't do background processing unless the file count is large enough
714 718 # to justify it.
715 719 minfilecount = ui.configint(b'worker', b'backgroundcloseminfilecount')
716 720 # FUTURE dynamically start background threads after minfilecount closes.
717 721 # (We don't currently have any callers that don't know their file count)
718 722 if expectedcount > 0 and expectedcount < minfilecount:
719 723 return
720 724
721 725 maxqueue = ui.configint(b'worker', b'backgroundclosemaxqueue')
722 726 threadcount = ui.configint(b'worker', b'backgroundclosethreadcount')
723 727
724 728 ui.debug(
725 729 b'starting %d threads for background file closing\n' % threadcount
726 730 )
727 731
728 732 self._queue = pycompat.queue.Queue(maxsize=maxqueue)
729 733 self._running = True
730 734
731 735 for i in range(threadcount):
732 736 t = threading.Thread(target=self._worker, name='backgroundcloser')
733 737 self._threads.append(t)
734 738 t.start()
735 739
736 740 def __enter__(self):
737 741 self._entered = True
738 742 return self
739 743
740 744 def __exit__(self, exc_type, exc_value, exc_tb):
741 745 self._running = False
742 746
743 747 # Wait for threads to finish closing so open files don't linger for
744 748 # longer than lifetime of context manager.
745 749 for t in self._threads:
746 750 t.join()
747 751
748 752 def _worker(self):
749 753 """Main routine for worker thread."""
750 754 while True:
751 755 try:
752 756 fh = self._queue.get(block=True, timeout=0.100)
753 757 # Need to catch or the thread will terminate and
754 758 # we could orphan file descriptors.
755 759 try:
756 760 fh.close()
757 761 except Exception as e:
758 762 # Stash so can re-raise from main thread later.
759 763 self._threadexception = e
760 764 except pycompat.queue.Empty:
761 765 if not self._running:
762 766 break
763 767
764 768 def close(self, fh):
765 769 """Schedule a file for closing."""
766 770 if not self._entered:
767 771 raise error.Abort(
768 772 _(b'can only call close() when context manager active')
769 773 )
770 774
771 775 # If a background thread encountered an exception, raise now so we fail
772 776 # fast. Otherwise we may potentially go on for minutes until the error
773 777 # is acted on.
774 778 if self._threadexception:
775 779 e = self._threadexception
776 780 self._threadexception = None
777 781 raise e
778 782
779 783 # If we're not actively running, close synchronously.
780 784 if not self._running:
781 785 fh.close()
782 786 return
783 787
784 788 self._queue.put(fh, block=True, timeout=None)
785 789
786 790
787 791 class checkambigatclosing(closewrapbase):
788 792 """Proxy for a file object, to avoid ambiguity of file stat
789 793
790 794 See also util.filestat for detail about "ambiguity of file stat".
791 795
792 796 This proxy is useful only if the target file is guarded by any
793 797 lock (e.g. repo.lock or repo.wlock)
794 798
795 799 Do not instantiate outside of the vfs layer.
796 800 """
797 801
798 802 def __init__(self, fh):
799 803 super(checkambigatclosing, self).__init__(fh)
800 804 object.__setattr__(self, '_oldstat', util.filestat.frompath(fh.name))
801 805
802 806 def _checkambig(self):
803 807 oldstat = self._oldstat
804 808 if oldstat.stat:
805 809 _avoidambig(self._origfh.name, oldstat)
806 810
807 811 def __exit__(self, exc_type, exc_value, exc_tb):
808 812 self._origfh.__exit__(exc_type, exc_value, exc_tb)
809 813 self._checkambig()
810 814
811 815 def close(self):
812 816 self._origfh.close()
813 817 self._checkambig()
@@ -1,190 +1,203 b''
1 = Mercurial 6.4.3 =
2
3 * chg: declare environ (issue6812)
4 * chg: set CHGHG before connecting to command server
5 * delta-find: never do anything fancy when general delta is off
6 * delta-find: add a simple safeguard to prevent bad non-general-delta
7 * debug-delta: add minimal documentation for `devel.bundle-delta` option
8 * fix: highlight the required configuration and behavior of the fixer tools
9 * rhg: don't print copy source when --no-status is passed
10 * rhg: correctly relativize copy source path
11 * repo-upgrade: write new requirement before upgrading the dirstate
12 * backup: fix issue when the backup end up in a different directory
13
1 14 = Mercurial 6.4.2 =
2 15
3 16 Exceptional bugfix release due to a corruption bug that happens when using
4 17 clonebundles on repositories with large files.
5 18
6 19 * revlog-split: make sure the self._indexfile attribute is reset (issue6811)
7 20
8 21
9 22 = Mercurial 6.4.1 =
10 23
11 24 * rhg: fix a bug in path encoding
12 25 * rhg: don't crash on empty directory names in path_encode, just in case
13 26 * commands: correct documentation of hg serve’s --ipv6 options
14 27 * run-tests: remove obsolete coverage check and packaging import (issue6805)
15 28 * chg: populate CHGHG if not set
16 29 * match: sort patterns before compiling them into a regex
17 30 * match: match explicit file using a set
18 31 * rebase: do not cleanup the working copy when --dry-run is used (issue6802)
19 32 * sslutil: set context security level for legacy tls testing (issue6760)
20 33
21 34
22 35 = Mercurial 6.4 =
23 36
24 37 == New Features ==
25 38
26 39 * There is a new internal merge tool called `internal:union-other-first`.
27 40 It works like `internal:union` but add other side on top of local.
28 41 * Pullbundles are enabled by default
29 42 * delta-find: add a way to control the number of bases tested at the same time
30 43 * changelog-v2: add a configuration to disable rank computation
31 44 * debug: add an option to display statistic about a bundling operation
32 45 * debug: add an option to display statistic about a unbundling operation
33 46 * delta-find: add a delta-reuse policy that blindly accepts incoming deltas
34 47 * debug: add debug-revlog-stats command
35 48 * dirstate: add narrow support to `verify`
36 49 * verify: also check dirstate
37 50 * commit: add --draft option to use draft phase
38 51 * amend: add a --draft option to set phase to draft
39 52 * debug: add a config to abort update early
40 53 * rhg: implement checkexec to support weird filesystems
41 54 * debugshell: allow commands to be specified as a CLI argument
42 55 * rhg-files: add support for narrow when specifying a revision
43 56 * rust-narrow: enable narrow support for plain `rhg files`
44 57
45 58 == Bug Fixes ==
46 59
47 60 Aside from the following (unordered) commits which made it through a manual filter, there are a bunch of typing improvements and fixes, removal of deprecated code and general code cleanup.
48 61
49 62 * lfs: improve an exception message for blob corruption detected on transfer
50 63 * revlog: use the user facing filename as the display_id for filelogs
51 64 * rust-status: query fs traversal metadata lazily
52 65 * shelve: add Shelf.changed_files for resolving changed files in a plugin
53 66 * demandimport: ensure lazyloaderex sets loader attributes (issue6725)
54 67 * typing: fix a syntax error in mercurial/cext/bdiff.pyi
55 68 * cffi: fix a bytes vs str issue on macOS when listing directories
56 69 * changelog-v2: fix the docket `struct`
57 70 * schemes: fix a broken check for drive letter conflicts
58 71 * worker: avoid reading 1 byte at a time from the OS pipe
59 72 * rust-narrow: fix loop that never loops
60 73 * setup: Ensure target directory exists with building rust extension
61 74 * dirstate: invalidate changes when parent-change fails
62 75 * dirstate: warn about non-explicitly rolledback parent-change
63 76 * dirstate: write dirstate on successful exit of changing_parents context
64 77 * largefile: make sure we hold the lock when updating the second dirstate
65 78 * dirstate: enforce holding the lock while doing any changes
66 79 * run-tests: stop ignoring venv-installed packages
67 80 * transaction: run abort callback in all cases
68 81 * transaction: quietly rollback if no other changes than temporary files
69 82 * debugrebuilddirstate: double check that no transaction is open
70 83 * dirstate: do not write an empty dirstate just for backup
71 84 * locking: take the `wlock` for the full `hg add` duration
72 85 * locking: take the `wlock` for the full `hg remove` duration
73 86 * locking: take the `wlock` for the full `hg forget` duration
74 87 * locking: take the `wlock` for the full `hg addremove` duration
75 88 * locking: grab the wlock before touching the dirstate in `perfdirstatewrite`
76 89 * locking: hold the wlock for the full duration of the "keyword demo"
77 90 * mq: properly take the wlock during the full qfold operation
78 91 * dirstate: invalidate the dirstate change on transaction failure
79 92 * status: fix post status writing
80 93 * status: fix post status invalidation
81 94 * dirstate: avoid transaction backup/restore if we do not hold the lock
82 95 * rollback: explicitly skip dirstate rollback when applicable
83 96 * dirstate-guard: remove the feature
84 97 * dirstate: make `restorebackup` more robust when it is a noop
85 98 * dirstate: generalize the dirstate's invalidation on transaction abort
86 99 * dirstate: detect potential fishy transaction patterns while changing
87 100 * mq: write the dirstate before stripping
88 101 * dirstate: explicitly backup the datafile
89 102 * localrepo: enforce a clean dirstate when the transaction open
90 103 * localrepo: "blindly" do a dirstate backup at the end of the transaction
91 104 * dirstate: remove the dedicated backup logic
92 105 * rhg: fix a bug in path_encode
93 106 * dirstate: invalidate on all exceptions
94 107 * large-files: make sure we write newly initialized standin file early
95 108 * dirstate: warn if dirty when starting an edition
96 109 * dirstate: track that changes are pending in a transaction
97 110 * dirstate: distinct transaction callback from largefile
98 111 * automv: lock the repository before searching for renames
99 112 * dirstate: only reload the dirstate when it may have changed
100 113 * dirstate: cleanup the `_map` property cache
101 114 * status: invalidate dirstate on LockError
102 115 * dirstate: check that dirstate is clean at the initial context opening
103 116 * dirstate: have `running_status` write the dirstate when holding the lock
104 117 * dirstate: have `running_status` warn when exiting with a dirty dirstate
105 118 * narrow: widden the lock context in `tracking`
106 119 * narrow: enforce that narrow spec is written within a transaction
107 120 * transaction: no longer explicitly cache phaseroots
108 121 * transaction: no longer explicitly cache bookmarks
109 122 * transaction: use the standard transaction mechanism to backup branch
110 123 * bundlerepo: handle changegroup induced phase movement in the associated method
111 124 * bundlerepo: apply phase data stored in the bundle instead of assuming `draft`
112 125 * config-item: declare undeclared path suboption
113 126 * narrow: read pending file when applicable
114 127 * rust: fix building on macOS (issue6801)
115 128 * run-tests: fix a crash when using the coverage options
116 129 * undo-files: also remove the undo.backupfiles
117 130 * undo-files: cleanup backup when cleaning undos
118 131 * undo-files: clean existing files up before writing new one
119 132 * undo-files: cleanup legacy files when applicable
120 133 * dirstate-v2: fix an incorrect handling of readdir errors
121 134 * rust: update zstd dependency
122 135 * rust: upgrade `rayon` dependency
123 136 * dirstate: fix the bug in [status] dealing with committed&ignored directories
124 137 * dirstate: fix a potential traceback when in `copy` and `rename`
125 138 * histedit: fix diff colors
126 139 * cext: fix for PyLong refactoring in CPython 3.12
127 140 * py3: fix for Python 3.12 emitting SyntaxWarning on invalid escape sequences
128 141 * statprof: with Python 3.12, lineno is (more) often None
129 142 * transaction: properly clean up backup file outside of .hg/store/
130 143 * transaction: raise on backup restoration error
131 144 * revlog: improve the robustness of the splitting process
132 145 * debugdeltachain: stop summing the same chain over and over
133 146 * url: don't ignore timeout for https connections
134 147 * py3: fix for Python 3.12 emitting SyntaxWarning on invalid escape sequences
135 148 * tests: accept a test output change in [tests/test-serve.t]
136 149 * rust: fix thread cap (for real this time)
137 150 * dirstate: try refreshing the changelog when parent are unknown
138 151 * hooks: invalidate the repo after the hooks
139 152
140 153 == Backwards Compatibility Changes ==
141 154 * rust: upgrade supported Rust toolchain version
142 155 * rust: move all crates in the main workspace to edition 2021
143 156 * hg-core: upgrade `zstd` dependency
144 157 * hg-core: upgrade `clap` dependency
145 158 * hg-core: upgrade all remaining dependencies
146 159 * hg-cpython: upgrade dependencies
147 160 * rhg: upgrade `clap` dependency
148 161 * rhg: upgrade the remainder of the dependencies
149 162
150 163 == Internal API Changes ==
151 164
152 165 * Many APIs around the dirstate have been made much stricter with regards to
153 166 locking and transaction handling
154 167 * Some dirstate APIs have been renamed/removed
155 168 * In both cases, you should get loud complaints in your tests if you do
156 169 something wrong.
157 170
158 171 == Miscellaneous ==
159 172
160 173 * pullbundle support no longer requires setting a server-side option,
161 174 providing a .hg/pullbundles.manifest according to the syntax specified in
162 175 'hg help -e clonebundles' is enough.
163 176 * debug-delta-find: add a --source option
164 177 * delta-find: add debug information about reuse of cached data
165 178 * delta-find: set the default candidate chunk size to 10
166 179 * attr: vendor 22.1.0
167 180 * configitems: add a default value for "merge-tools.xxx.regappend"
168 181 * debugrevlog: display total stored information
169 182 * emitrevision: if we need to compute a delta on the fly, try p1 or p2 first
170 183 * emitrevision: consider ancestors revision to emit as available base
171 184 * find-delta: pass the cache-delta usage policy alongside the cache-delta
172 185 * delta-find: use a smarter object for snapshot caching
173 186 * delta-find: use sets instead of list in the snapshot cache
174 187 * delta-find: make sure we only use newer full snapshot as candidate
175 188 * delta-find: use a single snapshot cache when applying a group to an object
176 189 * bundleoperation: optionnaly record the `remote` that produced the bundle
177 190 * bundle: when forcing acceptance of incoming delta also accept snapshot
178 191 * bundle: emit full snapshot as is, without doing a redelta
179 192 * pathutil: slightly faster path audit in the common case
180 193 * merge: don't pay for pathconflicts if there are none
181 194 * merge: short-circuit the _checkfs loop upon getting ENOENT
182 195 * merge: disable the whole filesystem access loop if [_realfs] is false
183 196 * merge: cache the fs checks made during [_checkunknownfiles]
184 197 * rust: use `logging_timer` instead of `micro_timer`
185 198 * rust: run `cargo clippy`
186 199 * makefile: add `cargo clippy` to tests if cargo is available
187 200 * heptapod-ci: add `clippy` to the CI
188 201 * convert: use a priority queue for sorting commits, to make sorting faster
189 202 * delta-find: adjust the default candidate group chunk size
190 203 * delta-find: declare the "paths..*:pulled-delta-reuse-policy option No newline at end of file
@@ -1,670 +1,675 b''
1 1 // status.rs
2 2 //
3 3 // Copyright 2020, Georges Racinet <georges.racinets@octobus.net>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 use crate::error::CommandError;
9 9 use crate::ui::{
10 10 format_pattern_file_warning, print_narrow_sparse_warnings, Ui,
11 11 };
12 12 use crate::utils::path_utils::RelativizePaths;
13 13 use clap::Arg;
14 14 use format_bytes::format_bytes;
15 15 use hg::config::Config;
16 16 use hg::dirstate::has_exec_bit;
17 17 use hg::dirstate::status::StatusPath;
18 18 use hg::dirstate::TruncatedTimestamp;
19 19 use hg::errors::{HgError, IoResultExt};
20 20 use hg::lock::LockError;
21 21 use hg::manifest::Manifest;
22 22 use hg::matchers::{AlwaysMatcher, IntersectionMatcher};
23 23 use hg::repo::Repo;
24 24 use hg::utils::debug::debug_wait_for_file;
25 25 use hg::utils::files::get_bytes_from_os_string;
26 26 use hg::utils::files::get_path_from_bytes;
27 27 use hg::utils::hg_path::{hg_path_to_path_buf, HgPath};
28 28 use hg::DirstateStatus;
29 29 use hg::PatternFileWarning;
30 30 use hg::StatusError;
31 31 use hg::StatusOptions;
32 32 use hg::{self, narrow, sparse};
33 33 use log::info;
34 34 use rayon::prelude::*;
35 35 use std::io;
36 36 use std::path::PathBuf;
37 37
38 38 pub const HELP_TEXT: &str = "
39 39 Show changed files in the working directory
40 40
41 41 This is a pure Rust version of `hg status`.
42 42
43 43 Some options might be missing, check the list below.
44 44 ";
45 45
46 46 pub fn args() -> clap::Command {
47 47 clap::command!("status")
48 48 .alias("st")
49 49 .about(HELP_TEXT)
50 50 .arg(
51 51 Arg::new("all")
52 52 .help("show status of all files")
53 53 .short('A')
54 54 .action(clap::ArgAction::SetTrue)
55 55 .long("all"),
56 56 )
57 57 .arg(
58 58 Arg::new("modified")
59 59 .help("show only modified files")
60 60 .short('m')
61 61 .action(clap::ArgAction::SetTrue)
62 62 .long("modified"),
63 63 )
64 64 .arg(
65 65 Arg::new("added")
66 66 .help("show only added files")
67 67 .short('a')
68 68 .action(clap::ArgAction::SetTrue)
69 69 .long("added"),
70 70 )
71 71 .arg(
72 72 Arg::new("removed")
73 73 .help("show only removed files")
74 74 .short('r')
75 75 .action(clap::ArgAction::SetTrue)
76 76 .long("removed"),
77 77 )
78 78 .arg(
79 79 Arg::new("clean")
80 80 .help("show only clean files")
81 81 .short('c')
82 82 .action(clap::ArgAction::SetTrue)
83 83 .long("clean"),
84 84 )
85 85 .arg(
86 86 Arg::new("deleted")
87 87 .help("show only deleted files")
88 88 .short('d')
89 89 .action(clap::ArgAction::SetTrue)
90 90 .long("deleted"),
91 91 )
92 92 .arg(
93 93 Arg::new("unknown")
94 94 .help("show only unknown (not tracked) files")
95 95 .short('u')
96 96 .action(clap::ArgAction::SetTrue)
97 97 .long("unknown"),
98 98 )
99 99 .arg(
100 100 Arg::new("ignored")
101 101 .help("show only ignored files")
102 102 .short('i')
103 103 .action(clap::ArgAction::SetTrue)
104 104 .long("ignored"),
105 105 )
106 106 .arg(
107 107 Arg::new("copies")
108 108 .help("show source of copied files (DEFAULT: ui.statuscopies)")
109 109 .short('C')
110 110 .action(clap::ArgAction::SetTrue)
111 111 .long("copies"),
112 112 )
113 113 .arg(
114 114 Arg::new("print0")
115 115 .help("end filenames with NUL, for use with xargs")
116 116 .short('0')
117 117 .action(clap::ArgAction::SetTrue)
118 118 .long("print0"),
119 119 )
120 120 .arg(
121 121 Arg::new("no-status")
122 122 .help("hide status prefix")
123 123 .short('n')
124 124 .action(clap::ArgAction::SetTrue)
125 125 .long("no-status"),
126 126 )
127 127 .arg(
128 128 Arg::new("verbose")
129 129 .help("enable additional output")
130 130 .short('v')
131 131 .action(clap::ArgAction::SetTrue)
132 132 .long("verbose"),
133 133 )
134 134 }
135 135
136 136 /// Pure data type allowing the caller to specify file states to display
137 137 #[derive(Copy, Clone, Debug)]
138 138 pub struct DisplayStates {
139 139 pub modified: bool,
140 140 pub added: bool,
141 141 pub removed: bool,
142 142 pub clean: bool,
143 143 pub deleted: bool,
144 144 pub unknown: bool,
145 145 pub ignored: bool,
146 146 }
147 147
148 148 pub const DEFAULT_DISPLAY_STATES: DisplayStates = DisplayStates {
149 149 modified: true,
150 150 added: true,
151 151 removed: true,
152 152 clean: false,
153 153 deleted: true,
154 154 unknown: true,
155 155 ignored: false,
156 156 };
157 157
158 158 pub const ALL_DISPLAY_STATES: DisplayStates = DisplayStates {
159 159 modified: true,
160 160 added: true,
161 161 removed: true,
162 162 clean: true,
163 163 deleted: true,
164 164 unknown: true,
165 165 ignored: true,
166 166 };
167 167
168 168 impl DisplayStates {
169 169 pub fn is_empty(&self) -> bool {
170 170 !(self.modified
171 171 || self.added
172 172 || self.removed
173 173 || self.clean
174 174 || self.deleted
175 175 || self.unknown
176 176 || self.ignored)
177 177 }
178 178 }
179 179
180 180 fn has_unfinished_merge(repo: &Repo) -> Result<bool, CommandError> {
181 181 Ok(repo.dirstate_parents()?.is_merge())
182 182 }
183 183
184 184 fn has_unfinished_state(repo: &Repo) -> Result<bool, CommandError> {
185 185 // These are all the known values for the [fname] argument of
186 186 // [addunfinished] function in [state.py]
187 187 let known_state_files: &[&str] = &[
188 188 "bisect.state",
189 189 "graftstate",
190 190 "histedit-state",
191 191 "rebasestate",
192 192 "shelvedstate",
193 193 "transplant/journal",
194 194 "updatestate",
195 195 ];
196 196 if has_unfinished_merge(repo)? {
197 197 return Ok(true);
198 198 };
199 199 for f in known_state_files {
200 200 if repo.hg_vfs().join(f).exists() {
201 201 return Ok(true);
202 202 }
203 203 }
204 204 Ok(false)
205 205 }
206 206
207 207 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
208 208 // TODO: lift these limitations
209 209 if invocation
210 210 .config
211 211 .get(b"commands", b"status.terse")
212 212 .is_some()
213 213 {
214 214 return Err(CommandError::unsupported(
215 215 "status.terse is not yet supported with rhg status",
216 216 ));
217 217 }
218 218
219 219 let ui = invocation.ui;
220 220 let config = invocation.config;
221 221 let args = invocation.subcommand_args;
222 222
223 223 let print0 = args.get_flag("print0");
224 224 let verbose = args.get_flag("verbose")
225 225 || config.get_bool(b"ui", b"verbose")?
226 226 || config.get_bool(b"commands", b"status.verbose")?;
227 227 let verbose = verbose && !print0;
228 228
229 229 let all = args.get_flag("all");
230 230 let display_states = if all {
231 231 // TODO when implementing `--quiet`: it excludes clean files
232 232 // from `--all`
233 233 ALL_DISPLAY_STATES
234 234 } else {
235 235 let requested = DisplayStates {
236 236 modified: args.get_flag("modified"),
237 237 added: args.get_flag("added"),
238 238 removed: args.get_flag("removed"),
239 239 clean: args.get_flag("clean"),
240 240 deleted: args.get_flag("deleted"),
241 241 unknown: args.get_flag("unknown"),
242 242 ignored: args.get_flag("ignored"),
243 243 };
244 244 if requested.is_empty() {
245 245 DEFAULT_DISPLAY_STATES
246 246 } else {
247 247 requested
248 248 }
249 249 };
250 250 let no_status = args.get_flag("no-status");
251 251 let list_copies = all
252 252 || args.get_flag("copies")
253 253 || config.get_bool(b"ui", b"statuscopies")?;
254 254
255 255 let repo = invocation.repo?;
256 256
257 257 if verbose && has_unfinished_state(repo)? {
258 258 return Err(CommandError::unsupported(
259 259 "verbose status output is not supported by rhg (and is needed because we're in an unfinished operation)",
260 260 ));
261 261 }
262 262
263 263 let mut dmap = repo.dirstate_map_mut()?;
264 264
265 265 let check_exec = hg::checkexec::check_exec(repo.working_directory_path());
266 266
267 267 let options = StatusOptions {
268 268 check_exec,
269 269 list_clean: display_states.clean,
270 270 list_unknown: display_states.unknown,
271 271 list_ignored: display_states.ignored,
272 272 list_copies,
273 273 collect_traversed_dirs: false,
274 274 };
275 275
276 276 type StatusResult<'a> =
277 277 Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>;
278 278
279 279 let after_status = |res: StatusResult| -> Result<_, CommandError> {
280 280 let (mut ds_status, pattern_warnings) = res?;
281 281 for warning in pattern_warnings {
282 282 ui.write_stderr(&format_pattern_file_warning(&warning, repo))?;
283 283 }
284 284
285 285 for (path, error) in ds_status.bad {
286 286 let error = match error {
287 287 hg::BadMatch::OsError(code) => {
288 288 std::io::Error::from_raw_os_error(code).to_string()
289 289 }
290 290 hg::BadMatch::BadType(ty) => {
291 291 format!("unsupported file type (type is {})", ty)
292 292 }
293 293 };
294 294 ui.write_stderr(&format_bytes!(
295 295 b"{}: {}\n",
296 296 path.as_bytes(),
297 297 error.as_bytes()
298 298 ))?
299 299 }
300 300 if !ds_status.unsure.is_empty() {
301 301 info!(
302 302 "Files to be rechecked by retrieval from filelog: {:?}",
303 303 ds_status.unsure.iter().map(|s| &s.path).collect::<Vec<_>>()
304 304 );
305 305 }
306 306 let mut fixup = Vec::new();
307 307 if !ds_status.unsure.is_empty()
308 308 && (display_states.modified || display_states.clean)
309 309 {
310 310 let p1 = repo.dirstate_parents()?.p1;
311 311 let manifest = repo.manifest_for_node(p1).map_err(|e| {
312 312 CommandError::from((e, &*format!("{:x}", p1.short())))
313 313 })?;
314 314 let working_directory_vfs = repo.working_directory_vfs();
315 315 let store_vfs = repo.store_vfs();
316 316 let res: Vec<_> = ds_status
317 317 .unsure
318 318 .into_par_iter()
319 319 .map(|to_check| {
320 320 // The compiler seems to get a bit confused with complex
321 321 // inference when using a parallel iterator + map
322 322 // + map_err + collect, so let's just inline some of the
323 323 // logic.
324 324 match unsure_is_modified(
325 325 working_directory_vfs,
326 326 store_vfs,
327 327 check_exec,
328 328 &manifest,
329 329 &to_check.path,
330 330 ) {
331 331 Err(HgError::IoError { .. }) => {
332 332 // IO errors most likely stem from the file being
333 333 // deleted even though we know it's in the
334 334 // dirstate.
335 335 Ok((to_check, UnsureOutcome::Deleted))
336 336 }
337 337 Ok(outcome) => Ok((to_check, outcome)),
338 338 Err(e) => Err(e),
339 339 }
340 340 })
341 341 .collect::<Result<_, _>>()?;
342 342 for (status_path, outcome) in res.into_iter() {
343 343 match outcome {
344 344 UnsureOutcome::Clean => {
345 345 if display_states.clean {
346 346 ds_status.clean.push(status_path.clone());
347 347 }
348 348 fixup.push(status_path.path.into_owned())
349 349 }
350 350 UnsureOutcome::Modified => {
351 351 if display_states.modified {
352 352 ds_status.modified.push(status_path);
353 353 }
354 354 }
355 355 UnsureOutcome::Deleted => {
356 356 if display_states.deleted {
357 357 ds_status.deleted.push(status_path);
358 358 }
359 359 }
360 360 }
361 361 }
362 362 }
363 363 let relative_paths = config
364 364 .get_option(b"commands", b"status.relative")?
365 365 .unwrap_or(config.get_bool(b"ui", b"relative-paths")?);
366 366 let output = DisplayStatusPaths {
367 367 ui,
368 368 no_status,
369 369 relativize: if relative_paths {
370 370 Some(RelativizePaths::new(repo)?)
371 371 } else {
372 372 None
373 373 },
374 374 print0,
375 375 };
376 376 if display_states.modified {
377 377 output.display(b"M ", "status.modified", ds_status.modified)?;
378 378 }
379 379 if display_states.added {
380 380 output.display(b"A ", "status.added", ds_status.added)?;
381 381 }
382 382 if display_states.removed {
383 383 output.display(b"R ", "status.removed", ds_status.removed)?;
384 384 }
385 385 if display_states.deleted {
386 386 output.display(b"! ", "status.deleted", ds_status.deleted)?;
387 387 }
388 388 if display_states.unknown {
389 389 output.display(b"? ", "status.unknown", ds_status.unknown)?;
390 390 }
391 391 if display_states.ignored {
392 392 output.display(b"I ", "status.ignored", ds_status.ignored)?;
393 393 }
394 394 if display_states.clean {
395 395 output.display(b"C ", "status.clean", ds_status.clean)?;
396 396 }
397 397
398 398 let dirstate_write_needed = ds_status.dirty;
399 399 let filesystem_time_at_status_start =
400 400 ds_status.filesystem_time_at_status_start;
401 401
402 402 Ok((
403 403 fixup,
404 404 dirstate_write_needed,
405 405 filesystem_time_at_status_start,
406 406 ))
407 407 };
408 408 let (narrow_matcher, narrow_warnings) = narrow::matcher(repo)?;
409 409 let (sparse_matcher, sparse_warnings) = sparse::matcher(repo)?;
410 410 let matcher = match (repo.has_narrow(), repo.has_sparse()) {
411 411 (true, true) => {
412 412 Box::new(IntersectionMatcher::new(narrow_matcher, sparse_matcher))
413 413 }
414 414 (true, false) => narrow_matcher,
415 415 (false, true) => sparse_matcher,
416 416 (false, false) => Box::new(AlwaysMatcher),
417 417 };
418 418
419 419 print_narrow_sparse_warnings(
420 420 &narrow_warnings,
421 421 &sparse_warnings,
422 422 ui,
423 423 repo,
424 424 )?;
425 425 let (fixup, mut dirstate_write_needed, filesystem_time_at_status_start) =
426 426 dmap.with_status(
427 427 matcher.as_ref(),
428 428 repo.working_directory_path().to_owned(),
429 429 ignore_files(repo, config),
430 430 options,
431 431 after_status,
432 432 )?;
433 433
434 434 // Development config option to test write races
435 435 if let Err(e) =
436 436 debug_wait_for_file(config, "status.pre-dirstate-write-file")
437 437 {
438 438 ui.write_stderr(e.as_bytes()).ok();
439 439 }
440 440
441 441 if (fixup.is_empty() || filesystem_time_at_status_start.is_none())
442 442 && !dirstate_write_needed
443 443 {
444 444 // Nothing to update
445 445 return Ok(());
446 446 }
447 447
448 448 // Update the dirstate on disk if we can
449 449 let with_lock_result =
450 450 repo.try_with_wlock_no_wait(|| -> Result<(), CommandError> {
451 451 if let Some(mtime_boundary) = filesystem_time_at_status_start {
452 452 for hg_path in fixup {
453 453 use std::os::unix::fs::MetadataExt;
454 454 let fs_path = hg_path_to_path_buf(&hg_path)
455 455 .expect("HgPath conversion");
456 456 // Specifically do not reuse `fs_metadata` from
457 457 // `unsure_is_clean` which was needed before reading
458 458 // contents. Here we access metadata again after reading
459 459 // content, in case it changed in the meantime.
460 460 let metadata_res = repo
461 461 .working_directory_vfs()
462 462 .symlink_metadata(&fs_path);
463 463 let fs_metadata = match metadata_res {
464 464 Ok(meta) => meta,
465 465 Err(err) => match err {
466 466 HgError::IoError { .. } => {
467 467 // The file has probably been deleted. In any
468 468 // case, it was in the dirstate before, so
469 469 // let's ignore the error.
470 470 continue;
471 471 }
472 472 _ => return Err(err.into()),
473 473 },
474 474 };
475 475 if let Some(mtime) =
476 476 TruncatedTimestamp::for_reliable_mtime_of(
477 477 &fs_metadata,
478 478 &mtime_boundary,
479 479 )
480 480 .when_reading_file(&fs_path)?
481 481 {
482 482 let mode = fs_metadata.mode();
483 483 let size = fs_metadata.len();
484 484 dmap.set_clean(&hg_path, mode, size as u32, mtime)?;
485 485 dirstate_write_needed = true
486 486 }
487 487 }
488 488 }
489 489 drop(dmap); // Avoid "already mutably borrowed" RefCell panics
490 490 if dirstate_write_needed {
491 491 repo.write_dirstate()?
492 492 }
493 493 Ok(())
494 494 });
495 495 match with_lock_result {
496 496 Ok(closure_result) => closure_result?,
497 497 Err(LockError::AlreadyHeld) => {
498 498 // Not updating the dirstate is not ideal but not critical:
499 499 // don’t keep our caller waiting until some other Mercurial
500 500 // process releases the lock.
501 501 log::info!("not writing dirstate from `status`: lock is held")
502 502 }
503 503 Err(LockError::Other(HgError::IoError { error, .. }))
504 504 if error.kind() == io::ErrorKind::PermissionDenied =>
505 505 {
506 506 // `hg status` on a read-only repository is fine
507 507 }
508 508 Err(LockError::Other(error)) => {
509 509 // Report other I/O errors
510 510 Err(error)?
511 511 }
512 512 }
513 513 Ok(())
514 514 }
515 515
516 516 fn ignore_files(repo: &Repo, config: &Config) -> Vec<PathBuf> {
517 517 let mut ignore_files = Vec::new();
518 518 let repo_ignore = repo.working_directory_vfs().join(".hgignore");
519 519 if repo_ignore.exists() {
520 520 ignore_files.push(repo_ignore)
521 521 }
522 522 for (key, value) in config.iter_section(b"ui") {
523 523 if key == b"ignore" || key.starts_with(b"ignore.") {
524 524 let path = get_path_from_bytes(value);
525 525 // TODO: expand "~/" and environment variable here, like Python
526 526 // does with `os.path.expanduser` and `os.path.expandvars`
527 527
528 528 let joined = repo.working_directory_path().join(path);
529 529 ignore_files.push(joined);
530 530 }
531 531 }
532 532 ignore_files
533 533 }
534 534
535 535 struct DisplayStatusPaths<'a> {
536 536 ui: &'a Ui,
537 537 no_status: bool,
538 538 relativize: Option<RelativizePaths>,
539 539 print0: bool,
540 540 }
541 541
542 542 impl DisplayStatusPaths<'_> {
543 543 // Probably more elegant to use a Deref or Borrow trait rather than
544 544 // harcode HgPathBuf, but probably not really useful at this point
545 545 fn display(
546 546 &self,
547 547 status_prefix: &[u8],
548 548 label: &'static str,
549 549 mut paths: Vec<StatusPath<'_>>,
550 550 ) -> Result<(), CommandError> {
551 551 paths.sort_unstable();
552 552 // TODO: get the stdout lock once for the whole loop
553 553 // instead of in each write
554 554 for StatusPath { path, copy_source } in paths {
555 let relative;
556 let path = if let Some(relativize) = &self.relativize {
557 relative = relativize.relativize(&path);
558 &*relative
555 let relative_path;
556 let relative_source;
557 let (path, copy_source) = if let Some(relativize) =
558 &self.relativize
559 {
560 relative_path = relativize.relativize(&path);
561 relative_source =
562 copy_source.as_ref().map(|s| relativize.relativize(s));
563 (&*relative_path, relative_source.as_deref())
559 564 } else {
560 path.as_bytes()
565 (path.as_bytes(), copy_source.as_ref().map(|s| s.as_bytes()))
561 566 };
562 567 // TODO: Add a way to use `write_bytes!` instead of `format_bytes!`
563 568 // in order to stream to stdout instead of allocating an
564 569 // itermediate `Vec<u8>`.
565 570 if !self.no_status {
566 571 self.ui.write_stdout_labelled(status_prefix, label)?
567 572 }
568 573 let linebreak = if self.print0 { b"\x00" } else { b"\n" };
569 574 self.ui.write_stdout_labelled(
570 575 &format_bytes!(b"{}{}", path, linebreak),
571 576 label,
572 577 )?;
573 if let Some(source) = copy_source {
578 if let Some(source) = copy_source.filter(|_| !self.no_status) {
574 579 let label = "status.copied";
575 580 self.ui.write_stdout_labelled(
576 &format_bytes!(b" {}{}", source.as_bytes(), linebreak),
581 &format_bytes!(b" {}{}", source, linebreak),
577 582 label,
578 583 )?
579 584 }
580 585 }
581 586 Ok(())
582 587 }
583 588 }
584 589
585 590 /// Outcome of the additional check for an ambiguous tracked file
586 591 enum UnsureOutcome {
587 592 /// The file is actually clean
588 593 Clean,
589 594 /// The file has been modified
590 595 Modified,
591 596 /// The file was deleted on disk (or became another type of fs entry)
592 597 Deleted,
593 598 }
594 599
595 600 /// Check if a file is modified by comparing actual repo store and file system.
596 601 ///
597 602 /// This meant to be used for those that the dirstate cannot resolve, due
598 603 /// to time resolution limits.
599 604 fn unsure_is_modified(
600 605 working_directory_vfs: hg::vfs::Vfs,
601 606 store_vfs: hg::vfs::Vfs,
602 607 check_exec: bool,
603 608 manifest: &Manifest,
604 609 hg_path: &HgPath,
605 610 ) -> Result<UnsureOutcome, HgError> {
606 611 let vfs = working_directory_vfs;
607 612 let fs_path = hg_path_to_path_buf(hg_path).expect("HgPath conversion");
608 613 let fs_metadata = vfs.symlink_metadata(&fs_path)?;
609 614 let is_symlink = fs_metadata.file_type().is_symlink();
610 615
611 616 let entry = manifest
612 617 .find_by_path(hg_path)?
613 618 .expect("ambgious file not in p1");
614 619
615 620 // TODO: Also account for `FALLBACK_SYMLINK` and `FALLBACK_EXEC` from the
616 621 // dirstate
617 622 let fs_flags = if is_symlink {
618 623 Some(b'l')
619 624 } else if check_exec && has_exec_bit(&fs_metadata) {
620 625 Some(b'x')
621 626 } else {
622 627 None
623 628 };
624 629
625 630 let entry_flags = if check_exec {
626 631 entry.flags
627 632 } else if entry.flags == Some(b'x') {
628 633 None
629 634 } else {
630 635 entry.flags
631 636 };
632 637
633 638 if entry_flags != fs_flags {
634 639 return Ok(UnsureOutcome::Modified);
635 640 }
636 641 let filelog = hg::filelog::Filelog::open_vfs(&store_vfs, hg_path)?;
637 642 let fs_len = fs_metadata.len();
638 643 let file_node = entry.node_id()?;
639 644 let filelog_entry = filelog.entry_for_node(file_node).map_err(|_| {
640 645 HgError::corrupted(format!(
641 646 "filelog {:?} missing node {:?} from manifest",
642 647 hg_path, file_node
643 648 ))
644 649 })?;
645 650 if filelog_entry.file_data_len_not_equal_to(fs_len) {
646 651 // No need to read file contents:
647 652 // it cannot be equal if it has a different length.
648 653 return Ok(UnsureOutcome::Modified);
649 654 }
650 655
651 656 let p1_filelog_data = filelog_entry.data()?;
652 657 let p1_contents = p1_filelog_data.file_data()?;
653 658 if p1_contents.len() as u64 != fs_len {
654 659 // No need to read file contents:
655 660 // it cannot be equal if it has a different length.
656 661 return Ok(UnsureOutcome::Modified);
657 662 }
658 663
659 664 let fs_contents = if is_symlink {
660 665 get_bytes_from_os_string(vfs.read_link(fs_path)?.into_os_string())
661 666 } else {
662 667 vfs.read(fs_path)?
663 668 };
664 669
665 670 Ok(if p1_contents != &*fs_contents {
666 671 UnsureOutcome::Modified
667 672 } else {
668 673 UnsureOutcome::Clean
669 674 })
670 675 }
@@ -1,555 +1,572 b''
1 1 #require chg
2 2
3 3 Scale the timeout for the chg-server to the test timeout scaling.
4 4 This is done to reduce the flakiness of this test on heavy load.
5 5
6 6 $ CHGTIMEOUT=`expr $HGTEST_TIMEOUT / 6`
7 7 $ export CHGTIMEOUT
8 8
9 9 $ mkdir log
10 10 $ cp $HGRCPATH $HGRCPATH.unconfigured
11 11 $ cat <<'EOF' >> $HGRCPATH
12 12 > [cmdserver]
13 13 > log = $TESTTMP/log/server.log
14 14 > max-log-files = 1
15 15 > max-log-size = 10 kB
16 16 > EOF
17 17 $ cp $HGRCPATH $HGRCPATH.orig
18 18
19 19 $ filterlog () {
20 20 > sed -e 's!^[0-9/]* [0-9:]* ([0-9]*)>!YYYY/MM/DD HH:MM:SS (PID)>!' \
21 21 > -e 's!\(setprocname\|received fds\|setenv\): .*!\1: ...!' \
22 22 > -e 's!\(confighash\|mtimehash\) = [0-9a-f]*!\1 = ...!g' \
23 23 > -e 's!\(in \)[0-9.]*s\b!\1 ...s!g' \
24 24 > -e 's!\(pid\)=[0-9]*!\1=...!g' \
25 25 > -e 's!\(/server-\)[0-9a-f]*!\1...!g'
26 26 > }
27 27
28 28 init repo
29 29
30 30 $ chg init foo
31 31 $ cd foo
32 32
33 33 ill-formed config
34 34
35 35 $ chg status
36 36 $ echo '=brokenconfig' >> $HGRCPATH
37 37 $ chg status
38 38 config error at * =brokenconfig (glob)
39 39 [30]
40 40
41 41 $ cp $HGRCPATH.orig $HGRCPATH
42 42
43 43 long socket path
44 44
45 45 $ sockpath=$TESTTMP/this/path/should/be/longer/than/one-hundred-and-seven/characters/where/107/is/the/typical/size/limit/of/unix-domain-socket
46 46 $ mkdir -p $sockpath
47 47 $ bakchgsockname=$CHGSOCKNAME
48 48 $ CHGSOCKNAME=$sockpath/server
49 49 $ export CHGSOCKNAME
50 50 $ chg root
51 51 $TESTTMP/foo
52 52 $ rm -rf $sockpath
53 53 $ CHGSOCKNAME=$bakchgsockname
54 54 $ export CHGSOCKNAME
55 55
56 56 $ cd ..
57 57
58 58 editor
59 59 ------
60 60
61 61 $ cat >> pushbuffer.py <<EOF
62 62 > def reposetup(ui, repo):
63 63 > repo.ui.pushbuffer(subproc=True)
64 64 > EOF
65 65
66 66 $ chg init editor
67 67 $ cd editor
68 68
69 69 by default, system() should be redirected to the client:
70 70
71 71 $ touch foo
72 72 $ CHGDEBUG= HGEDITOR=cat chg ci -Am channeled --edit 2>&1 \
73 73 > | egrep "HG:|run 'cat"
74 74 chg: debug: * run 'cat "*"' at '$TESTTMP/editor' (glob)
75 75 HG: Enter commit message. Lines beginning with 'HG:' are removed.
76 76 HG: Leave message empty to abort commit.
77 77 HG: --
78 78 HG: user: test
79 79 HG: branch 'default'
80 80 HG: added foo
81 81
82 82 but no redirection should be made if output is captured:
83 83
84 84 $ touch bar
85 85 $ CHGDEBUG= HGEDITOR=cat chg ci -Am bufferred --edit \
86 86 > --config extensions.pushbuffer="$TESTTMP/pushbuffer.py" 2>&1 \
87 87 > | egrep "HG:|run 'cat"
88 88 [1]
89 89
90 90 check that commit commands succeeded:
91 91
92 92 $ hg log -T '{rev}:{desc}\n'
93 93 1:bufferred
94 94 0:channeled
95 95
96 96 $ cd ..
97 97
98 98 pager
99 99 -----
100 100
101 101 $ cat >> fakepager.py <<EOF
102 102 > import sys
103 103 > for line in sys.stdin:
104 104 > sys.stdout.write('paged! %r\n' % line)
105 105 > EOF
106 106
107 107 enable pager extension globally, but spawns the master server with no tty:
108 108
109 109 $ chg init pager
110 110 $ cd pager
111 111 $ cat >> $HGRCPATH <<EOF
112 112 > [extensions]
113 113 > pager =
114 114 > [pager]
115 115 > pager = "$PYTHON" $TESTTMP/fakepager.py
116 116 > EOF
117 117 $ chg version > /dev/null
118 118 $ touch foo
119 119 $ chg ci -qAm foo
120 120
121 121 pager should be enabled if the attached client has a tty:
122 122
123 123 $ chg log -l1 -q --config ui.formatted=True
124 124 paged! '0:1f7b0de80e11\n'
125 125 $ chg log -l1 -q --config ui.formatted=False
126 126 0:1f7b0de80e11
127 127
128 128 chg waits for pager if runcommand raises
129 129
130 130 $ cat > $TESTTMP/crash.py <<EOF
131 131 > from mercurial import registrar
132 132 > cmdtable = {}
133 133 > command = registrar.command(cmdtable)
134 134 > @command(b'crash')
135 135 > def pagercrash(ui, repo, *pats, **opts):
136 136 > ui.write(b'going to crash\n')
137 137 > raise Exception('.')
138 138 > EOF
139 139
140 140 $ cat > $TESTTMP/fakepager.py <<EOF
141 141 > import sys
142 142 > import time
143 143 > for line in iter(sys.stdin.readline, ''):
144 144 > if 'crash' in line: # only interested in lines containing 'crash'
145 145 > # if chg exits when pager is sleeping (incorrectly), the output
146 146 > # will be captured by the next test case
147 147 > time.sleep(1)
148 148 > sys.stdout.write('crash-pager: %s' % line)
149 149 > EOF
150 150
151 151 $ cat >> .hg/hgrc <<EOF
152 152 > [extensions]
153 153 > crash = $TESTTMP/crash.py
154 154 > EOF
155 155
156 156 $ chg crash --pager=on --config ui.formatted=True 2>/dev/null
157 157 crash-pager: going to crash
158 158 [255]
159 159
160 160 no stdout data should be printed after pager quits, and the buffered data
161 161 should never persist (issue6207)
162 162
163 163 "killed!" may be printed if terminated by SIGPIPE, which isn't important
164 164 in this test.
165 165
166 166 $ cat > $TESTTMP/bulkwrite.py <<'EOF'
167 167 > import time
168 168 > from mercurial import error, registrar
169 169 > cmdtable = {}
170 170 > command = registrar.command(cmdtable)
171 171 > @command(b'bulkwrite')
172 172 > def bulkwrite(ui, repo, *pats, **opts):
173 173 > ui.write(b'going to write massive data\n')
174 174 > ui.flush()
175 175 > t = time.time()
176 176 > while time.time() - t < 2:
177 177 > ui.write(b'x' * 1023 + b'\n') # will be interrupted by SIGPIPE
178 178 > raise error.Abort(b"write() doesn't block")
179 179 > EOF
180 180
181 181 $ cat > $TESTTMP/fakepager.py <<'EOF'
182 182 > import sys
183 183 > import time
184 184 > sys.stdout.write('paged! %r\n' % sys.stdin.readline())
185 185 > time.sleep(1) # new data will be written
186 186 > EOF
187 187
188 188 $ cat >> .hg/hgrc <<EOF
189 189 > [extensions]
190 190 > bulkwrite = $TESTTMP/bulkwrite.py
191 191 > EOF
192 192
193 193 $ chg bulkwrite --pager=on --color no --config ui.formatted=True
194 194 paged! 'going to write massive data\n'
195 195 killed! (?)
196 196 [255]
197 197
198 198 $ chg bulkwrite --pager=on --color no --config ui.formatted=True
199 199 paged! 'going to write massive data\n'
200 200 killed! (?)
201 201 [255]
202 202
203 203 $ cd ..
204 204
205 205 missing stdio
206 206 -------------
207 207
208 208 $ CHGDEBUG=1 chg version -q 0<&-
209 209 chg: debug: * stdio fds are missing (glob)
210 210 chg: debug: * execute original hg (glob)
211 211 Mercurial Distributed SCM * (glob)
212 212
213 213 server lifecycle
214 214 ----------------
215 215
216 216 chg server should be restarted on code change, and old server will shut down
217 217 automatically. In this test, we use the following time parameters:
218 218
219 219 - "sleep 1" to make mtime different
220 220 - "sleep 2" to notice mtime change (polling interval is 1 sec)
221 221
222 222 set up repository with an extension:
223 223
224 224 $ chg init extreload
225 225 $ cd extreload
226 226 $ touch dummyext.py
227 227 $ cat <<EOF >> .hg/hgrc
228 228 > [extensions]
229 229 > dummyext = dummyext.py
230 230 > EOF
231 231
232 232 isolate socket directory for stable result:
233 233
234 234 $ OLDCHGSOCKNAME=$CHGSOCKNAME
235 235 $ mkdir chgsock
236 236 $ CHGSOCKNAME=`pwd`/chgsock/server
237 237
238 238 warm up server:
239 239
240 240 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
241 241 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
242 242
243 243 new server should be started if extension modified:
244 244
245 245 $ sleep 1
246 246 $ touch dummyext.py
247 247 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
248 248 chg: debug: * instruction: unlink $TESTTMP/extreload/chgsock/server-* (glob)
249 249 chg: debug: * instruction: reconnect (glob)
250 250 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
251 251
252 252 old server will shut down, while new server should still be reachable:
253 253
254 254 $ sleep 2
255 255 $ CHGDEBUG= chg log 2>&1 | (egrep 'instruction|start' || true)
256 256
257 257 socket file should never be unlinked by old server:
258 258 (simulates unowned socket by updating mtime, which makes sure server exits
259 259 at polling cycle)
260 260
261 261 $ ls chgsock/server-*
262 262 chgsock/server-* (glob)
263 263 $ touch chgsock/server-*
264 264 $ sleep 2
265 265 $ ls chgsock/server-*
266 266 chgsock/server-* (glob)
267 267
268 268 since no server is reachable from socket file, new server should be started:
269 269 (this test makes sure that old server shut down automatically)
270 270
271 271 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
272 272 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
273 273
274 274 shut down servers and restore environment:
275 275
276 276 $ rm -R chgsock
277 277 $ sleep 2
278 278 $ CHGSOCKNAME=$OLDCHGSOCKNAME
279 279 $ cd ..
280 280
281 281 check that server events are recorded:
282 282
283 283 $ ls log
284 284 server.log
285 285 server.log.1
286 286
287 287 print only the last 10 lines, since we aren't sure how many records are
288 288 preserved (since setprocname isn't available on py3 and pure version,
289 289 the 10th-most-recent line is different when using py3):
290 290
291 291 $ cat log/server.log.1 log/server.log | tail -10 | filterlog
292 292 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ... (no-setprocname !)
293 293 YYYY/MM/DD HH:MM:SS (PID)> forked worker process (pid=...)
294 294 YYYY/MM/DD HH:MM:SS (PID)> setprocname: ... (setprocname !)
295 295 YYYY/MM/DD HH:MM:SS (PID)> received fds: ...
296 296 YYYY/MM/DD HH:MM:SS (PID)> chdir to '$TESTTMP/extreload'
297 297 YYYY/MM/DD HH:MM:SS (PID)> setumask 18
298 298 YYYY/MM/DD HH:MM:SS (PID)> setenv: ...
299 299 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ...
300 300 YYYY/MM/DD HH:MM:SS (PID)> validate: []
301 301 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
302 302 YYYY/MM/DD HH:MM:SS (PID)> $TESTTMP/extreload/chgsock/server-... is not owned, exiting.
303 303
304 304 global data mutated by schems
305 305 -----------------------------
306 306
307 307 $ hg init schemes
308 308 $ cd schemes
309 309
310 310 initial state
311 311
312 312 $ cat > .hg/hgrc <<'EOF'
313 313 > [extensions]
314 314 > schemes =
315 315 > [schemes]
316 316 > foo = https://foo.example.org/
317 317 > EOF
318 318 $ hg debugexpandscheme foo://expanded
319 319 https://foo.example.org/expanded
320 320 $ hg debugexpandscheme bar://unexpanded
321 321 bar://unexpanded
322 322
323 323 add bar
324 324
325 325 $ cat > .hg/hgrc <<'EOF'
326 326 > [extensions]
327 327 > schemes =
328 328 > [schemes]
329 329 > foo = https://foo.example.org/
330 330 > bar = https://bar.example.org/
331 331 > EOF
332 332 $ hg debugexpandscheme foo://expanded
333 333 https://foo.example.org/expanded
334 334 $ hg debugexpandscheme bar://expanded
335 335 https://bar.example.org/expanded
336 336
337 337 remove foo
338 338
339 339 $ cat > .hg/hgrc <<'EOF'
340 340 > [extensions]
341 341 > schemes =
342 342 > [schemes]
343 343 > bar = https://bar.example.org/
344 344 > EOF
345 345 $ hg debugexpandscheme foo://unexpanded
346 346 foo://unexpanded
347 347 $ hg debugexpandscheme bar://expanded
348 348 https://bar.example.org/expanded
349 349
350 350 $ cd ..
351 351
352 352 repository cache
353 353 ----------------
354 354
355 355 $ cp $HGRCPATH.unconfigured $HGRCPATH
356 356 $ cat <<'EOF' >> $HGRCPATH
357 357 > [cmdserver]
358 358 > log = $TESTTMP/log/server-cached.log
359 359 > max-repo-cache = 1
360 360 > track-log = command, repocache
361 361 > EOF
362 362
363 363 isolate socket directory for stable result:
364 364
365 365 $ OLDCHGSOCKNAME=$CHGSOCKNAME
366 366 $ mkdir chgsock
367 367 $ CHGSOCKNAME=`pwd`/chgsock/server
368 368
369 369 create empty repo and cache it:
370 370
371 371 $ hg init cached
372 372 $ hg id -R cached
373 373 000000000000 tip
374 374 $ sleep 1
375 375
376 376 modify repo (and cache will be invalidated):
377 377
378 378 $ touch cached/a
379 379 $ hg ci -R cached -Am 'add a'
380 380 adding a
381 381 $ sleep 1
382 382
383 383 read cached repo:
384 384
385 385 $ hg log -R cached
386 386 changeset: 0:ac82d8b1f7c4
387 387 tag: tip
388 388 user: test
389 389 date: Thu Jan 01 00:00:00 1970 +0000
390 390 summary: add a
391 391
392 392 $ sleep 1
393 393
394 394 discard cached from LRU cache:
395 395
396 396 $ hg clone cached cached2
397 397 updating to branch default
398 398 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 399 $ hg id -R cached2
400 400 ac82d8b1f7c4 tip
401 401 $ sleep 1
402 402
403 403 read uncached repo:
404 404
405 405 $ hg log -R cached
406 406 changeset: 0:ac82d8b1f7c4
407 407 tag: tip
408 408 user: test
409 409 date: Thu Jan 01 00:00:00 1970 +0000
410 410 summary: add a
411 411
412 412 $ sleep 1
413 413
414 414 shut down servers and restore environment:
415 415
416 416 $ rm -R chgsock
417 417 $ sleep 2
418 418 $ CHGSOCKNAME=$OLDCHGSOCKNAME
419 419
420 420 check server log:
421 421
422 422 $ cat log/server-cached.log | filterlog
423 423 YYYY/MM/DD HH:MM:SS (PID)> init cached
424 424 YYYY/MM/DD HH:MM:SS (PID)> id -R cached
425 425 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
426 426 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
427 427 YYYY/MM/DD HH:MM:SS (PID)> ci -R cached -Am 'add a'
428 428 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
429 429 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
430 430 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
431 431 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
432 432 YYYY/MM/DD HH:MM:SS (PID)> clone cached cached2
433 433 YYYY/MM/DD HH:MM:SS (PID)> id -R cached2
434 434 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached2 (in ...s)
435 435 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
436 436 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
437 437
438 438 Test that -R is interpreted relative to --cwd.
439 439
440 440 $ hg init repo1
441 441 $ mkdir -p a/b
442 442 $ hg init a/b/repo2
443 443 $ printf "[alias]\ntest=repo1\n" >> repo1/.hg/hgrc
444 444 $ printf "[alias]\ntest=repo2\n" >> a/b/repo2/.hg/hgrc
445 445 $ cd a
446 446 $ chg --cwd .. -R repo1 show alias.test
447 447 repo1
448 448 $ chg --cwd . -R b/repo2 show alias.test
449 449 repo2
450 450 $ cd ..
451 451
452 452 Test that chg works (sets to the user's actual LC_CTYPE) even when python
453 453 "coerces" the locale (py3.7+)
454 454
455 455 $ cat > $TESTTMP/debugenv.py <<EOF
456 456 > from mercurial import encoding
457 457 > from mercurial import registrar
458 458 > cmdtable = {}
459 459 > command = registrar.command(cmdtable)
460 460 > @command(b'debugenv', [], b'', norepo=True)
461 461 > def debugenv(ui):
462 462 > for k in [b'LC_ALL', b'LC_CTYPE', b'LANG']:
463 463 > v = encoding.environ.get(k)
464 464 > if v is not None:
465 465 > ui.write(b'%s=%s\n' % (k, encoding.environ[k]))
466 466 > EOF
467 467 (hg keeps python's modified LC_CTYPE, chg doesn't)
468 468 $ (unset LC_ALL; unset LANG; LC_CTYPE= "$CHGHG" \
469 469 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
470 470 LC_CTYPE=C.UTF-8 (py37 !)
471 471 LC_CTYPE= (no-py37 !)
472 472 $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
473 473 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
474 474 LC_CTYPE=
475 475 $ (unset LC_ALL; unset LANG; LC_CTYPE=unsupported_value chg \
476 476 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
477 477 *cannot change locale* (glob) (?)
478 478 LC_CTYPE=unsupported_value
479 479 $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
480 480 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
481 481 LC_CTYPE=
482 482 $ LANG= LC_ALL= LC_CTYPE= chg \
483 483 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv
484 484 LC_ALL=
485 485 LC_CTYPE=
486 486 LANG=
487 487
488 488 Profiling isn't permanently enabled or carried over between chg invocations that
489 489 share the same server
490 490 $ cp $HGRCPATH.orig $HGRCPATH
491 491 $ hg init $TESTTMP/profiling
492 492 $ cd $TESTTMP/profiling
493 493 $ filteredchg() {
494 494 > CHGDEBUG=1 chg "$@" 2>&1 | sed -rn 's_^No samples recorded.*$_Sample count: 0_; /Sample count/p; /start cmdserver/p'
495 495 > }
496 496 $ newchg() {
497 497 > chg --kill-chg-daemon
498 498 > filteredchg "$@" | egrep -v 'start cmdserver' || true
499 499 > }
500 500 (--profile isn't permanently on just because it was specified when chg was
501 501 started)
502 502 $ newchg log -r . --profile
503 503 Sample count: * (glob)
504 504 $ filteredchg log -r .
505 505 (enabling profiling via config works, even on the first chg command that starts
506 506 a cmdserver)
507 507 $ cat >> $HGRCPATH <<EOF
508 508 > [profiling]
509 509 > type=stat
510 510 > enabled=1
511 511 > EOF
512 512 $ newchg log -r .
513 513 Sample count: * (glob)
514 514 $ filteredchg log -r .
515 515 Sample count: * (glob)
516 516 (test that we aren't accumulating more and more samples each run)
517 517 $ cat > $TESTTMP/debugsleep.py <<EOF
518 518 > import time
519 519 > from mercurial import registrar
520 520 > cmdtable = {}
521 521 > command = registrar.command(cmdtable)
522 522 > @command(b'debugsleep', [], b'', norepo=True)
523 523 > def debugsleep(ui):
524 524 > start = time.time()
525 525 > x = 0
526 526 > while time.time() < start + 0.5:
527 527 > time.sleep(.1)
528 528 > x += 1
529 529 > ui.status(b'%d debugsleep iterations in %.03fs\n' % (x, time.time() - start))
530 530 > EOF
531 531 $ cat >> $HGRCPATH <<EOF
532 532 > [extensions]
533 533 > debugsleep = $TESTTMP/debugsleep.py
534 534 > EOF
535 535 $ newchg debugsleep > run_1
536 536 $ filteredchg debugsleep > run_2
537 537 $ filteredchg debugsleep > run_3
538 538 $ filteredchg debugsleep > run_4
539 539 FIXME: Run 4 should not be >3x Run 1's number of samples.
540 540 $ "$PYTHON" <<EOF
541 541 > r1 = int(open("run_1", "r").read().split()[-1])
542 542 > r4 = int(open("run_4", "r").read().split()[-1])
543 543 > print("Run 1: %d samples\nRun 4: %d samples\nRun 4 > 3 * Run 1: %s" %
544 544 > (r1, r4, r4 > (r1 * 3)))
545 545 > EOF
546 546 Run 1: * samples (glob)
547 547 Run 4: * samples (glob)
548 548 Run 4 > 3 * Run 1: False
549 549 (Disabling with --no-profile on the commandline still works, but isn't permanent)
550 550 $ newchg log -r . --no-profile
551 551 $ filteredchg log -r .
552 552 Sample count: * (glob)
553 553 $ filteredchg log -r . --no-profile
554 554 $ filteredchg log -r .
555 555 Sample count: * (glob)
556
557 chg setting CHGHG itself
558 ------------------------
559
560 If CHGHG is not set, chg will set it before spawning the command server.
561 $ hg --kill-chg-daemon
562 $ HG=$CHGHG CHGHG= CHGDEBUG= hg debugshell -c \
563 > 'ui.write(b"CHGHG=%s\n" % ui.environ.get(b"CHGHG"))' 2>&1 \
564 > | egrep 'CHGHG|start'
565 chg: debug: * start cmdserver at * (glob)
566 CHGHG=/*/install/bin/hg (glob)
567
568 Running the same command a second time shouldn't spawn a new command server.
569 $ HG=$CHGHG CHGHG= CHGDEBUG= hg debugshell -c \
570 > 'ui.write(b"CHGHG=%s\n" % ui.environ.get(b"CHGHG"))' 2>&1 \
571 > | egrep 'CHGHG|start'
572 CHGHG=/*/install/bin/hg (glob)
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now