##// END OF EJS Templates
merge with stable
Matt Mackall -
r24163:bb110815 merge default
parent child Browse files
Show More

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

@@ -1,104 +1,105 b''
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
79 335a558f81dc73afeab4d7be63617392b130117f 0 iQIVAwUAUiZrIyBXgaxoKi1yAQK2iw//cquNqqSkc8Re5/TZT9I6NH+lh6DbOKjJP0Xl1Wqq0K+KSIUgZG4G32ovaEb2l5X0uY+3unRPiZ0ebl0YSw4Fb2ZiPIADXLBTOYRrY2Wwd3tpJeGI6wEgZt3SfcITV/g7NJrCjT3FlYoSOIayrExM80InSdcEM0Q3Rx6HKzY2acyxzgZeAtAW5ohFvHilSvY6p5Gcm4+QptMxvw45GPdreUmjeXZxNXNXZ8P+MjMz/QJbai/N7PjmK8lqnhkBsT48Ng/KhhmOkGntNJ2/ImBWLFGcWngSvJ7sfWwnyhndvGhe0Hq1NcCf7I8TjNDxU5TR+m+uW7xjXdLoDbUjBdX4sKXnh8ZjbYiODKBOrrDq25cf8nA/tnpKyE/qsVy60kOk6loY4XKiYmn1V49Ta0emmDx0hqo3HgxHHsHX0NDnGdWGol7cPRET0RzVobKq1A0jnrhPooWidvLh9bPzLonrWDo+ib+DuySoRkuYUK4pgZJ2mbg6daFOBEZygkSyRB8bo1UQUP7EgQDrWe4khb/5GHEfDkrQz3qu/sXvc0Ir1mOUWBFPHC2DjjCn/oMJuUkG1SwM8l2Bfv7h67ssES6YQ2+RjOix4yid7EXS/Ogl45PzCIPSI5+BbNs10JhE0w5uErBHlF53EDTe/TSLc+GU6DB6PP6dH912Njdr3jpNSUQ=
79 335a558f81dc73afeab4d7be63617392b130117f 0 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
@@ -1,117 +1,118 b''
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
@@ -1,586 +1,586 b''
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''largefiles utility code: must not import other modules in this package.'''
9 '''largefiles utility code: must not import other modules in this package.'''
10
10
11 import os
11 import os
12 import platform
12 import platform
13 import shutil
13 import shutil
14 import stat
14 import stat
15 import copy
15 import copy
16
16
17 from mercurial import dirstate, httpconnection, match as match_, util, scmutil
17 from mercurial import dirstate, httpconnection, match as match_, util, scmutil
18 from mercurial.i18n import _
18 from mercurial.i18n import _
19 from mercurial import node
19 from mercurial import node
20
20
21 shortname = '.hglf'
21 shortname = '.hglf'
22 shortnameslash = shortname + '/'
22 shortnameslash = shortname + '/'
23 longname = 'largefiles'
23 longname = 'largefiles'
24
24
25
25
26 # -- Private worker functions ------------------------------------------
26 # -- Private worker functions ------------------------------------------
27
27
28 def getminsize(ui, assumelfiles, opt, default=10):
28 def getminsize(ui, assumelfiles, opt, default=10):
29 lfsize = opt
29 lfsize = opt
30 if not lfsize and assumelfiles:
30 if not lfsize and assumelfiles:
31 lfsize = ui.config(longname, 'minsize', default=default)
31 lfsize = ui.config(longname, 'minsize', default=default)
32 if lfsize:
32 if lfsize:
33 try:
33 try:
34 lfsize = float(lfsize)
34 lfsize = float(lfsize)
35 except ValueError:
35 except ValueError:
36 raise util.Abort(_('largefiles: size must be number (not %s)\n')
36 raise util.Abort(_('largefiles: size must be number (not %s)\n')
37 % lfsize)
37 % lfsize)
38 if lfsize is None:
38 if lfsize is None:
39 raise util.Abort(_('minimum size for largefiles must be specified'))
39 raise util.Abort(_('minimum size for largefiles must be specified'))
40 return lfsize
40 return lfsize
41
41
42 def link(src, dest):
42 def link(src, dest):
43 util.makedirs(os.path.dirname(dest))
43 util.makedirs(os.path.dirname(dest))
44 try:
44 try:
45 util.oslink(src, dest)
45 util.oslink(src, dest)
46 except OSError:
46 except OSError:
47 # if hardlinks fail, fallback on atomic copy
47 # if hardlinks fail, fallback on atomic copy
48 dst = util.atomictempfile(dest)
48 dst = util.atomictempfile(dest)
49 for chunk in util.filechunkiter(open(src, 'rb')):
49 for chunk in util.filechunkiter(open(src, 'rb')):
50 dst.write(chunk)
50 dst.write(chunk)
51 dst.close()
51 dst.close()
52 os.chmod(dest, os.stat(src).st_mode)
52 os.chmod(dest, os.stat(src).st_mode)
53
53
54 def usercachepath(ui, hash):
54 def usercachepath(ui, hash):
55 path = ui.configpath(longname, 'usercache', None)
55 path = ui.configpath(longname, 'usercache', None)
56 if path:
56 if path:
57 path = os.path.join(path, hash)
57 path = os.path.join(path, hash)
58 else:
58 else:
59 if os.name == 'nt':
59 if os.name == 'nt':
60 appdata = os.getenv('LOCALAPPDATA', os.getenv('APPDATA'))
60 appdata = os.getenv('LOCALAPPDATA', os.getenv('APPDATA'))
61 if appdata:
61 if appdata:
62 path = os.path.join(appdata, longname, hash)
62 path = os.path.join(appdata, longname, hash)
63 elif platform.system() == 'Darwin':
63 elif platform.system() == 'Darwin':
64 home = os.getenv('HOME')
64 home = os.getenv('HOME')
65 if home:
65 if home:
66 path = os.path.join(home, 'Library', 'Caches',
66 path = os.path.join(home, 'Library', 'Caches',
67 longname, hash)
67 longname, hash)
68 elif os.name == 'posix':
68 elif os.name == 'posix':
69 path = os.getenv('XDG_CACHE_HOME')
69 path = os.getenv('XDG_CACHE_HOME')
70 if path:
70 if path:
71 path = os.path.join(path, longname, hash)
71 path = os.path.join(path, longname, hash)
72 else:
72 else:
73 home = os.getenv('HOME')
73 home = os.getenv('HOME')
74 if home:
74 if home:
75 path = os.path.join(home, '.cache', longname, hash)
75 path = os.path.join(home, '.cache', longname, hash)
76 else:
76 else:
77 raise util.Abort(_('unknown operating system: %s\n') % os.name)
77 raise util.Abort(_('unknown operating system: %s\n') % os.name)
78 return path
78 return path
79
79
80 def inusercache(ui, hash):
80 def inusercache(ui, hash):
81 path = usercachepath(ui, hash)
81 path = usercachepath(ui, hash)
82 return path and os.path.exists(path)
82 return path and os.path.exists(path)
83
83
84 def findfile(repo, hash):
84 def findfile(repo, hash):
85 if instore(repo, hash):
85 if instore(repo, hash):
86 repo.ui.note(_('found %s in store\n') % hash)
86 repo.ui.note(_('found %s in store\n') % hash)
87 return storepath(repo, hash)
87 return storepath(repo, hash)
88 elif inusercache(repo.ui, hash):
88 elif inusercache(repo.ui, hash):
89 repo.ui.note(_('found %s in system cache\n') % hash)
89 repo.ui.note(_('found %s in system cache\n') % hash)
90 path = storepath(repo, hash)
90 path = storepath(repo, hash)
91 link(usercachepath(repo.ui, hash), path)
91 link(usercachepath(repo.ui, hash), path)
92 return path
92 return path
93 return None
93 return None
94
94
95 class largefilesdirstate(dirstate.dirstate):
95 class largefilesdirstate(dirstate.dirstate):
96 def __getitem__(self, key):
96 def __getitem__(self, key):
97 return super(largefilesdirstate, self).__getitem__(unixpath(key))
97 return super(largefilesdirstate, self).__getitem__(unixpath(key))
98 def normal(self, f):
98 def normal(self, f):
99 return super(largefilesdirstate, self).normal(unixpath(f))
99 return super(largefilesdirstate, self).normal(unixpath(f))
100 def remove(self, f):
100 def remove(self, f):
101 return super(largefilesdirstate, self).remove(unixpath(f))
101 return super(largefilesdirstate, self).remove(unixpath(f))
102 def add(self, f):
102 def add(self, f):
103 return super(largefilesdirstate, self).add(unixpath(f))
103 return super(largefilesdirstate, self).add(unixpath(f))
104 def drop(self, f):
104 def drop(self, f):
105 return super(largefilesdirstate, self).drop(unixpath(f))
105 return super(largefilesdirstate, self).drop(unixpath(f))
106 def forget(self, f):
106 def forget(self, f):
107 return super(largefilesdirstate, self).forget(unixpath(f))
107 return super(largefilesdirstate, self).forget(unixpath(f))
108 def normallookup(self, f):
108 def normallookup(self, f):
109 return super(largefilesdirstate, self).normallookup(unixpath(f))
109 return super(largefilesdirstate, self).normallookup(unixpath(f))
110 def _ignore(self, f):
110 def _ignore(self, f):
111 return False
111 return False
112
112
113 def openlfdirstate(ui, repo, create=True):
113 def openlfdirstate(ui, repo, create=True):
114 '''
114 '''
115 Return a dirstate object that tracks largefiles: i.e. its root is
115 Return a dirstate object that tracks largefiles: i.e. its root is
116 the repo root, but it is saved in .hg/largefiles/dirstate.
116 the repo root, but it is saved in .hg/largefiles/dirstate.
117 '''
117 '''
118 lfstoredir = repo.join(longname)
118 lfstoredir = repo.join(longname)
119 opener = scmutil.opener(lfstoredir)
119 opener = scmutil.opener(lfstoredir)
120 lfdirstate = largefilesdirstate(opener, ui, repo.root,
120 lfdirstate = largefilesdirstate(opener, ui, repo.root,
121 repo.dirstate._validate)
121 repo.dirstate._validate)
122
122
123 # If the largefiles dirstate does not exist, populate and create
123 # If the largefiles dirstate does not exist, populate and create
124 # it. This ensures that we create it on the first meaningful
124 # it. This ensures that we create it on the first meaningful
125 # largefiles operation in a new clone.
125 # largefiles operation in a new clone.
126 if create and not os.path.exists(os.path.join(lfstoredir, 'dirstate')):
126 if create and not os.path.exists(os.path.join(lfstoredir, 'dirstate')):
127 matcher = getstandinmatcher(repo)
127 matcher = getstandinmatcher(repo)
128 standins = repo.dirstate.walk(matcher, [], False, False)
128 standins = repo.dirstate.walk(matcher, [], False, False)
129
129
130 if len(standins) > 0:
130 if len(standins) > 0:
131 util.makedirs(lfstoredir)
131 util.makedirs(lfstoredir)
132
132
133 for standin in standins:
133 for standin in standins:
134 lfile = splitstandin(standin)
134 lfile = splitstandin(standin)
135 lfdirstate.normallookup(lfile)
135 lfdirstate.normallookup(lfile)
136 return lfdirstate
136 return lfdirstate
137
137
138 def lfdirstatestatus(lfdirstate, repo):
138 def lfdirstatestatus(lfdirstate, repo):
139 wctx = repo['.']
139 wctx = repo['.']
140 match = match_.always(repo.root, repo.getcwd())
140 match = match_.always(repo.root, repo.getcwd())
141 unsure, s = lfdirstate.status(match, [], False, False, False)
141 unsure, s = lfdirstate.status(match, [], False, False, False)
142 modified, clean = s.modified, s.clean
142 modified, clean = s.modified, s.clean
143 for lfile in unsure:
143 for lfile in unsure:
144 try:
144 try:
145 fctx = wctx[standin(lfile)]
145 fctx = wctx[standin(lfile)]
146 except LookupError:
146 except LookupError:
147 fctx = None
147 fctx = None
148 if not fctx or fctx.data().strip() != hashfile(repo.wjoin(lfile)):
148 if not fctx or fctx.data().strip() != hashfile(repo.wjoin(lfile)):
149 modified.append(lfile)
149 modified.append(lfile)
150 else:
150 else:
151 clean.append(lfile)
151 clean.append(lfile)
152 lfdirstate.normal(lfile)
152 lfdirstate.normal(lfile)
153 return s
153 return s
154
154
155 def listlfiles(repo, rev=None, matcher=None):
155 def listlfiles(repo, rev=None, matcher=None):
156 '''return a list of largefiles in the working copy or the
156 '''return a list of largefiles in the working copy or the
157 specified changeset'''
157 specified changeset'''
158
158
159 if matcher is None:
159 if matcher is None:
160 matcher = getstandinmatcher(repo)
160 matcher = getstandinmatcher(repo)
161
161
162 # ignore unknown files in working directory
162 # ignore unknown files in working directory
163 return [splitstandin(f)
163 return [splitstandin(f)
164 for f in repo[rev].walk(matcher)
164 for f in repo[rev].walk(matcher)
165 if rev is not None or repo.dirstate[f] != '?']
165 if rev is not None or repo.dirstate[f] != '?']
166
166
167 def instore(repo, hash):
167 def instore(repo, hash):
168 return os.path.exists(storepath(repo, hash))
168 return os.path.exists(storepath(repo, hash))
169
169
170 def storepath(repo, hash):
170 def storepath(repo, hash):
171 return repo.join(os.path.join(longname, hash))
171 return repo.join(os.path.join(longname, hash))
172
172
173 def copyfromcache(repo, hash, filename):
173 def copyfromcache(repo, hash, filename):
174 '''Copy the specified largefile from the repo or system cache to
174 '''Copy the specified largefile from the repo or system cache to
175 filename in the repository. Return true on success or false if the
175 filename in the repository. Return true on success or false if the
176 file was not found in either cache (which should not happened:
176 file was not found in either cache (which should not happened:
177 this is meant to be called only after ensuring that the needed
177 this is meant to be called only after ensuring that the needed
178 largefile exists in the cache).'''
178 largefile exists in the cache).'''
179 path = findfile(repo, hash)
179 path = findfile(repo, hash)
180 if path is None:
180 if path is None:
181 return False
181 return False
182 util.makedirs(os.path.dirname(repo.wjoin(filename)))
182 util.makedirs(os.path.dirname(repo.wjoin(filename)))
183 # The write may fail before the file is fully written, but we
183 # The write may fail before the file is fully written, but we
184 # don't use atomic writes in the working copy.
184 # don't use atomic writes in the working copy.
185 shutil.copy(path, repo.wjoin(filename))
185 shutil.copy(path, repo.wjoin(filename))
186 return True
186 return True
187
187
188 def copytostore(repo, rev, file, uploaded=False):
188 def copytostore(repo, rev, file, uploaded=False):
189 hash = readstandin(repo, file, rev)
189 hash = readstandin(repo, file, rev)
190 if instore(repo, hash):
190 if instore(repo, hash):
191 return
191 return
192 copytostoreabsolute(repo, repo.wjoin(file), hash)
192 copytostoreabsolute(repo, repo.wjoin(file), hash)
193
193
194 def copyalltostore(repo, node):
194 def copyalltostore(repo, node):
195 '''Copy all largefiles in a given revision to the store'''
195 '''Copy all largefiles in a given revision to the store'''
196
196
197 ctx = repo[node]
197 ctx = repo[node]
198 for filename in ctx.files():
198 for filename in ctx.files():
199 if isstandin(filename) and filename in ctx.manifest():
199 if isstandin(filename) and filename in ctx.manifest():
200 realfile = splitstandin(filename)
200 realfile = splitstandin(filename)
201 copytostore(repo, ctx.node(), realfile)
201 copytostore(repo, ctx.node(), realfile)
202
202
203
203
204 def copytostoreabsolute(repo, file, hash):
204 def copytostoreabsolute(repo, file, hash):
205 if inusercache(repo.ui, hash):
205 if inusercache(repo.ui, hash):
206 link(usercachepath(repo.ui, hash), storepath(repo, hash))
206 link(usercachepath(repo.ui, hash), storepath(repo, hash))
207 else:
207 else:
208 util.makedirs(os.path.dirname(storepath(repo, hash)))
208 util.makedirs(os.path.dirname(storepath(repo, hash)))
209 dst = util.atomictempfile(storepath(repo, hash),
209 dst = util.atomictempfile(storepath(repo, hash),
210 createmode=repo.store.createmode)
210 createmode=repo.store.createmode)
211 for chunk in util.filechunkiter(open(file, 'rb')):
211 for chunk in util.filechunkiter(open(file, 'rb')):
212 dst.write(chunk)
212 dst.write(chunk)
213 dst.close()
213 dst.close()
214 linktousercache(repo, hash)
214 linktousercache(repo, hash)
215
215
216 def linktousercache(repo, hash):
216 def linktousercache(repo, hash):
217 path = usercachepath(repo.ui, hash)
217 path = usercachepath(repo.ui, hash)
218 if path:
218 if path:
219 link(storepath(repo, hash), path)
219 link(storepath(repo, hash), path)
220
220
221 def getstandinmatcher(repo, pats=[], opts={}):
221 def getstandinmatcher(repo, pats=[], opts={}):
222 '''Return a match object that applies pats to the standin directory'''
222 '''Return a match object that applies pats to the standin directory'''
223 standindir = repo.wjoin(shortname)
223 standindir = repo.wjoin(shortname)
224 if pats:
224 if pats:
225 pats = [os.path.join(standindir, pat) for pat in pats]
225 pats = [os.path.join(standindir, pat) for pat in pats]
226 else:
226 else:
227 # no patterns: relative to repo root
227 # no patterns: relative to repo root
228 pats = [standindir]
228 pats = [standindir]
229 # no warnings about missing files or directories
229 # no warnings about missing files or directories
230 match = scmutil.match(repo[None], pats, opts)
230 match = scmutil.match(repo[None], pats, opts)
231 match.bad = lambda f, msg: None
231 match.bad = lambda f, msg: None
232 return match
232 return match
233
233
234 def composestandinmatcher(repo, rmatcher):
234 def composestandinmatcher(repo, rmatcher):
235 '''Return a matcher that accepts standins corresponding to the
235 '''Return a matcher that accepts standins corresponding to the
236 files accepted by rmatcher. Pass the list of files in the matcher
236 files accepted by rmatcher. Pass the list of files in the matcher
237 as the paths specified by the user.'''
237 as the paths specified by the user.'''
238 smatcher = getstandinmatcher(repo, rmatcher.files())
238 smatcher = getstandinmatcher(repo, rmatcher.files())
239 isstandin = smatcher.matchfn
239 isstandin = smatcher.matchfn
240 def composedmatchfn(f):
240 def composedmatchfn(f):
241 return isstandin(f) and rmatcher.matchfn(splitstandin(f))
241 return isstandin(f) and rmatcher.matchfn(splitstandin(f))
242 smatcher.matchfn = composedmatchfn
242 smatcher.matchfn = composedmatchfn
243
243
244 return smatcher
244 return smatcher
245
245
246 def standin(filename):
246 def standin(filename):
247 '''Return the repo-relative path to the standin for the specified big
247 '''Return the repo-relative path to the standin for the specified big
248 file.'''
248 file.'''
249 # Notes:
249 # Notes:
250 # 1) Some callers want an absolute path, but for instance addlargefiles
250 # 1) Some callers want an absolute path, but for instance addlargefiles
251 # needs it repo-relative so it can be passed to repo[None].add(). So
251 # needs it repo-relative so it can be passed to repo[None].add(). So
252 # leave it up to the caller to use repo.wjoin() to get an absolute path.
252 # leave it up to the caller to use repo.wjoin() to get an absolute path.
253 # 2) Join with '/' because that's what dirstate always uses, even on
253 # 2) Join with '/' because that's what dirstate always uses, even on
254 # Windows. Change existing separator to '/' first in case we are
254 # Windows. Change existing separator to '/' first in case we are
255 # passed filenames from an external source (like the command line).
255 # passed filenames from an external source (like the command line).
256 return shortnameslash + util.pconvert(filename)
256 return shortnameslash + util.pconvert(filename)
257
257
258 def isstandin(filename):
258 def isstandin(filename):
259 '''Return true if filename is a big file standin. filename must be
259 '''Return true if filename is a big file standin. filename must be
260 in Mercurial's internal form (slash-separated).'''
260 in Mercurial's internal form (slash-separated).'''
261 return filename.startswith(shortnameslash)
261 return filename.startswith(shortnameslash)
262
262
263 def splitstandin(filename):
263 def splitstandin(filename):
264 # Split on / because that's what dirstate always uses, even on Windows.
264 # Split on / because that's what dirstate always uses, even on Windows.
265 # Change local separator to / first just in case we are passed filenames
265 # Change local separator to / first just in case we are passed filenames
266 # from an external source (like the command line).
266 # from an external source (like the command line).
267 bits = util.pconvert(filename).split('/', 1)
267 bits = util.pconvert(filename).split('/', 1)
268 if len(bits) == 2 and bits[0] == shortname:
268 if len(bits) == 2 and bits[0] == shortname:
269 return bits[1]
269 return bits[1]
270 else:
270 else:
271 return None
271 return None
272
272
273 def updatestandin(repo, standin):
273 def updatestandin(repo, standin):
274 file = repo.wjoin(splitstandin(standin))
274 file = repo.wjoin(splitstandin(standin))
275 if os.path.exists(file):
275 if os.path.exists(file):
276 hash = hashfile(file)
276 hash = hashfile(file)
277 executable = getexecutable(file)
277 executable = getexecutable(file)
278 writestandin(repo, standin, hash, executable)
278 writestandin(repo, standin, hash, executable)
279
279
280 def readstandin(repo, filename, node=None):
280 def readstandin(repo, filename, node=None):
281 '''read hex hash from standin for filename at given node, or working
281 '''read hex hash from standin for filename at given node, or working
282 directory if no node is given'''
282 directory if no node is given'''
283 return repo[node][standin(filename)].data().strip()
283 return repo[node][standin(filename)].data().strip()
284
284
285 def writestandin(repo, standin, hash, executable):
285 def writestandin(repo, standin, hash, executable):
286 '''write hash to <repo.root>/<standin>'''
286 '''write hash to <repo.root>/<standin>'''
287 repo.wwrite(standin, hash + '\n', executable and 'x' or '')
287 repo.wwrite(standin, hash + '\n', executable and 'x' or '')
288
288
289 def copyandhash(instream, outfile):
289 def copyandhash(instream, outfile):
290 '''Read bytes from instream (iterable) and write them to outfile,
290 '''Read bytes from instream (iterable) and write them to outfile,
291 computing the SHA-1 hash of the data along the way. Return the hash.'''
291 computing the SHA-1 hash of the data along the way. Return the hash.'''
292 hasher = util.sha1('')
292 hasher = util.sha1('')
293 for data in instream:
293 for data in instream:
294 hasher.update(data)
294 hasher.update(data)
295 outfile.write(data)
295 outfile.write(data)
296 return hasher.hexdigest()
296 return hasher.hexdigest()
297
297
298 def hashrepofile(repo, file):
298 def hashrepofile(repo, file):
299 return hashfile(repo.wjoin(file))
299 return hashfile(repo.wjoin(file))
300
300
301 def hashfile(file):
301 def hashfile(file):
302 if not os.path.exists(file):
302 if not os.path.exists(file):
303 return ''
303 return ''
304 hasher = util.sha1('')
304 hasher = util.sha1('')
305 fd = open(file, 'rb')
305 fd = open(file, 'rb')
306 for data in util.filechunkiter(fd, 128 * 1024):
306 for data in util.filechunkiter(fd, 128 * 1024):
307 hasher.update(data)
307 hasher.update(data)
308 fd.close()
308 fd.close()
309 return hasher.hexdigest()
309 return hasher.hexdigest()
310
310
311 def getexecutable(filename):
311 def getexecutable(filename):
312 mode = os.stat(filename).st_mode
312 mode = os.stat(filename).st_mode
313 return ((mode & stat.S_IXUSR) and
313 return ((mode & stat.S_IXUSR) and
314 (mode & stat.S_IXGRP) and
314 (mode & stat.S_IXGRP) and
315 (mode & stat.S_IXOTH))
315 (mode & stat.S_IXOTH))
316
316
317 def urljoin(first, second, *arg):
317 def urljoin(first, second, *arg):
318 def join(left, right):
318 def join(left, right):
319 if not left.endswith('/'):
319 if not left.endswith('/'):
320 left += '/'
320 left += '/'
321 if right.startswith('/'):
321 if right.startswith('/'):
322 right = right[1:]
322 right = right[1:]
323 return left + right
323 return left + right
324
324
325 url = join(first, second)
325 url = join(first, second)
326 for a in arg:
326 for a in arg:
327 url = join(url, a)
327 url = join(url, a)
328 return url
328 return url
329
329
330 def hexsha1(data):
330 def hexsha1(data):
331 """hexsha1 returns the hex-encoded sha1 sum of the data in the file-like
331 """hexsha1 returns the hex-encoded sha1 sum of the data in the file-like
332 object data"""
332 object data"""
333 h = util.sha1()
333 h = util.sha1()
334 for chunk in util.filechunkiter(data):
334 for chunk in util.filechunkiter(data):
335 h.update(chunk)
335 h.update(chunk)
336 return h.hexdigest()
336 return h.hexdigest()
337
337
338 def httpsendfile(ui, filename):
338 def httpsendfile(ui, filename):
339 return httpconnection.httpsendfile(ui, filename, 'rb')
339 return httpconnection.httpsendfile(ui, filename, 'rb')
340
340
341 def unixpath(path):
341 def unixpath(path):
342 '''Return a version of path normalized for use with the lfdirstate.'''
342 '''Return a version of path normalized for use with the lfdirstate.'''
343 return util.pconvert(os.path.normpath(path))
343 return util.pconvert(os.path.normpath(path))
344
344
345 def islfilesrepo(repo):
345 def islfilesrepo(repo):
346 if ('largefiles' in repo.requirements and
346 if ('largefiles' in repo.requirements and
347 util.any(shortnameslash in f[0] for f in repo.store.datafiles())):
347 util.any(shortnameslash in f[0] for f in repo.store.datafiles())):
348 return True
348 return True
349
349
350 return util.any(openlfdirstate(repo.ui, repo, False))
350 return util.any(openlfdirstate(repo.ui, repo, False))
351
351
352 class storeprotonotcapable(Exception):
352 class storeprotonotcapable(Exception):
353 def __init__(self, storetypes):
353 def __init__(self, storetypes):
354 self.storetypes = storetypes
354 self.storetypes = storetypes
355
355
356 def getstandinsstate(repo):
356 def getstandinsstate(repo):
357 standins = []
357 standins = []
358 matcher = getstandinmatcher(repo)
358 matcher = getstandinmatcher(repo)
359 for standin in repo.dirstate.walk(matcher, [], False, False):
359 for standin in repo.dirstate.walk(matcher, [], False, False):
360 lfile = splitstandin(standin)
360 lfile = splitstandin(standin)
361 try:
361 try:
362 hash = readstandin(repo, lfile)
362 hash = readstandin(repo, lfile)
363 except IOError:
363 except IOError:
364 hash = None
364 hash = None
365 standins.append((lfile, hash))
365 standins.append((lfile, hash))
366 return standins
366 return standins
367
367
368 def synclfdirstate(repo, lfdirstate, lfile, normallookup):
368 def synclfdirstate(repo, lfdirstate, lfile, normallookup):
369 lfstandin = standin(lfile)
369 lfstandin = standin(lfile)
370 if lfstandin in repo.dirstate:
370 if lfstandin in repo.dirstate:
371 stat = repo.dirstate._map[lfstandin]
371 stat = repo.dirstate._map[lfstandin]
372 state, mtime = stat[0], stat[3]
372 state, mtime = stat[0], stat[3]
373 else:
373 else:
374 state, mtime = '?', -1
374 state, mtime = '?', -1
375 if state == 'n':
375 if state == 'n':
376 if normallookup or mtime < 0:
376 if normallookup or mtime < 0:
377 # state 'n' doesn't ensure 'clean' in this case
377 # state 'n' doesn't ensure 'clean' in this case
378 lfdirstate.normallookup(lfile)
378 lfdirstate.normallookup(lfile)
379 else:
379 else:
380 lfdirstate.normal(lfile)
380 lfdirstate.normal(lfile)
381 elif state == 'm':
381 elif state == 'm':
382 lfdirstate.normallookup(lfile)
382 lfdirstate.normallookup(lfile)
383 elif state == 'r':
383 elif state == 'r':
384 lfdirstate.remove(lfile)
384 lfdirstate.remove(lfile)
385 elif state == 'a':
385 elif state == 'a':
386 lfdirstate.add(lfile)
386 lfdirstate.add(lfile)
387 elif state == '?':
387 elif state == '?':
388 lfdirstate.drop(lfile)
388 lfdirstate.drop(lfile)
389
389
390 def markcommitted(orig, ctx, node):
390 def markcommitted(orig, ctx, node):
391 repo = ctx._repo
391 repo = ctx._repo
392
392
393 orig(node)
393 orig(node)
394
394
395 # ATTENTION: "ctx.files()" may differ from "repo[node].files()"
395 # ATTENTION: "ctx.files()" may differ from "repo[node].files()"
396 # because files coming from the 2nd parent are omitted in the latter.
396 # because files coming from the 2nd parent are omitted in the latter.
397 #
397 #
398 # The former should be used to get targets of "synclfdirstate",
398 # The former should be used to get targets of "synclfdirstate",
399 # because such files:
399 # because such files:
400 # - are marked as "a" by "patch.patch()" (e.g. via transplant), and
400 # - are marked as "a" by "patch.patch()" (e.g. via transplant), and
401 # - have to be marked as "n" after commit, but
401 # - have to be marked as "n" after commit, but
402 # - aren't listed in "repo[node].files()"
402 # - aren't listed in "repo[node].files()"
403
403
404 lfdirstate = openlfdirstate(repo.ui, repo)
404 lfdirstate = openlfdirstate(repo.ui, repo)
405 for f in ctx.files():
405 for f in ctx.files():
406 if isstandin(f):
406 if isstandin(f):
407 lfile = splitstandin(f)
407 lfile = splitstandin(f)
408 synclfdirstate(repo, lfdirstate, lfile, False)
408 synclfdirstate(repo, lfdirstate, lfile, False)
409 lfdirstate.write()
409 lfdirstate.write()
410
410
411 # As part of committing, copy all of the largefiles into the cache.
411 # As part of committing, copy all of the largefiles into the cache.
412 copyalltostore(repo, node)
412 copyalltostore(repo, node)
413
413
414 def getlfilestoupdate(oldstandins, newstandins):
414 def getlfilestoupdate(oldstandins, newstandins):
415 changedstandins = set(oldstandins).symmetric_difference(set(newstandins))
415 changedstandins = set(oldstandins).symmetric_difference(set(newstandins))
416 filelist = []
416 filelist = []
417 for f in changedstandins:
417 for f in changedstandins:
418 if f[0] not in filelist:
418 if f[0] not in filelist:
419 filelist.append(f[0])
419 filelist.append(f[0])
420 return filelist
420 return filelist
421
421
422 def getlfilestoupload(repo, missing, addfunc):
422 def getlfilestoupload(repo, missing, addfunc):
423 for i, n in enumerate(missing):
423 for i, n in enumerate(missing):
424 repo.ui.progress(_('finding outgoing largefiles'), i,
424 repo.ui.progress(_('finding outgoing largefiles'), i,
425 unit=_('revision'), total=len(missing))
425 unit=_('revision'), total=len(missing))
426 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
426 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
427
427
428 oldlfstatus = repo.lfstatus
428 oldlfstatus = repo.lfstatus
429 repo.lfstatus = False
429 repo.lfstatus = False
430 try:
430 try:
431 ctx = repo[n]
431 ctx = repo[n]
432 finally:
432 finally:
433 repo.lfstatus = oldlfstatus
433 repo.lfstatus = oldlfstatus
434
434
435 files = set(ctx.files())
435 files = set(ctx.files())
436 if len(parents) == 2:
436 if len(parents) == 2:
437 mc = ctx.manifest()
437 mc = ctx.manifest()
438 mp1 = ctx.parents()[0].manifest()
438 mp1 = ctx.parents()[0].manifest()
439 mp2 = ctx.parents()[1].manifest()
439 mp2 = ctx.parents()[1].manifest()
440 for f in mp1:
440 for f in mp1:
441 if f not in mc:
441 if f not in mc:
442 files.add(f)
442 files.add(f)
443 for f in mp2:
443 for f in mp2:
444 if f not in mc:
444 if f not in mc:
445 files.add(f)
445 files.add(f)
446 for f in mc:
446 for f in mc:
447 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
447 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
448 files.add(f)
448 files.add(f)
449 for fn in files:
449 for fn in files:
450 if isstandin(fn) and fn in ctx:
450 if isstandin(fn) and fn in ctx:
451 addfunc(fn, ctx[fn].data().strip())
451 addfunc(fn, ctx[fn].data().strip())
452 repo.ui.progress(_('finding outgoing largefiles'), None)
452 repo.ui.progress(_('finding outgoing largefiles'), None)
453
453
454 def updatestandinsbymatch(repo, match):
454 def updatestandinsbymatch(repo, match):
455 '''Update standins in the working directory according to specified match
455 '''Update standins in the working directory according to specified match
456
456
457 This returns (possibly modified) ``match`` object to be used for
457 This returns (possibly modified) ``match`` object to be used for
458 subsequent commit process.
458 subsequent commit process.
459 '''
459 '''
460
460
461 ui = repo.ui
461 ui = repo.ui
462
462
463 # Case 1: user calls commit with no specific files or
463 # Case 1: user calls commit with no specific files or
464 # include/exclude patterns: refresh and commit all files that
464 # include/exclude patterns: refresh and commit all files that
465 # are "dirty".
465 # are "dirty".
466 if match is None or match.always():
466 if match is None or match.always():
467 # Spend a bit of time here to get a list of files we know
467 # Spend a bit of time here to get a list of files we know
468 # are modified so we can compare only against those.
468 # are modified so we can compare only against those.
469 # It can cost a lot of time (several seconds)
469 # It can cost a lot of time (several seconds)
470 # otherwise to update all standins if the largefiles are
470 # otherwise to update all standins if the largefiles are
471 # large.
471 # large.
472 lfdirstate = openlfdirstate(ui, repo)
472 lfdirstate = openlfdirstate(ui, repo)
473 dirtymatch = match_.always(repo.root, repo.getcwd())
473 dirtymatch = match_.always(repo.root, repo.getcwd())
474 unsure, s = lfdirstate.status(dirtymatch, [], False, False,
474 unsure, s = lfdirstate.status(dirtymatch, [], False, False,
475 False)
475 False)
476 modifiedfiles = unsure + s.modified + s.added + s.removed
476 modifiedfiles = unsure + s.modified + s.added + s.removed
477 lfiles = listlfiles(repo)
477 lfiles = listlfiles(repo)
478 # this only loops through largefiles that exist (not
478 # this only loops through largefiles that exist (not
479 # removed/renamed)
479 # removed/renamed)
480 for lfile in lfiles:
480 for lfile in lfiles:
481 if lfile in modifiedfiles:
481 if lfile in modifiedfiles:
482 if os.path.exists(
482 if os.path.exists(
483 repo.wjoin(standin(lfile))):
483 repo.wjoin(standin(lfile))):
484 # this handles the case where a rebase is being
484 # this handles the case where a rebase is being
485 # performed and the working copy is not updated
485 # performed and the working copy is not updated
486 # yet.
486 # yet.
487 if os.path.exists(repo.wjoin(lfile)):
487 if os.path.exists(repo.wjoin(lfile)):
488 updatestandin(repo,
488 updatestandin(repo,
489 standin(lfile))
489 standin(lfile))
490
490
491 return match
491 return match
492
492
493 lfiles = listlfiles(repo)
493 lfiles = listlfiles(repo)
494 match._files = repo._subdirlfs(match.files(), lfiles)
494 match._files = repo._subdirlfs(match.files(), lfiles)
495
495
496 # Case 2: user calls commit with specified patterns: refresh
496 # Case 2: user calls commit with specified patterns: refresh
497 # any matching big files.
497 # any matching big files.
498 smatcher = composestandinmatcher(repo, match)
498 smatcher = composestandinmatcher(repo, match)
499 standins = repo.dirstate.walk(smatcher, [], False, False)
499 standins = repo.dirstate.walk(smatcher, [], False, False)
500
500
501 # No matching big files: get out of the way and pass control to
501 # No matching big files: get out of the way and pass control to
502 # the usual commit() method.
502 # the usual commit() method.
503 if not standins:
503 if not standins:
504 return match
504 return match
505
505
506 # Refresh all matching big files. It's possible that the
506 # Refresh all matching big files. It's possible that the
507 # commit will end up failing, in which case the big files will
507 # commit will end up failing, in which case the big files will
508 # stay refreshed. No harm done: the user modified them and
508 # stay refreshed. No harm done: the user modified them and
509 # asked to commit them, so sooner or later we're going to
509 # asked to commit them, so sooner or later we're going to
510 # refresh the standins. Might as well leave them refreshed.
510 # refresh the standins. Might as well leave them refreshed.
511 lfdirstate = openlfdirstate(ui, repo)
511 lfdirstate = openlfdirstate(ui, repo)
512 for fstandin in standins:
512 for fstandin in standins:
513 lfile = splitstandin(fstandin)
513 lfile = splitstandin(fstandin)
514 if lfdirstate[lfile] != 'r':
514 if lfdirstate[lfile] != 'r':
515 updatestandin(repo, fstandin)
515 updatestandin(repo, fstandin)
516
516
517 # Cook up a new matcher that only matches regular files or
517 # Cook up a new matcher that only matches regular files or
518 # standins corresponding to the big files requested by the
518 # standins corresponding to the big files requested by the
519 # user. Have to modify _files to prevent commit() from
519 # user. Have to modify _files to prevent commit() from
520 # complaining "not tracked" for big files.
520 # complaining "not tracked" for big files.
521 match = copy.copy(match)
521 match = copy.copy(match)
522 origmatchfn = match.matchfn
522 origmatchfn = match.matchfn
523
523
524 # Check both the list of largefiles and the list of
524 # Check both the list of largefiles and the list of
525 # standins because if a largefile was removed, it
525 # standins because if a largefile was removed, it
526 # won't be in the list of largefiles at this point
526 # won't be in the list of largefiles at this point
527 match._files += sorted(standins)
527 match._files += sorted(standins)
528
528
529 actualfiles = []
529 actualfiles = []
530 for f in match._files:
530 for f in match._files:
531 fstandin = standin(f)
531 fstandin = standin(f)
532
532
533 # ignore known largefiles and standins
533 # ignore known largefiles and standins
534 if f in lfiles or fstandin in standins:
534 if f in lfiles or fstandin in standins:
535 continue
535 continue
536
536
537 actualfiles.append(f)
537 actualfiles.append(f)
538 match._files = actualfiles
538 match._files = actualfiles
539
539
540 def matchfn(f):
540 def matchfn(f):
541 if origmatchfn(f):
541 if origmatchfn(f):
542 return f not in lfiles
542 return f not in lfiles
543 else:
543 else:
544 return f in standins
544 return f in standins
545
545
546 match.matchfn = matchfn
546 match.matchfn = matchfn
547
547
548 return match
548 return match
549
549
550 class automatedcommithook(object):
550 class automatedcommithook(object):
551 '''Stateful hook to update standins at the 1st commit of resuming
551 '''Stateful hook to update standins at the 1st commit of resuming
552
552
553 For efficiency, updating standins in the working directory should
553 For efficiency, updating standins in the working directory should
554 be avoided while automated committing (like rebase, transplant and
554 be avoided while automated committing (like rebase, transplant and
555 so on), because they should be updated before committing.
555 so on), because they should be updated before committing.
556
556
557 But the 1st commit of resuming automated committing (e.g. ``rebase
557 But the 1st commit of resuming automated committing (e.g. ``rebase
558 --continue``) should update them, because largefiles may be
558 --continue``) should update them, because largefiles may be
559 modified manually.
559 modified manually.
560 '''
560 '''
561 def __init__(self, resuming):
561 def __init__(self, resuming):
562 self.resuming = resuming
562 self.resuming = resuming
563
563
564 def __call__(self, repo, match):
564 def __call__(self, repo, match):
565 if self.resuming:
565 if self.resuming:
566 self.resuming = False # avoids updating at subsequent commits
566 self.resuming = False # avoids updating at subsequent commits
567 return updatestandinsbymatch(repo, match)
567 return updatestandinsbymatch(repo, match)
568 else:
568 else:
569 return match
569 return match
570
570
571 def getstatuswriter(ui, repo, forcibly=None):
571 def getstatuswriter(ui, repo, forcibly=None):
572 '''Return the function to write largefiles specific status out
572 '''Return the function to write largefiles specific status out
573
573
574 If ``forcibly`` is ``None``, this returns the last element of
574 If ``forcibly`` is ``None``, this returns the last element of
575 ``repo._lfstatuswriters`` as "default" writer function.
575 ``repo._lfstatuswriters`` as "default" writer function.
576
576
577 Otherwise, this returns the function to always write out (or
577 Otherwise, this returns the function to always write out (or
578 ignore if ``not forcibly``) status.
578 ignore if ``not forcibly``) status.
579 '''
579 '''
580 if forcibly is None:
580 if forcibly is None and util.safehasattr(repo, '_largefilesenabled'):
581 return repo._lfstatuswriters[-1]
581 return repo._lfstatuswriters[-1]
582 else:
582 else:
583 if forcibly:
583 if forcibly:
584 return ui.status # forcibly WRITE OUT
584 return ui.status # forcibly WRITE OUT
585 else:
585 else:
586 return lambda *msg, **opts: None # forcibly IGNORE
586 return lambda *msg, **opts: None # forcibly IGNORE
@@ -1,1362 +1,1365 b''
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''Overridden Mercurial commands and functions for the largefiles extension'''
9 '''Overridden Mercurial commands and functions for the largefiles extension'''
10
10
11 import os
11 import os
12 import copy
12 import copy
13
13
14 from mercurial import hg, util, cmdutil, scmutil, match as match_, \
14 from mercurial import hg, util, cmdutil, scmutil, match as match_, \
15 archival, pathutil, revset
15 archival, pathutil, revset
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17 from mercurial.node import hex
17 from mercurial.node import hex
18
18
19 import lfutil
19 import lfutil
20 import lfcommands
20 import lfcommands
21 import basestore
21 import basestore
22
22
23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24
24
25 def composelargefilematcher(match, manifest):
25 def composelargefilematcher(match, manifest):
26 '''create a matcher that matches only the largefiles in the original
26 '''create a matcher that matches only the largefiles in the original
27 matcher'''
27 matcher'''
28 m = copy.copy(match)
28 m = copy.copy(match)
29 lfile = lambda f: lfutil.standin(f) in manifest
29 lfile = lambda f: lfutil.standin(f) in manifest
30 m._files = filter(lfile, m._files)
30 m._files = filter(lfile, m._files)
31 m._fmap = set(m._files)
31 m._fmap = set(m._files)
32 m._always = False
32 m._always = False
33 origmatchfn = m.matchfn
33 origmatchfn = m.matchfn
34 m.matchfn = lambda f: lfile(f) and origmatchfn(f)
34 m.matchfn = lambda f: lfile(f) and origmatchfn(f)
35 return m
35 return m
36
36
37 def composenormalfilematcher(match, manifest, exclude=None):
37 def composenormalfilematcher(match, manifest, exclude=None):
38 excluded = set()
38 excluded = set()
39 if exclude is not None:
39 if exclude is not None:
40 excluded.update(exclude)
40 excluded.update(exclude)
41
41
42 m = copy.copy(match)
42 m = copy.copy(match)
43 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
43 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
44 manifest or f in excluded)
44 manifest or f in excluded)
45 m._files = filter(notlfile, m._files)
45 m._files = filter(notlfile, m._files)
46 m._fmap = set(m._files)
46 m._fmap = set(m._files)
47 m._always = False
47 m._always = False
48 origmatchfn = m.matchfn
48 origmatchfn = m.matchfn
49 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
49 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
50 return m
50 return m
51
51
52 def installnormalfilesmatchfn(manifest):
52 def installnormalfilesmatchfn(manifest):
53 '''installmatchfn with a matchfn that ignores all largefiles'''
53 '''installmatchfn with a matchfn that ignores all largefiles'''
54 def overridematch(ctx, pats=[], opts={}, globbed=False,
54 def overridematch(ctx, pats=[], opts={}, globbed=False,
55 default='relpath'):
55 default='relpath'):
56 match = oldmatch(ctx, pats, opts, globbed, default)
56 match = oldmatch(ctx, pats, opts, globbed, default)
57 return composenormalfilematcher(match, manifest)
57 return composenormalfilematcher(match, manifest)
58 oldmatch = installmatchfn(overridematch)
58 oldmatch = installmatchfn(overridematch)
59
59
60 def installmatchfn(f):
60 def installmatchfn(f):
61 '''monkey patch the scmutil module with a custom match function.
61 '''monkey patch the scmutil module with a custom match function.
62 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
62 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
63 oldmatch = scmutil.match
63 oldmatch = scmutil.match
64 setattr(f, 'oldmatch', oldmatch)
64 setattr(f, 'oldmatch', oldmatch)
65 scmutil.match = f
65 scmutil.match = f
66 return oldmatch
66 return oldmatch
67
67
68 def restorematchfn():
68 def restorematchfn():
69 '''restores scmutil.match to what it was before installmatchfn
69 '''restores scmutil.match to what it was before installmatchfn
70 was called. no-op if scmutil.match is its original function.
70 was called. no-op if scmutil.match is its original function.
71
71
72 Note that n calls to installmatchfn will require n calls to
72 Note that n calls to installmatchfn will require n calls to
73 restore the original matchfn.'''
73 restore the original matchfn.'''
74 scmutil.match = getattr(scmutil.match, 'oldmatch')
74 scmutil.match = getattr(scmutil.match, 'oldmatch')
75
75
76 def installmatchandpatsfn(f):
76 def installmatchandpatsfn(f):
77 oldmatchandpats = scmutil.matchandpats
77 oldmatchandpats = scmutil.matchandpats
78 setattr(f, 'oldmatchandpats', oldmatchandpats)
78 setattr(f, 'oldmatchandpats', oldmatchandpats)
79 scmutil.matchandpats = f
79 scmutil.matchandpats = f
80 return oldmatchandpats
80 return oldmatchandpats
81
81
82 def restorematchandpatsfn():
82 def restorematchandpatsfn():
83 '''restores scmutil.matchandpats to what it was before
83 '''restores scmutil.matchandpats to what it was before
84 installmatchandpatsfn was called. No-op if scmutil.matchandpats
84 installmatchandpatsfn was called. No-op if scmutil.matchandpats
85 is its original function.
85 is its original function.
86
86
87 Note that n calls to installmatchandpatsfn will require n calls
87 Note that n calls to installmatchandpatsfn will require n calls
88 to restore the original matchfn.'''
88 to restore the original matchfn.'''
89 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
89 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
90 scmutil.matchandpats)
90 scmutil.matchandpats)
91
91
92 def addlargefiles(ui, repo, isaddremove, matcher, **opts):
92 def addlargefiles(ui, repo, isaddremove, matcher, **opts):
93 large = opts.get('large')
93 large = opts.get('large')
94 lfsize = lfutil.getminsize(
94 lfsize = lfutil.getminsize(
95 ui, lfutil.islfilesrepo(repo), opts.get('lfsize'))
95 ui, lfutil.islfilesrepo(repo), opts.get('lfsize'))
96
96
97 lfmatcher = None
97 lfmatcher = None
98 if lfutil.islfilesrepo(repo):
98 if lfutil.islfilesrepo(repo):
99 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
99 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
100 if lfpats:
100 if lfpats:
101 lfmatcher = match_.match(repo.root, '', list(lfpats))
101 lfmatcher = match_.match(repo.root, '', list(lfpats))
102
102
103 lfnames = []
103 lfnames = []
104 m = copy.copy(matcher)
104 m = copy.copy(matcher)
105 m.bad = lambda x, y: None
105 m.bad = lambda x, y: None
106 wctx = repo[None]
106 wctx = repo[None]
107 for f in repo.walk(m):
107 for f in repo.walk(m):
108 exact = m.exact(f)
108 exact = m.exact(f)
109 lfile = lfutil.standin(f) in wctx
109 lfile = lfutil.standin(f) in wctx
110 nfile = f in wctx
110 nfile = f in wctx
111 exists = lfile or nfile
111 exists = lfile or nfile
112
112
113 # addremove in core gets fancy with the name, add doesn't
113 # addremove in core gets fancy with the name, add doesn't
114 if isaddremove:
114 if isaddremove:
115 name = m.uipath(f)
115 name = m.uipath(f)
116 else:
116 else:
117 name = m.rel(f)
117 name = m.rel(f)
118
118
119 # Don't warn the user when they attempt to add a normal tracked file.
119 # Don't warn the user when they attempt to add a normal tracked file.
120 # The normal add code will do that for us.
120 # The normal add code will do that for us.
121 if exact and exists:
121 if exact and exists:
122 if lfile:
122 if lfile:
123 ui.warn(_('%s already a largefile\n') % name)
123 ui.warn(_('%s already a largefile\n') % name)
124 continue
124 continue
125
125
126 if (exact or not exists) and not lfutil.isstandin(f):
126 if (exact or not exists) and not lfutil.isstandin(f):
127 # In case the file was removed previously, but not committed
127 # In case the file was removed previously, but not committed
128 # (issue3507)
128 # (issue3507)
129 if not repo.wvfs.exists(f):
129 if not repo.wvfs.exists(f):
130 continue
130 continue
131
131
132 abovemin = (lfsize and
132 abovemin = (lfsize and
133 repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024)
133 repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024)
134 if large or abovemin or (lfmatcher and lfmatcher(f)):
134 if large or abovemin or (lfmatcher and lfmatcher(f)):
135 lfnames.append(f)
135 lfnames.append(f)
136 if ui.verbose or not exact:
136 if ui.verbose or not exact:
137 ui.status(_('adding %s as a largefile\n') % name)
137 ui.status(_('adding %s as a largefile\n') % name)
138
138
139 bad = []
139 bad = []
140
140
141 # Need to lock, otherwise there could be a race condition between
141 # Need to lock, otherwise there could be a race condition between
142 # when standins are created and added to the repo.
142 # when standins are created and added to the repo.
143 wlock = repo.wlock()
143 wlock = repo.wlock()
144 try:
144 try:
145 if not opts.get('dry_run'):
145 if not opts.get('dry_run'):
146 standins = []
146 standins = []
147 lfdirstate = lfutil.openlfdirstate(ui, repo)
147 lfdirstate = lfutil.openlfdirstate(ui, repo)
148 for f in lfnames:
148 for f in lfnames:
149 standinname = lfutil.standin(f)
149 standinname = lfutil.standin(f)
150 lfutil.writestandin(repo, standinname, hash='',
150 lfutil.writestandin(repo, standinname, hash='',
151 executable=lfutil.getexecutable(repo.wjoin(f)))
151 executable=lfutil.getexecutable(repo.wjoin(f)))
152 standins.append(standinname)
152 standins.append(standinname)
153 if lfdirstate[f] == 'r':
153 if lfdirstate[f] == 'r':
154 lfdirstate.normallookup(f)
154 lfdirstate.normallookup(f)
155 else:
155 else:
156 lfdirstate.add(f)
156 lfdirstate.add(f)
157 lfdirstate.write()
157 lfdirstate.write()
158 bad += [lfutil.splitstandin(f)
158 bad += [lfutil.splitstandin(f)
159 for f in repo[None].add(standins)
159 for f in repo[None].add(standins)
160 if f in m.files()]
160 if f in m.files()]
161
161
162 added = [f for f in lfnames if f not in bad]
162 added = [f for f in lfnames if f not in bad]
163 finally:
163 finally:
164 wlock.release()
164 wlock.release()
165 return added, bad
165 return added, bad
166
166
167 def removelargefiles(ui, repo, isaddremove, matcher, **opts):
167 def removelargefiles(ui, repo, isaddremove, matcher, **opts):
168 after = opts.get('after')
168 after = opts.get('after')
169 m = composelargefilematcher(matcher, repo[None].manifest())
169 m = composelargefilematcher(matcher, repo[None].manifest())
170 try:
170 try:
171 repo.lfstatus = True
171 repo.lfstatus = True
172 s = repo.status(match=m, clean=not isaddremove)
172 s = repo.status(match=m, clean=not isaddremove)
173 finally:
173 finally:
174 repo.lfstatus = False
174 repo.lfstatus = False
175 manifest = repo[None].manifest()
175 manifest = repo[None].manifest()
176 modified, added, deleted, clean = [[f for f in list
176 modified, added, deleted, clean = [[f for f in list
177 if lfutil.standin(f) in manifest]
177 if lfutil.standin(f) in manifest]
178 for list in (s.modified, s.added,
178 for list in (s.modified, s.added,
179 s.deleted, s.clean)]
179 s.deleted, s.clean)]
180
180
181 def warn(files, msg):
181 def warn(files, msg):
182 for f in files:
182 for f in files:
183 ui.warn(msg % m.rel(f))
183 ui.warn(msg % m.rel(f))
184 return int(len(files) > 0)
184 return int(len(files) > 0)
185
185
186 result = 0
186 result = 0
187
187
188 if after:
188 if after:
189 remove = deleted
189 remove = deleted
190 result = warn(modified + added + clean,
190 result = warn(modified + added + clean,
191 _('not removing %s: file still exists\n'))
191 _('not removing %s: file still exists\n'))
192 else:
192 else:
193 remove = deleted + clean
193 remove = deleted + clean
194 result = warn(modified, _('not removing %s: file is modified (use -f'
194 result = warn(modified, _('not removing %s: file is modified (use -f'
195 ' to force removal)\n'))
195 ' to force removal)\n'))
196 result = warn(added, _('not removing %s: file has been marked for add'
196 result = warn(added, _('not removing %s: file has been marked for add'
197 ' (use forget to undo)\n')) or result
197 ' (use forget to undo)\n')) or result
198
198
199 # Need to lock because standin files are deleted then removed from the
199 # Need to lock because standin files are deleted then removed from the
200 # repository and we could race in-between.
200 # repository and we could race in-between.
201 wlock = repo.wlock()
201 wlock = repo.wlock()
202 try:
202 try:
203 lfdirstate = lfutil.openlfdirstate(ui, repo)
203 lfdirstate = lfutil.openlfdirstate(ui, repo)
204 for f in sorted(remove):
204 for f in sorted(remove):
205 if ui.verbose or not m.exact(f):
205 if ui.verbose or not m.exact(f):
206 # addremove in core gets fancy with the name, remove doesn't
206 # addremove in core gets fancy with the name, remove doesn't
207 if isaddremove:
207 if isaddremove:
208 name = m.uipath(f)
208 name = m.uipath(f)
209 else:
209 else:
210 name = m.rel(f)
210 name = m.rel(f)
211 ui.status(_('removing %s\n') % name)
211 ui.status(_('removing %s\n') % name)
212
212
213 if not opts.get('dry_run'):
213 if not opts.get('dry_run'):
214 if not after:
214 if not after:
215 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
215 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
216
216
217 if opts.get('dry_run'):
217 if opts.get('dry_run'):
218 return result
218 return result
219
219
220 remove = [lfutil.standin(f) for f in remove]
220 remove = [lfutil.standin(f) for f in remove]
221 # If this is being called by addremove, let the original addremove
221 # If this is being called by addremove, let the original addremove
222 # function handle this.
222 # function handle this.
223 if not isaddremove:
223 if not isaddremove:
224 for f in remove:
224 for f in remove:
225 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
225 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
226 repo[None].forget(remove)
226 repo[None].forget(remove)
227
227
228 for f in remove:
228 for f in remove:
229 lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f),
229 lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f),
230 False)
230 False)
231
231
232 lfdirstate.write()
232 lfdirstate.write()
233 finally:
233 finally:
234 wlock.release()
234 wlock.release()
235
235
236 return result
236 return result
237
237
238 # For overriding mercurial.hgweb.webcommands so that largefiles will
238 # For overriding mercurial.hgweb.webcommands so that largefiles will
239 # appear at their right place in the manifests.
239 # appear at their right place in the manifests.
240 def decodepath(orig, path):
240 def decodepath(orig, path):
241 return lfutil.splitstandin(path) or path
241 return lfutil.splitstandin(path) or path
242
242
243 # -- Wrappers: modify existing commands --------------------------------
243 # -- Wrappers: modify existing commands --------------------------------
244
244
245 def overrideadd(orig, ui, repo, *pats, **opts):
245 def overrideadd(orig, ui, repo, *pats, **opts):
246 if opts.get('normal') and opts.get('large'):
246 if opts.get('normal') and opts.get('large'):
247 raise util.Abort(_('--normal cannot be used with --large'))
247 raise util.Abort(_('--normal cannot be used with --large'))
248 return orig(ui, repo, *pats, **opts)
248 return orig(ui, repo, *pats, **opts)
249
249
250 def cmdutiladd(orig, ui, repo, matcher, prefix, explicitonly, **opts):
250 def cmdutiladd(orig, ui, repo, matcher, prefix, explicitonly, **opts):
251 # The --normal flag short circuits this override
251 # The --normal flag short circuits this override
252 if opts.get('normal'):
252 if opts.get('normal'):
253 return orig(ui, repo, matcher, prefix, explicitonly, **opts)
253 return orig(ui, repo, matcher, prefix, explicitonly, **opts)
254
254
255 ladded, lbad = addlargefiles(ui, repo, False, matcher, **opts)
255 ladded, lbad = addlargefiles(ui, repo, False, matcher, **opts)
256 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest(),
256 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest(),
257 ladded)
257 ladded)
258 bad = orig(ui, repo, normalmatcher, prefix, explicitonly, **opts)
258 bad = orig(ui, repo, normalmatcher, prefix, explicitonly, **opts)
259
259
260 bad.extend(f for f in lbad)
260 bad.extend(f for f in lbad)
261 return bad
261 return bad
262
262
263 def cmdutilremove(orig, ui, repo, matcher, prefix, after, force, subrepos):
263 def cmdutilremove(orig, ui, repo, matcher, prefix, after, force, subrepos):
264 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest())
264 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest())
265 result = orig(ui, repo, normalmatcher, prefix, after, force, subrepos)
265 result = orig(ui, repo, normalmatcher, prefix, after, force, subrepos)
266 return removelargefiles(ui, repo, False, matcher, after=after,
266 return removelargefiles(ui, repo, False, matcher, after=after,
267 force=force) or result
267 force=force) or result
268
268
269 def overridestatusfn(orig, repo, rev2, **opts):
269 def overridestatusfn(orig, repo, rev2, **opts):
270 try:
270 try:
271 repo._repo.lfstatus = True
271 repo._repo.lfstatus = True
272 return orig(repo, rev2, **opts)
272 return orig(repo, rev2, **opts)
273 finally:
273 finally:
274 repo._repo.lfstatus = False
274 repo._repo.lfstatus = False
275
275
276 def overridestatus(orig, ui, repo, *pats, **opts):
276 def overridestatus(orig, ui, repo, *pats, **opts):
277 try:
277 try:
278 repo.lfstatus = True
278 repo.lfstatus = True
279 return orig(ui, repo, *pats, **opts)
279 return orig(ui, repo, *pats, **opts)
280 finally:
280 finally:
281 repo.lfstatus = False
281 repo.lfstatus = False
282
282
283 def overridedirty(orig, repo, ignoreupdate=False):
283 def overridedirty(orig, repo, ignoreupdate=False):
284 try:
284 try:
285 repo._repo.lfstatus = True
285 repo._repo.lfstatus = True
286 return orig(repo, ignoreupdate)
286 return orig(repo, ignoreupdate)
287 finally:
287 finally:
288 repo._repo.lfstatus = False
288 repo._repo.lfstatus = False
289
289
290 def overridelog(orig, ui, repo, *pats, **opts):
290 def overridelog(orig, ui, repo, *pats, **opts):
291 def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
291 def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
292 default='relpath'):
292 default='relpath'):
293 """Matcher that merges root directory with .hglf, suitable for log.
293 """Matcher that merges root directory with .hglf, suitable for log.
294 It is still possible to match .hglf directly.
294 It is still possible to match .hglf directly.
295 For any listed files run log on the standin too.
295 For any listed files run log on the standin too.
296 matchfn tries both the given filename and with .hglf stripped.
296 matchfn tries both the given filename and with .hglf stripped.
297 """
297 """
298 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
298 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
299 m, p = copy.copy(matchandpats)
299 m, p = copy.copy(matchandpats)
300
300
301 if m.always():
301 if m.always():
302 # We want to match everything anyway, so there's no benefit trying
302 # We want to match everything anyway, so there's no benefit trying
303 # to add standins.
303 # to add standins.
304 return matchandpats
304 return matchandpats
305
305
306 pats = set(p)
306 pats = set(p)
307 # TODO: handling of patterns in both cases below
307 # TODO: handling of patterns in both cases below
308 if m._cwd:
308 if m._cwd:
309 if os.path.isabs(m._cwd):
309 if os.path.isabs(m._cwd):
310 # TODO: handle largefile magic when invoked from other cwd
310 # TODO: handle largefile magic when invoked from other cwd
311 return matchandpats
311 return matchandpats
312 back = (m._cwd.count('/') + 1) * '../'
312 back = (m._cwd.count('/') + 1) * '../'
313 pats.update(back + lfutil.standin(m._cwd + '/' + f) for f in p)
313 pats.update(back + lfutil.standin(m._cwd + '/' + f) for f in p)
314 else:
314 else:
315 pats.update(lfutil.standin(f) for f in p)
315 pats.update(lfutil.standin(f) for f in p)
316
316
317 for i in range(0, len(m._files)):
317 for i in range(0, len(m._files)):
318 standin = lfutil.standin(m._files[i])
318 standin = lfutil.standin(m._files[i])
319 # If the "standin" is a directory, append instead of replace to
319 # If the "standin" is a directory, append instead of replace to
320 # support naming a directory on the command line with only
320 # support naming a directory on the command line with only
321 # largefiles. The original directory is kept to support normal
321 # largefiles. The original directory is kept to support normal
322 # files.
322 # files.
323 if standin in repo[ctx.node()]:
323 if standin in repo[ctx.node()]:
324 m._files[i] = standin
324 m._files[i] = standin
325 elif m._files[i] not in repo[ctx.node()] \
325 elif m._files[i] not in repo[ctx.node()] \
326 and repo.wvfs.isdir(standin):
326 and repo.wvfs.isdir(standin):
327 m._files.append(standin)
327 m._files.append(standin)
328 pats.add(standin)
328 pats.add(standin)
329
329
330 m._fmap = set(m._files)
330 m._fmap = set(m._files)
331 m._always = False
331 m._always = False
332 origmatchfn = m.matchfn
332 origmatchfn = m.matchfn
333 def lfmatchfn(f):
333 def lfmatchfn(f):
334 lf = lfutil.splitstandin(f)
334 lf = lfutil.splitstandin(f)
335 if lf is not None and origmatchfn(lf):
335 if lf is not None and origmatchfn(lf):
336 return True
336 return True
337 r = origmatchfn(f)
337 r = origmatchfn(f)
338 return r
338 return r
339 m.matchfn = lfmatchfn
339 m.matchfn = lfmatchfn
340
340
341 return m, pats
341 return m, pats
342
342
343 # For hg log --patch, the match object is used in two different senses:
343 # For hg log --patch, the match object is used in two different senses:
344 # (1) to determine what revisions should be printed out, and
344 # (1) to determine what revisions should be printed out, and
345 # (2) to determine what files to print out diffs for.
345 # (2) to determine what files to print out diffs for.
346 # The magic matchandpats override should be used for case (1) but not for
346 # The magic matchandpats override should be used for case (1) but not for
347 # case (2).
347 # case (2).
348 def overridemakelogfilematcher(repo, pats, opts):
348 def overridemakelogfilematcher(repo, pats, opts):
349 pctx = repo[None]
349 pctx = repo[None]
350 match, pats = oldmatchandpats(pctx, pats, opts)
350 match, pats = oldmatchandpats(pctx, pats, opts)
351 return lambda rev: match
351 return lambda rev: match
352
352
353 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
353 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
354 oldmakelogfilematcher = cmdutil._makenofollowlogfilematcher
354 oldmakelogfilematcher = cmdutil._makenofollowlogfilematcher
355 setattr(cmdutil, '_makenofollowlogfilematcher', overridemakelogfilematcher)
355 setattr(cmdutil, '_makenofollowlogfilematcher', overridemakelogfilematcher)
356
356
357 try:
357 try:
358 return orig(ui, repo, *pats, **opts)
358 return orig(ui, repo, *pats, **opts)
359 finally:
359 finally:
360 restorematchandpatsfn()
360 restorematchandpatsfn()
361 setattr(cmdutil, '_makenofollowlogfilematcher', oldmakelogfilematcher)
361 setattr(cmdutil, '_makenofollowlogfilematcher', oldmakelogfilematcher)
362
362
363 def overrideverify(orig, ui, repo, *pats, **opts):
363 def overrideverify(orig, ui, repo, *pats, **opts):
364 large = opts.pop('large', False)
364 large = opts.pop('large', False)
365 all = opts.pop('lfa', False)
365 all = opts.pop('lfa', False)
366 contents = opts.pop('lfc', False)
366 contents = opts.pop('lfc', False)
367
367
368 result = orig(ui, repo, *pats, **opts)
368 result = orig(ui, repo, *pats, **opts)
369 if large or all or contents:
369 if large or all or contents:
370 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
370 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
371 return result
371 return result
372
372
373 def overridedebugstate(orig, ui, repo, *pats, **opts):
373 def overridedebugstate(orig, ui, repo, *pats, **opts):
374 large = opts.pop('large', False)
374 large = opts.pop('large', False)
375 if large:
375 if large:
376 class fakerepo(object):
376 class fakerepo(object):
377 dirstate = lfutil.openlfdirstate(ui, repo)
377 dirstate = lfutil.openlfdirstate(ui, repo)
378 orig(ui, fakerepo, *pats, **opts)
378 orig(ui, fakerepo, *pats, **opts)
379 else:
379 else:
380 orig(ui, repo, *pats, **opts)
380 orig(ui, repo, *pats, **opts)
381
381
382 # Override needs to refresh standins so that update's normal merge
382 # Override needs to refresh standins so that update's normal merge
383 # will go through properly. Then the other update hook (overriding repo.update)
383 # will go through properly. Then the other update hook (overriding repo.update)
384 # will get the new files. Filemerge is also overridden so that the merge
384 # will get the new files. Filemerge is also overridden so that the merge
385 # will merge standins correctly.
385 # will merge standins correctly.
386 def overrideupdate(orig, ui, repo, *pats, **opts):
386 def overrideupdate(orig, ui, repo, *pats, **opts):
387 # Need to lock between the standins getting updated and their
387 # Need to lock between the standins getting updated and their
388 # largefiles getting updated
388 # largefiles getting updated
389 wlock = repo.wlock()
389 wlock = repo.wlock()
390 try:
390 try:
391 if opts['check']:
391 if opts['check']:
392 lfdirstate = lfutil.openlfdirstate(ui, repo)
392 lfdirstate = lfutil.openlfdirstate(ui, repo)
393 unsure, s = lfdirstate.status(
393 unsure, s = lfdirstate.status(
394 match_.always(repo.root, repo.getcwd()),
394 match_.always(repo.root, repo.getcwd()),
395 [], False, False, False)
395 [], False, False, False)
396
396
397 mod = len(s.modified) > 0
397 mod = len(s.modified) > 0
398 for lfile in unsure:
398 for lfile in unsure:
399 standin = lfutil.standin(lfile)
399 standin = lfutil.standin(lfile)
400 if repo['.'][standin].data().strip() != \
400 if repo['.'][standin].data().strip() != \
401 lfutil.hashfile(repo.wjoin(lfile)):
401 lfutil.hashfile(repo.wjoin(lfile)):
402 mod = True
402 mod = True
403 else:
403 else:
404 lfdirstate.normal(lfile)
404 lfdirstate.normal(lfile)
405 lfdirstate.write()
405 lfdirstate.write()
406 if mod:
406 if mod:
407 raise util.Abort(_('uncommitted changes'))
407 raise util.Abort(_('uncommitted changes'))
408 return orig(ui, repo, *pats, **opts)
408 return orig(ui, repo, *pats, **opts)
409 finally:
409 finally:
410 wlock.release()
410 wlock.release()
411
411
412 # Before starting the manifest merge, merge.updates will call
412 # Before starting the manifest merge, merge.updates will call
413 # _checkunknownfile to check if there are any files in the merged-in
413 # _checkunknownfile to check if there are any files in the merged-in
414 # changeset that collide with unknown files in the working copy.
414 # changeset that collide with unknown files in the working copy.
415 #
415 #
416 # The largefiles are seen as unknown, so this prevents us from merging
416 # The largefiles are seen as unknown, so this prevents us from merging
417 # in a file 'foo' if we already have a largefile with the same name.
417 # in a file 'foo' if we already have a largefile with the same name.
418 #
418 #
419 # The overridden function filters the unknown files by removing any
419 # The overridden function filters the unknown files by removing any
420 # largefiles. This makes the merge proceed and we can then handle this
420 # largefiles. This makes the merge proceed and we can then handle this
421 # case further in the overridden calculateupdates function below.
421 # case further in the overridden calculateupdates function below.
422 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None):
422 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None):
423 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
423 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
424 return False
424 return False
425 return origfn(repo, wctx, mctx, f, f2)
425 return origfn(repo, wctx, mctx, f, f2)
426
426
427 # The manifest merge handles conflicts on the manifest level. We want
427 # The manifest merge handles conflicts on the manifest level. We want
428 # to handle changes in largefile-ness of files at this level too.
428 # to handle changes in largefile-ness of files at this level too.
429 #
429 #
430 # The strategy is to run the original calculateupdates and then process
430 # The strategy is to run the original calculateupdates and then process
431 # the action list it outputs. There are two cases we need to deal with:
431 # the action list it outputs. There are two cases we need to deal with:
432 #
432 #
433 # 1. Normal file in p1, largefile in p2. Here the largefile is
433 # 1. Normal file in p1, largefile in p2. Here the largefile is
434 # detected via its standin file, which will enter the working copy
434 # detected via its standin file, which will enter the working copy
435 # with a "get" action. It is not "merge" since the standin is all
435 # with a "get" action. It is not "merge" since the standin is all
436 # Mercurial is concerned with at this level -- the link to the
436 # Mercurial is concerned with at this level -- the link to the
437 # existing normal file is not relevant here.
437 # existing normal file is not relevant here.
438 #
438 #
439 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
439 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
440 # since the largefile will be present in the working copy and
440 # since the largefile will be present in the working copy and
441 # different from the normal file in p2. Mercurial therefore
441 # different from the normal file in p2. Mercurial therefore
442 # triggers a merge action.
442 # triggers a merge action.
443 #
443 #
444 # In both cases, we prompt the user and emit new actions to either
444 # In both cases, we prompt the user and emit new actions to either
445 # remove the standin (if the normal file was kept) or to remove the
445 # remove the standin (if the normal file was kept) or to remove the
446 # normal file and get the standin (if the largefile was kept). The
446 # normal file and get the standin (if the largefile was kept). The
447 # default prompt answer is to use the largefile version since it was
447 # default prompt answer is to use the largefile version since it was
448 # presumably changed on purpose.
448 # presumably changed on purpose.
449 #
449 #
450 # Finally, the merge.applyupdates function will then take care of
450 # Finally, the merge.applyupdates function will then take care of
451 # writing the files into the working copy and lfcommands.updatelfiles
451 # writing the files into the working copy and lfcommands.updatelfiles
452 # will update the largefiles.
452 # will update the largefiles.
453 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
453 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
454 partial, acceptremote, followcopies):
454 partial, acceptremote, followcopies):
455 overwrite = force and not branchmerge
455 overwrite = force and not branchmerge
456 actions, diverge, renamedelete = origfn(
456 actions, diverge, renamedelete = origfn(
457 repo, p1, p2, pas, branchmerge, force, partial, acceptremote,
457 repo, p1, p2, pas, branchmerge, force, partial, acceptremote,
458 followcopies)
458 followcopies)
459
459
460 if overwrite:
460 if overwrite:
461 return actions, diverge, renamedelete
461 return actions, diverge, renamedelete
462
462
463 # Convert to dictionary with filename as key and action as value.
463 # Convert to dictionary with filename as key and action as value.
464 lfiles = set()
464 lfiles = set()
465 for f in actions:
465 for f in actions:
466 splitstandin = f and lfutil.splitstandin(f)
466 splitstandin = f and lfutil.splitstandin(f)
467 if splitstandin in p1:
467 if splitstandin in p1:
468 lfiles.add(splitstandin)
468 lfiles.add(splitstandin)
469 elif lfutil.standin(f) in p1:
469 elif lfutil.standin(f) in p1:
470 lfiles.add(f)
470 lfiles.add(f)
471
471
472 for lfile in lfiles:
472 for lfile in lfiles:
473 standin = lfutil.standin(lfile)
473 standin = lfutil.standin(lfile)
474 (lm, largs, lmsg) = actions.get(lfile, (None, None, None))
474 (lm, largs, lmsg) = actions.get(lfile, (None, None, None))
475 (sm, sargs, smsg) = actions.get(standin, (None, None, None))
475 (sm, sargs, smsg) = actions.get(standin, (None, None, None))
476 if sm in ('g', 'dc') and lm != 'r':
476 if sm in ('g', 'dc') and lm != 'r':
477 # Case 1: normal file in the working copy, largefile in
477 # Case 1: normal file in the working copy, largefile in
478 # the second parent
478 # the second parent
479 usermsg = _('remote turned local normal file %s into a largefile\n'
479 usermsg = _('remote turned local normal file %s into a largefile\n'
480 'use (l)argefile or keep (n)ormal file?'
480 'use (l)argefile or keep (n)ormal file?'
481 '$$ &Largefile $$ &Normal file') % lfile
481 '$$ &Largefile $$ &Normal file') % lfile
482 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
482 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
483 actions[lfile] = ('r', None, 'replaced by standin')
483 actions[lfile] = ('r', None, 'replaced by standin')
484 actions[standin] = ('g', sargs, 'replaces standin')
484 actions[standin] = ('g', sargs, 'replaces standin')
485 else: # keep local normal file
485 else: # keep local normal file
486 actions[lfile] = ('k', None, 'replaces standin')
486 actions[lfile] = ('k', None, 'replaces standin')
487 if branchmerge:
487 if branchmerge:
488 actions[standin] = ('k', None, 'replaced by non-standin')
488 actions[standin] = ('k', None, 'replaced by non-standin')
489 else:
489 else:
490 actions[standin] = ('r', None, 'replaced by non-standin')
490 actions[standin] = ('r', None, 'replaced by non-standin')
491 elif lm in ('g', 'dc') and sm != 'r':
491 elif lm in ('g', 'dc') and sm != 'r':
492 # Case 2: largefile in the working copy, normal file in
492 # Case 2: largefile in the working copy, normal file in
493 # the second parent
493 # the second parent
494 usermsg = _('remote turned local largefile %s into a normal file\n'
494 usermsg = _('remote turned local largefile %s into a normal file\n'
495 'keep (l)argefile or use (n)ormal file?'
495 'keep (l)argefile or use (n)ormal file?'
496 '$$ &Largefile $$ &Normal file') % lfile
496 '$$ &Largefile $$ &Normal file') % lfile
497 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
497 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
498 if branchmerge:
498 if branchmerge:
499 # largefile can be restored from standin safely
499 # largefile can be restored from standin safely
500 actions[lfile] = ('k', None, 'replaced by standin')
500 actions[lfile] = ('k', None, 'replaced by standin')
501 actions[standin] = ('k', None, 'replaces standin')
501 actions[standin] = ('k', None, 'replaces standin')
502 else:
502 else:
503 # "lfile" should be marked as "removed" without
503 # "lfile" should be marked as "removed" without
504 # removal of itself
504 # removal of itself
505 actions[lfile] = ('lfmr', None,
505 actions[lfile] = ('lfmr', None,
506 'forget non-standin largefile')
506 'forget non-standin largefile')
507
507
508 # linear-merge should treat this largefile as 're-added'
508 # linear-merge should treat this largefile as 're-added'
509 actions[standin] = ('a', None, 'keep standin')
509 actions[standin] = ('a', None, 'keep standin')
510 else: # pick remote normal file
510 else: # pick remote normal file
511 actions[lfile] = ('g', largs, 'replaces standin')
511 actions[lfile] = ('g', largs, 'replaces standin')
512 actions[standin] = ('r', None, 'replaced by non-standin')
512 actions[standin] = ('r', None, 'replaced by non-standin')
513
513
514 return actions, diverge, renamedelete
514 return actions, diverge, renamedelete
515
515
516 def mergerecordupdates(orig, repo, actions, branchmerge):
516 def mergerecordupdates(orig, repo, actions, branchmerge):
517 if 'lfmr' in actions:
517 if 'lfmr' in actions:
518 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
518 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
519 for lfile, args, msg in actions['lfmr']:
519 for lfile, args, msg in actions['lfmr']:
520 # this should be executed before 'orig', to execute 'remove'
520 # this should be executed before 'orig', to execute 'remove'
521 # before all other actions
521 # before all other actions
522 repo.dirstate.remove(lfile)
522 repo.dirstate.remove(lfile)
523 # make sure lfile doesn't get synclfdirstate'd as normal
523 # make sure lfile doesn't get synclfdirstate'd as normal
524 lfdirstate.add(lfile)
524 lfdirstate.add(lfile)
525 lfdirstate.write()
525 lfdirstate.write()
526
526
527 return orig(repo, actions, branchmerge)
527 return orig(repo, actions, branchmerge)
528
528
529
529
530 # Override filemerge to prompt the user about how they wish to merge
530 # Override filemerge to prompt the user about how they wish to merge
531 # largefiles. This will handle identical edits without prompting the user.
531 # largefiles. This will handle identical edits without prompting the user.
532 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca, labels=None):
532 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca, labels=None):
533 if not lfutil.isstandin(orig):
533 if not lfutil.isstandin(orig):
534 return origfn(repo, mynode, orig, fcd, fco, fca, labels=labels)
534 return origfn(repo, mynode, orig, fcd, fco, fca, labels=labels)
535
535
536 ahash = fca.data().strip().lower()
536 ahash = fca.data().strip().lower()
537 dhash = fcd.data().strip().lower()
537 dhash = fcd.data().strip().lower()
538 ohash = fco.data().strip().lower()
538 ohash = fco.data().strip().lower()
539 if (ohash != ahash and
539 if (ohash != ahash and
540 ohash != dhash and
540 ohash != dhash and
541 (dhash == ahash or
541 (dhash == ahash or
542 repo.ui.promptchoice(
542 repo.ui.promptchoice(
543 _('largefile %s has a merge conflict\nancestor was %s\n'
543 _('largefile %s has a merge conflict\nancestor was %s\n'
544 'keep (l)ocal %s or\ntake (o)ther %s?'
544 'keep (l)ocal %s or\ntake (o)ther %s?'
545 '$$ &Local $$ &Other') %
545 '$$ &Local $$ &Other') %
546 (lfutil.splitstandin(orig), ahash, dhash, ohash),
546 (lfutil.splitstandin(orig), ahash, dhash, ohash),
547 0) == 1)):
547 0) == 1)):
548 repo.wwrite(fcd.path(), fco.data(), fco.flags())
548 repo.wwrite(fcd.path(), fco.data(), fco.flags())
549 return 0
549 return 0
550
550
551 # Copy first changes the matchers to match standins instead of
551 # Copy first changes the matchers to match standins instead of
552 # largefiles. Then it overrides util.copyfile in that function it
552 # largefiles. Then it overrides util.copyfile in that function it
553 # checks if the destination largefile already exists. It also keeps a
553 # checks if the destination largefile already exists. It also keeps a
554 # list of copied files so that the largefiles can be copied and the
554 # list of copied files so that the largefiles can be copied and the
555 # dirstate updated.
555 # dirstate updated.
556 def overridecopy(orig, ui, repo, pats, opts, rename=False):
556 def overridecopy(orig, ui, repo, pats, opts, rename=False):
557 # doesn't remove largefile on rename
557 # doesn't remove largefile on rename
558 if len(pats) < 2:
558 if len(pats) < 2:
559 # this isn't legal, let the original function deal with it
559 # this isn't legal, let the original function deal with it
560 return orig(ui, repo, pats, opts, rename)
560 return orig(ui, repo, pats, opts, rename)
561
561
562 # This could copy both lfiles and normal files in one command,
562 # This could copy both lfiles and normal files in one command,
563 # but we don't want to do that. First replace their matcher to
563 # but we don't want to do that. First replace their matcher to
564 # only match normal files and run it, then replace it to just
564 # only match normal files and run it, then replace it to just
565 # match largefiles and run it again.
565 # match largefiles and run it again.
566 nonormalfiles = False
566 nonormalfiles = False
567 nolfiles = False
567 nolfiles = False
568 installnormalfilesmatchfn(repo[None].manifest())
568 installnormalfilesmatchfn(repo[None].manifest())
569 try:
569 try:
570 try:
570 try:
571 result = orig(ui, repo, pats, opts, rename)
571 result = orig(ui, repo, pats, opts, rename)
572 except util.Abort, e:
572 except util.Abort, e:
573 if str(e) != _('no files to copy'):
573 if str(e) != _('no files to copy'):
574 raise e
574 raise e
575 else:
575 else:
576 nonormalfiles = True
576 nonormalfiles = True
577 result = 0
577 result = 0
578 finally:
578 finally:
579 restorematchfn()
579 restorematchfn()
580
580
581 # The first rename can cause our current working directory to be removed.
581 # The first rename can cause our current working directory to be removed.
582 # In that case there is nothing left to copy/rename so just quit.
582 # In that case there is nothing left to copy/rename so just quit.
583 try:
583 try:
584 repo.getcwd()
584 repo.getcwd()
585 except OSError:
585 except OSError:
586 return result
586 return result
587
587
588 def makestandin(relpath):
588 def makestandin(relpath):
589 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
589 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
590 return os.path.join(repo.wjoin(lfutil.standin(path)))
590 return os.path.join(repo.wjoin(lfutil.standin(path)))
591
591
592 fullpats = scmutil.expandpats(pats)
592 fullpats = scmutil.expandpats(pats)
593 dest = fullpats[-1]
593 dest = fullpats[-1]
594
594
595 if os.path.isdir(dest):
595 if os.path.isdir(dest):
596 if not os.path.isdir(makestandin(dest)):
596 if not os.path.isdir(makestandin(dest)):
597 os.makedirs(makestandin(dest))
597 os.makedirs(makestandin(dest))
598
598
599 try:
599 try:
600 try:
600 try:
601 # When we call orig below it creates the standins but we don't add
601 # When we call orig below it creates the standins but we don't add
602 # them to the dir state until later so lock during that time.
602 # them to the dir state until later so lock during that time.
603 wlock = repo.wlock()
603 wlock = repo.wlock()
604
604
605 manifest = repo[None].manifest()
605 manifest = repo[None].manifest()
606 def overridematch(ctx, pats=[], opts={}, globbed=False,
606 def overridematch(ctx, pats=[], opts={}, globbed=False,
607 default='relpath'):
607 default='relpath'):
608 newpats = []
608 newpats = []
609 # The patterns were previously mangled to add the standin
609 # The patterns were previously mangled to add the standin
610 # directory; we need to remove that now
610 # directory; we need to remove that now
611 for pat in pats:
611 for pat in pats:
612 if match_.patkind(pat) is None and lfutil.shortname in pat:
612 if match_.patkind(pat) is None and lfutil.shortname in pat:
613 newpats.append(pat.replace(lfutil.shortname, ''))
613 newpats.append(pat.replace(lfutil.shortname, ''))
614 else:
614 else:
615 newpats.append(pat)
615 newpats.append(pat)
616 match = oldmatch(ctx, newpats, opts, globbed, default)
616 match = oldmatch(ctx, newpats, opts, globbed, default)
617 m = copy.copy(match)
617 m = copy.copy(match)
618 lfile = lambda f: lfutil.standin(f) in manifest
618 lfile = lambda f: lfutil.standin(f) in manifest
619 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
619 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
620 m._fmap = set(m._files)
620 m._fmap = set(m._files)
621 origmatchfn = m.matchfn
621 origmatchfn = m.matchfn
622 m.matchfn = lambda f: (lfutil.isstandin(f) and
622 m.matchfn = lambda f: (lfutil.isstandin(f) and
623 (f in manifest) and
623 (f in manifest) and
624 origmatchfn(lfutil.splitstandin(f)) or
624 origmatchfn(lfutil.splitstandin(f)) or
625 None)
625 None)
626 return m
626 return m
627 oldmatch = installmatchfn(overridematch)
627 oldmatch = installmatchfn(overridematch)
628 listpats = []
628 listpats = []
629 for pat in pats:
629 for pat in pats:
630 if match_.patkind(pat) is not None:
630 if match_.patkind(pat) is not None:
631 listpats.append(pat)
631 listpats.append(pat)
632 else:
632 else:
633 listpats.append(makestandin(pat))
633 listpats.append(makestandin(pat))
634
634
635 try:
635 try:
636 origcopyfile = util.copyfile
636 origcopyfile = util.copyfile
637 copiedfiles = []
637 copiedfiles = []
638 def overridecopyfile(src, dest):
638 def overridecopyfile(src, dest):
639 if (lfutil.shortname in src and
639 if (lfutil.shortname in src and
640 dest.startswith(repo.wjoin(lfutil.shortname))):
640 dest.startswith(repo.wjoin(lfutil.shortname))):
641 destlfile = dest.replace(lfutil.shortname, '')
641 destlfile = dest.replace(lfutil.shortname, '')
642 if not opts['force'] and os.path.exists(destlfile):
642 if not opts['force'] and os.path.exists(destlfile):
643 raise IOError('',
643 raise IOError('',
644 _('destination largefile already exists'))
644 _('destination largefile already exists'))
645 copiedfiles.append((src, dest))
645 copiedfiles.append((src, dest))
646 origcopyfile(src, dest)
646 origcopyfile(src, dest)
647
647
648 util.copyfile = overridecopyfile
648 util.copyfile = overridecopyfile
649 result += orig(ui, repo, listpats, opts, rename)
649 result += orig(ui, repo, listpats, opts, rename)
650 finally:
650 finally:
651 util.copyfile = origcopyfile
651 util.copyfile = origcopyfile
652
652
653 lfdirstate = lfutil.openlfdirstate(ui, repo)
653 lfdirstate = lfutil.openlfdirstate(ui, repo)
654 for (src, dest) in copiedfiles:
654 for (src, dest) in copiedfiles:
655 if (lfutil.shortname in src and
655 if (lfutil.shortname in src and
656 dest.startswith(repo.wjoin(lfutil.shortname))):
656 dest.startswith(repo.wjoin(lfutil.shortname))):
657 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
657 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
658 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
658 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
659 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
659 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
660 if not os.path.isdir(destlfiledir):
660 if not os.path.isdir(destlfiledir):
661 os.makedirs(destlfiledir)
661 os.makedirs(destlfiledir)
662 if rename:
662 if rename:
663 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
663 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
664
664
665 # The file is gone, but this deletes any empty parent
665 # The file is gone, but this deletes any empty parent
666 # directories as a side-effect.
666 # directories as a side-effect.
667 util.unlinkpath(repo.wjoin(srclfile), True)
667 util.unlinkpath(repo.wjoin(srclfile), True)
668 lfdirstate.remove(srclfile)
668 lfdirstate.remove(srclfile)
669 else:
669 else:
670 util.copyfile(repo.wjoin(srclfile),
670 util.copyfile(repo.wjoin(srclfile),
671 repo.wjoin(destlfile))
671 repo.wjoin(destlfile))
672
672
673 lfdirstate.add(destlfile)
673 lfdirstate.add(destlfile)
674 lfdirstate.write()
674 lfdirstate.write()
675 except util.Abort, e:
675 except util.Abort, e:
676 if str(e) != _('no files to copy'):
676 if str(e) != _('no files to copy'):
677 raise e
677 raise e
678 else:
678 else:
679 nolfiles = True
679 nolfiles = True
680 finally:
680 finally:
681 restorematchfn()
681 restorematchfn()
682 wlock.release()
682 wlock.release()
683
683
684 if nolfiles and nonormalfiles:
684 if nolfiles and nonormalfiles:
685 raise util.Abort(_('no files to copy'))
685 raise util.Abort(_('no files to copy'))
686
686
687 return result
687 return result
688
688
689 # When the user calls revert, we have to be careful to not revert any
689 # When the user calls revert, we have to be careful to not revert any
690 # changes to other largefiles accidentally. This means we have to keep
690 # changes to other largefiles accidentally. This means we have to keep
691 # track of the largefiles that are being reverted so we only pull down
691 # track of the largefiles that are being reverted so we only pull down
692 # the necessary largefiles.
692 # the necessary largefiles.
693 #
693 #
694 # Standins are only updated (to match the hash of largefiles) before
694 # Standins are only updated (to match the hash of largefiles) before
695 # commits. Update the standins then run the original revert, changing
695 # commits. Update the standins then run the original revert, changing
696 # the matcher to hit standins instead of largefiles. Based on the
696 # the matcher to hit standins instead of largefiles. Based on the
697 # resulting standins update the largefiles.
697 # resulting standins update the largefiles.
698 def overriderevert(orig, ui, repo, *pats, **opts):
698 def overriderevert(orig, ui, repo, *pats, **opts):
699 # Because we put the standins in a bad state (by updating them)
699 # Because we put the standins in a bad state (by updating them)
700 # and then return them to a correct state we need to lock to
700 # and then return them to a correct state we need to lock to
701 # prevent others from changing them in their incorrect state.
701 # prevent others from changing them in their incorrect state.
702 wlock = repo.wlock()
702 wlock = repo.wlock()
703 try:
703 try:
704 lfdirstate = lfutil.openlfdirstate(ui, repo)
704 lfdirstate = lfutil.openlfdirstate(ui, repo)
705 s = lfutil.lfdirstatestatus(lfdirstate, repo)
705 s = lfutil.lfdirstatestatus(lfdirstate, repo)
706 lfdirstate.write()
706 lfdirstate.write()
707 for lfile in s.modified:
707 for lfile in s.modified:
708 lfutil.updatestandin(repo, lfutil.standin(lfile))
708 lfutil.updatestandin(repo, lfutil.standin(lfile))
709 for lfile in s.deleted:
709 for lfile in s.deleted:
710 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
710 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
711 os.unlink(repo.wjoin(lfutil.standin(lfile)))
711 os.unlink(repo.wjoin(lfutil.standin(lfile)))
712
712
713 oldstandins = lfutil.getstandinsstate(repo)
713 oldstandins = lfutil.getstandinsstate(repo)
714
714
715 def overridematch(ctx, pats=[], opts={}, globbed=False,
715 def overridematch(ctx, pats=[], opts={}, globbed=False,
716 default='relpath'):
716 default='relpath'):
717 match = oldmatch(ctx, pats, opts, globbed, default)
717 match = oldmatch(ctx, pats, opts, globbed, default)
718 m = copy.copy(match)
718 m = copy.copy(match)
719
719
720 # revert supports recursing into subrepos, and though largefiles
720 # revert supports recursing into subrepos, and though largefiles
721 # currently doesn't work correctly in that case, this match is
721 # currently doesn't work correctly in that case, this match is
722 # called, so the lfdirstate above may not be the correct one for
722 # called, so the lfdirstate above may not be the correct one for
723 # this invocation of match.
723 # this invocation of match.
724 lfdirstate = lfutil.openlfdirstate(ctx._repo.ui, ctx._repo)
724 lfdirstate = lfutil.openlfdirstate(ctx._repo.ui, ctx._repo)
725
725
726 def tostandin(f):
726 def tostandin(f):
727 if lfutil.standin(f) in ctx:
727 if lfutil.standin(f) in ctx:
728 return lfutil.standin(f)
728 return lfutil.standin(f)
729 elif lfutil.standin(f) in repo[None] or lfdirstate[f] == 'r':
729 elif lfutil.standin(f) in repo[None] or lfdirstate[f] == 'r':
730 return None
730 return None
731 return f
731 return f
732 m._files = [tostandin(f) for f in m._files]
732 m._files = [tostandin(f) for f in m._files]
733 m._files = [f for f in m._files if f is not None]
733 m._files = [f for f in m._files if f is not None]
734 m._fmap = set(m._files)
734 m._fmap = set(m._files)
735 origmatchfn = m.matchfn
735 origmatchfn = m.matchfn
736 def matchfn(f):
736 def matchfn(f):
737 if lfutil.isstandin(f):
737 if lfutil.isstandin(f):
738 return (origmatchfn(lfutil.splitstandin(f)) and
738 return (origmatchfn(lfutil.splitstandin(f)) and
739 (f in repo[None] or f in ctx))
739 (f in repo[None] or f in ctx))
740 return origmatchfn(f)
740 return origmatchfn(f)
741 m.matchfn = matchfn
741 m.matchfn = matchfn
742 return m
742 return m
743 oldmatch = installmatchfn(overridematch)
743 oldmatch = installmatchfn(overridematch)
744 try:
744 try:
745 orig(ui, repo, *pats, **opts)
745 orig(ui, repo, *pats, **opts)
746 finally:
746 finally:
747 restorematchfn()
747 restorematchfn()
748
748
749 newstandins = lfutil.getstandinsstate(repo)
749 newstandins = lfutil.getstandinsstate(repo)
750 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
750 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
751 # lfdirstate should be 'normallookup'-ed for updated files,
751 # lfdirstate should be 'normallookup'-ed for updated files,
752 # because reverting doesn't touch dirstate for 'normal' files
752 # because reverting doesn't touch dirstate for 'normal' files
753 # when target revision is explicitly specified: in such case,
753 # when target revision is explicitly specified: in such case,
754 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
754 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
755 # of target (standin) file.
755 # of target (standin) file.
756 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
756 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
757 normallookup=True)
757 normallookup=True)
758
758
759 finally:
759 finally:
760 wlock.release()
760 wlock.release()
761
761
762 # after pulling changesets, we need to take some extra care to get
762 # after pulling changesets, we need to take some extra care to get
763 # largefiles updated remotely
763 # largefiles updated remotely
764 def overridepull(orig, ui, repo, source=None, **opts):
764 def overridepull(orig, ui, repo, source=None, **opts):
765 revsprepull = len(repo)
765 revsprepull = len(repo)
766 if not source:
766 if not source:
767 source = 'default'
767 source = 'default'
768 repo.lfpullsource = source
768 repo.lfpullsource = source
769 result = orig(ui, repo, source, **opts)
769 result = orig(ui, repo, source, **opts)
770 revspostpull = len(repo)
770 revspostpull = len(repo)
771 lfrevs = opts.get('lfrev', [])
771 lfrevs = opts.get('lfrev', [])
772 if opts.get('all_largefiles'):
772 if opts.get('all_largefiles'):
773 lfrevs.append('pulled()')
773 lfrevs.append('pulled()')
774 if lfrevs and revspostpull > revsprepull:
774 if lfrevs and revspostpull > revsprepull:
775 numcached = 0
775 numcached = 0
776 repo.firstpulled = revsprepull # for pulled() revset expression
776 repo.firstpulled = revsprepull # for pulled() revset expression
777 try:
777 try:
778 for rev in scmutil.revrange(repo, lfrevs):
778 for rev in scmutil.revrange(repo, lfrevs):
779 ui.note(_('pulling largefiles for revision %s\n') % rev)
779 ui.note(_('pulling largefiles for revision %s\n') % rev)
780 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
780 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
781 numcached += len(cached)
781 numcached += len(cached)
782 finally:
782 finally:
783 del repo.firstpulled
783 del repo.firstpulled
784 ui.status(_("%d largefiles cached\n") % numcached)
784 ui.status(_("%d largefiles cached\n") % numcached)
785 return result
785 return result
786
786
787 def pulledrevsetsymbol(repo, subset, x):
787 def pulledrevsetsymbol(repo, subset, x):
788 """``pulled()``
788 """``pulled()``
789 Changesets that just has been pulled.
789 Changesets that just has been pulled.
790
790
791 Only available with largefiles from pull --lfrev expressions.
791 Only available with largefiles from pull --lfrev expressions.
792
792
793 .. container:: verbose
793 .. container:: verbose
794
794
795 Some examples:
795 Some examples:
796
796
797 - pull largefiles for all new changesets::
797 - pull largefiles for all new changesets::
798
798
799 hg pull -lfrev "pulled()"
799 hg pull -lfrev "pulled()"
800
800
801 - pull largefiles for all new branch heads::
801 - pull largefiles for all new branch heads::
802
802
803 hg pull -lfrev "head(pulled()) and not closed()"
803 hg pull -lfrev "head(pulled()) and not closed()"
804
804
805 """
805 """
806
806
807 try:
807 try:
808 firstpulled = repo.firstpulled
808 firstpulled = repo.firstpulled
809 except AttributeError:
809 except AttributeError:
810 raise util.Abort(_("pulled() only available in --lfrev"))
810 raise util.Abort(_("pulled() only available in --lfrev"))
811 return revset.baseset([r for r in subset if r >= firstpulled])
811 return revset.baseset([r for r in subset if r >= firstpulled])
812
812
813 def overrideclone(orig, ui, source, dest=None, **opts):
813 def overrideclone(orig, ui, source, dest=None, **opts):
814 d = dest
814 d = dest
815 if d is None:
815 if d is None:
816 d = hg.defaultdest(source)
816 d = hg.defaultdest(source)
817 if opts.get('all_largefiles') and not hg.islocal(d):
817 if opts.get('all_largefiles') and not hg.islocal(d):
818 raise util.Abort(_(
818 raise util.Abort(_(
819 '--all-largefiles is incompatible with non-local destination %s') %
819 '--all-largefiles is incompatible with non-local destination %s') %
820 d)
820 d)
821
821
822 return orig(ui, source, dest, **opts)
822 return orig(ui, source, dest, **opts)
823
823
824 def hgclone(orig, ui, opts, *args, **kwargs):
824 def hgclone(orig, ui, opts, *args, **kwargs):
825 result = orig(ui, opts, *args, **kwargs)
825 result = orig(ui, opts, *args, **kwargs)
826
826
827 if result is not None:
827 if result is not None:
828 sourcerepo, destrepo = result
828 sourcerepo, destrepo = result
829 repo = destrepo.local()
829 repo = destrepo.local()
830
830
831 # If largefiles is required for this repo, permanently enable it locally
831 # If largefiles is required for this repo, permanently enable it locally
832 if 'largefiles' in repo.requirements:
832 if 'largefiles' in repo.requirements:
833 fp = repo.vfs('hgrc', 'a', text=True)
833 fp = repo.vfs('hgrc', 'a', text=True)
834 try:
834 try:
835 fp.write('\n[extensions]\nlargefiles=\n')
835 fp.write('\n[extensions]\nlargefiles=\n')
836 finally:
836 finally:
837 fp.close()
837 fp.close()
838
838
839 # Caching is implicitly limited to 'rev' option, since the dest repo was
839 # Caching is implicitly limited to 'rev' option, since the dest repo was
840 # truncated at that point. The user may expect a download count with
840 # truncated at that point. The user may expect a download count with
841 # this option, so attempt whether or not this is a largefile repo.
841 # this option, so attempt whether or not this is a largefile repo.
842 if opts.get('all_largefiles'):
842 if opts.get('all_largefiles'):
843 success, missing = lfcommands.downloadlfiles(ui, repo, None)
843 success, missing = lfcommands.downloadlfiles(ui, repo, None)
844
844
845 if missing != 0:
845 if missing != 0:
846 return None
846 return None
847
847
848 return result
848 return result
849
849
850 def overriderebase(orig, ui, repo, **opts):
850 def overriderebase(orig, ui, repo, **opts):
851 if not util.safehasattr(repo, '_largefilesenabled'):
852 return orig(ui, repo, **opts)
853
851 resuming = opts.get('continue')
854 resuming = opts.get('continue')
852 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
855 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
853 repo._lfstatuswriters.append(lambda *msg, **opts: None)
856 repo._lfstatuswriters.append(lambda *msg, **opts: None)
854 try:
857 try:
855 return orig(ui, repo, **opts)
858 return orig(ui, repo, **opts)
856 finally:
859 finally:
857 repo._lfstatuswriters.pop()
860 repo._lfstatuswriters.pop()
858 repo._lfcommithooks.pop()
861 repo._lfcommithooks.pop()
859
862
860 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
863 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
861 prefix=None, mtime=None, subrepos=None):
864 prefix=None, mtime=None, subrepos=None):
862 # No need to lock because we are only reading history and
865 # No need to lock because we are only reading history and
863 # largefile caches, neither of which are modified.
866 # largefile caches, neither of which are modified.
864 lfcommands.cachelfiles(repo.ui, repo, node)
867 lfcommands.cachelfiles(repo.ui, repo, node)
865
868
866 if kind not in archival.archivers:
869 if kind not in archival.archivers:
867 raise util.Abort(_("unknown archive type '%s'") % kind)
870 raise util.Abort(_("unknown archive type '%s'") % kind)
868
871
869 ctx = repo[node]
872 ctx = repo[node]
870
873
871 if kind == 'files':
874 if kind == 'files':
872 if prefix:
875 if prefix:
873 raise util.Abort(
876 raise util.Abort(
874 _('cannot give prefix when archiving to files'))
877 _('cannot give prefix when archiving to files'))
875 else:
878 else:
876 prefix = archival.tidyprefix(dest, kind, prefix)
879 prefix = archival.tidyprefix(dest, kind, prefix)
877
880
878 def write(name, mode, islink, getdata):
881 def write(name, mode, islink, getdata):
879 if matchfn and not matchfn(name):
882 if matchfn and not matchfn(name):
880 return
883 return
881 data = getdata()
884 data = getdata()
882 if decode:
885 if decode:
883 data = repo.wwritedata(name, data)
886 data = repo.wwritedata(name, data)
884 archiver.addfile(prefix + name, mode, islink, data)
887 archiver.addfile(prefix + name, mode, islink, data)
885
888
886 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
889 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
887
890
888 if repo.ui.configbool("ui", "archivemeta", True):
891 if repo.ui.configbool("ui", "archivemeta", True):
889 def metadata():
892 def metadata():
890 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
893 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
891 hex(repo.changelog.node(0)), hex(node), ctx.branch())
894 hex(repo.changelog.node(0)), hex(node), ctx.branch())
892
895
893 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
896 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
894 if repo.tagtype(t) == 'global')
897 if repo.tagtype(t) == 'global')
895 if not tags:
898 if not tags:
896 repo.ui.pushbuffer()
899 repo.ui.pushbuffer()
897 opts = {'template': '{latesttag}\n{latesttagdistance}',
900 opts = {'template': '{latesttag}\n{latesttagdistance}',
898 'style': '', 'patch': None, 'git': None}
901 'style': '', 'patch': None, 'git': None}
899 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
902 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
900 ltags, dist = repo.ui.popbuffer().split('\n')
903 ltags, dist = repo.ui.popbuffer().split('\n')
901 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
904 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
902 tags += 'latesttagdistance: %s\n' % dist
905 tags += 'latesttagdistance: %s\n' % dist
903
906
904 return base + tags
907 return base + tags
905
908
906 write('.hg_archival.txt', 0644, False, metadata)
909 write('.hg_archival.txt', 0644, False, metadata)
907
910
908 for f in ctx:
911 for f in ctx:
909 ff = ctx.flags(f)
912 ff = ctx.flags(f)
910 getdata = ctx[f].data
913 getdata = ctx[f].data
911 if lfutil.isstandin(f):
914 if lfutil.isstandin(f):
912 path = lfutil.findfile(repo, getdata().strip())
915 path = lfutil.findfile(repo, getdata().strip())
913 if path is None:
916 if path is None:
914 raise util.Abort(
917 raise util.Abort(
915 _('largefile %s not found in repo store or system cache')
918 _('largefile %s not found in repo store or system cache')
916 % lfutil.splitstandin(f))
919 % lfutil.splitstandin(f))
917 f = lfutil.splitstandin(f)
920 f = lfutil.splitstandin(f)
918
921
919 def getdatafn():
922 def getdatafn():
920 fd = None
923 fd = None
921 try:
924 try:
922 fd = open(path, 'rb')
925 fd = open(path, 'rb')
923 return fd.read()
926 return fd.read()
924 finally:
927 finally:
925 if fd:
928 if fd:
926 fd.close()
929 fd.close()
927
930
928 getdata = getdatafn
931 getdata = getdatafn
929 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
932 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
930
933
931 if subrepos:
934 if subrepos:
932 for subpath in sorted(ctx.substate):
935 for subpath in sorted(ctx.substate):
933 sub = ctx.sub(subpath)
936 sub = ctx.sub(subpath)
934 submatch = match_.narrowmatcher(subpath, matchfn)
937 submatch = match_.narrowmatcher(subpath, matchfn)
935 sub.archive(archiver, prefix, submatch)
938 sub.archive(archiver, prefix, submatch)
936
939
937 archiver.done()
940 archiver.done()
938
941
939 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None):
942 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None):
940 repo._get(repo._state + ('hg',))
943 repo._get(repo._state + ('hg',))
941 rev = repo._state[1]
944 rev = repo._state[1]
942 ctx = repo._repo[rev]
945 ctx = repo._repo[rev]
943
946
944 lfcommands.cachelfiles(repo.ui, repo._repo, ctx.node())
947 lfcommands.cachelfiles(repo.ui, repo._repo, ctx.node())
945
948
946 def write(name, mode, islink, getdata):
949 def write(name, mode, islink, getdata):
947 # At this point, the standin has been replaced with the largefile name,
950 # At this point, the standin has been replaced with the largefile name,
948 # so the normal matcher works here without the lfutil variants.
951 # so the normal matcher works here without the lfutil variants.
949 if match and not match(f):
952 if match and not match(f):
950 return
953 return
951 data = getdata()
954 data = getdata()
952
955
953 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
956 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
954
957
955 for f in ctx:
958 for f in ctx:
956 ff = ctx.flags(f)
959 ff = ctx.flags(f)
957 getdata = ctx[f].data
960 getdata = ctx[f].data
958 if lfutil.isstandin(f):
961 if lfutil.isstandin(f):
959 path = lfutil.findfile(repo._repo, getdata().strip())
962 path = lfutil.findfile(repo._repo, getdata().strip())
960 if path is None:
963 if path is None:
961 raise util.Abort(
964 raise util.Abort(
962 _('largefile %s not found in repo store or system cache')
965 _('largefile %s not found in repo store or system cache')
963 % lfutil.splitstandin(f))
966 % lfutil.splitstandin(f))
964 f = lfutil.splitstandin(f)
967 f = lfutil.splitstandin(f)
965
968
966 def getdatafn():
969 def getdatafn():
967 fd = None
970 fd = None
968 try:
971 try:
969 fd = open(os.path.join(prefix, path), 'rb')
972 fd = open(os.path.join(prefix, path), 'rb')
970 return fd.read()
973 return fd.read()
971 finally:
974 finally:
972 if fd:
975 if fd:
973 fd.close()
976 fd.close()
974
977
975 getdata = getdatafn
978 getdata = getdatafn
976
979
977 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
980 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
978
981
979 for subpath in sorted(ctx.substate):
982 for subpath in sorted(ctx.substate):
980 sub = ctx.sub(subpath)
983 sub = ctx.sub(subpath)
981 submatch = match_.narrowmatcher(subpath, match)
984 submatch = match_.narrowmatcher(subpath, match)
982 sub.archive(archiver, os.path.join(prefix, repo._path) + '/', submatch)
985 sub.archive(archiver, os.path.join(prefix, repo._path) + '/', submatch)
983
986
984 # If a largefile is modified, the change is not reflected in its
987 # If a largefile is modified, the change is not reflected in its
985 # standin until a commit. cmdutil.bailifchanged() raises an exception
988 # standin until a commit. cmdutil.bailifchanged() raises an exception
986 # if the repo has uncommitted changes. Wrap it to also check if
989 # if the repo has uncommitted changes. Wrap it to also check if
987 # largefiles were changed. This is used by bisect, backout and fetch.
990 # largefiles were changed. This is used by bisect, backout and fetch.
988 def overridebailifchanged(orig, repo):
991 def overridebailifchanged(orig, repo):
989 orig(repo)
992 orig(repo)
990 repo.lfstatus = True
993 repo.lfstatus = True
991 s = repo.status()
994 s = repo.status()
992 repo.lfstatus = False
995 repo.lfstatus = False
993 if s.modified or s.added or s.removed or s.deleted:
996 if s.modified or s.added or s.removed or s.deleted:
994 raise util.Abort(_('uncommitted changes'))
997 raise util.Abort(_('uncommitted changes'))
995
998
996 def cmdutilforget(orig, ui, repo, match, prefix, explicitonly):
999 def cmdutilforget(orig, ui, repo, match, prefix, explicitonly):
997 normalmatcher = composenormalfilematcher(match, repo[None].manifest())
1000 normalmatcher = composenormalfilematcher(match, repo[None].manifest())
998 bad, forgot = orig(ui, repo, normalmatcher, prefix, explicitonly)
1001 bad, forgot = orig(ui, repo, normalmatcher, prefix, explicitonly)
999 m = composelargefilematcher(match, repo[None].manifest())
1002 m = composelargefilematcher(match, repo[None].manifest())
1000
1003
1001 try:
1004 try:
1002 repo.lfstatus = True
1005 repo.lfstatus = True
1003 s = repo.status(match=m, clean=True)
1006 s = repo.status(match=m, clean=True)
1004 finally:
1007 finally:
1005 repo.lfstatus = False
1008 repo.lfstatus = False
1006 forget = sorted(s.modified + s.added + s.deleted + s.clean)
1009 forget = sorted(s.modified + s.added + s.deleted + s.clean)
1007 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
1010 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
1008
1011
1009 for f in forget:
1012 for f in forget:
1010 if lfutil.standin(f) not in repo.dirstate and not \
1013 if lfutil.standin(f) not in repo.dirstate and not \
1011 repo.wvfs.isdir(lfutil.standin(f)):
1014 repo.wvfs.isdir(lfutil.standin(f)):
1012 ui.warn(_('not removing %s: file is already untracked\n')
1015 ui.warn(_('not removing %s: file is already untracked\n')
1013 % m.rel(f))
1016 % m.rel(f))
1014 bad.append(f)
1017 bad.append(f)
1015
1018
1016 for f in forget:
1019 for f in forget:
1017 if ui.verbose or not m.exact(f):
1020 if ui.verbose or not m.exact(f):
1018 ui.status(_('removing %s\n') % m.rel(f))
1021 ui.status(_('removing %s\n') % m.rel(f))
1019
1022
1020 # Need to lock because standin files are deleted then removed from the
1023 # Need to lock because standin files are deleted then removed from the
1021 # repository and we could race in-between.
1024 # repository and we could race in-between.
1022 wlock = repo.wlock()
1025 wlock = repo.wlock()
1023 try:
1026 try:
1024 lfdirstate = lfutil.openlfdirstate(ui, repo)
1027 lfdirstate = lfutil.openlfdirstate(ui, repo)
1025 for f in forget:
1028 for f in forget:
1026 if lfdirstate[f] == 'a':
1029 if lfdirstate[f] == 'a':
1027 lfdirstate.drop(f)
1030 lfdirstate.drop(f)
1028 else:
1031 else:
1029 lfdirstate.remove(f)
1032 lfdirstate.remove(f)
1030 lfdirstate.write()
1033 lfdirstate.write()
1031 standins = [lfutil.standin(f) for f in forget]
1034 standins = [lfutil.standin(f) for f in forget]
1032 for f in standins:
1035 for f in standins:
1033 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1036 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1034 rejected = repo[None].forget(standins)
1037 rejected = repo[None].forget(standins)
1035 finally:
1038 finally:
1036 wlock.release()
1039 wlock.release()
1037
1040
1038 bad.extend(f for f in rejected if f in m.files())
1041 bad.extend(f for f in rejected if f in m.files())
1039 forgot.extend(f for f in forget if f not in rejected)
1042 forgot.extend(f for f in forget if f not in rejected)
1040 return bad, forgot
1043 return bad, forgot
1041
1044
1042 def _getoutgoings(repo, other, missing, addfunc):
1045 def _getoutgoings(repo, other, missing, addfunc):
1043 """get pairs of filename and largefile hash in outgoing revisions
1046 """get pairs of filename and largefile hash in outgoing revisions
1044 in 'missing'.
1047 in 'missing'.
1045
1048
1046 largefiles already existing on 'other' repository are ignored.
1049 largefiles already existing on 'other' repository are ignored.
1047
1050
1048 'addfunc' is invoked with each unique pairs of filename and
1051 'addfunc' is invoked with each unique pairs of filename and
1049 largefile hash value.
1052 largefile hash value.
1050 """
1053 """
1051 knowns = set()
1054 knowns = set()
1052 lfhashes = set()
1055 lfhashes = set()
1053 def dedup(fn, lfhash):
1056 def dedup(fn, lfhash):
1054 k = (fn, lfhash)
1057 k = (fn, lfhash)
1055 if k not in knowns:
1058 if k not in knowns:
1056 knowns.add(k)
1059 knowns.add(k)
1057 lfhashes.add(lfhash)
1060 lfhashes.add(lfhash)
1058 lfutil.getlfilestoupload(repo, missing, dedup)
1061 lfutil.getlfilestoupload(repo, missing, dedup)
1059 if lfhashes:
1062 if lfhashes:
1060 lfexists = basestore._openstore(repo, other).exists(lfhashes)
1063 lfexists = basestore._openstore(repo, other).exists(lfhashes)
1061 for fn, lfhash in knowns:
1064 for fn, lfhash in knowns:
1062 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1065 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1063 addfunc(fn, lfhash)
1066 addfunc(fn, lfhash)
1064
1067
1065 def outgoinghook(ui, repo, other, opts, missing):
1068 def outgoinghook(ui, repo, other, opts, missing):
1066 if opts.pop('large', None):
1069 if opts.pop('large', None):
1067 lfhashes = set()
1070 lfhashes = set()
1068 if ui.debugflag:
1071 if ui.debugflag:
1069 toupload = {}
1072 toupload = {}
1070 def addfunc(fn, lfhash):
1073 def addfunc(fn, lfhash):
1071 if fn not in toupload:
1074 if fn not in toupload:
1072 toupload[fn] = []
1075 toupload[fn] = []
1073 toupload[fn].append(lfhash)
1076 toupload[fn].append(lfhash)
1074 lfhashes.add(lfhash)
1077 lfhashes.add(lfhash)
1075 def showhashes(fn):
1078 def showhashes(fn):
1076 for lfhash in sorted(toupload[fn]):
1079 for lfhash in sorted(toupload[fn]):
1077 ui.debug(' %s\n' % (lfhash))
1080 ui.debug(' %s\n' % (lfhash))
1078 else:
1081 else:
1079 toupload = set()
1082 toupload = set()
1080 def addfunc(fn, lfhash):
1083 def addfunc(fn, lfhash):
1081 toupload.add(fn)
1084 toupload.add(fn)
1082 lfhashes.add(lfhash)
1085 lfhashes.add(lfhash)
1083 def showhashes(fn):
1086 def showhashes(fn):
1084 pass
1087 pass
1085 _getoutgoings(repo, other, missing, addfunc)
1088 _getoutgoings(repo, other, missing, addfunc)
1086
1089
1087 if not toupload:
1090 if not toupload:
1088 ui.status(_('largefiles: no files to upload\n'))
1091 ui.status(_('largefiles: no files to upload\n'))
1089 else:
1092 else:
1090 ui.status(_('largefiles to upload (%d entities):\n')
1093 ui.status(_('largefiles to upload (%d entities):\n')
1091 % (len(lfhashes)))
1094 % (len(lfhashes)))
1092 for file in sorted(toupload):
1095 for file in sorted(toupload):
1093 ui.status(lfutil.splitstandin(file) + '\n')
1096 ui.status(lfutil.splitstandin(file) + '\n')
1094 showhashes(file)
1097 showhashes(file)
1095 ui.status('\n')
1098 ui.status('\n')
1096
1099
1097 def summaryremotehook(ui, repo, opts, changes):
1100 def summaryremotehook(ui, repo, opts, changes):
1098 largeopt = opts.get('large', False)
1101 largeopt = opts.get('large', False)
1099 if changes is None:
1102 if changes is None:
1100 if largeopt:
1103 if largeopt:
1101 return (False, True) # only outgoing check is needed
1104 return (False, True) # only outgoing check is needed
1102 else:
1105 else:
1103 return (False, False)
1106 return (False, False)
1104 elif largeopt:
1107 elif largeopt:
1105 url, branch, peer, outgoing = changes[1]
1108 url, branch, peer, outgoing = changes[1]
1106 if peer is None:
1109 if peer is None:
1107 # i18n: column positioning for "hg summary"
1110 # i18n: column positioning for "hg summary"
1108 ui.status(_('largefiles: (no remote repo)\n'))
1111 ui.status(_('largefiles: (no remote repo)\n'))
1109 return
1112 return
1110
1113
1111 toupload = set()
1114 toupload = set()
1112 lfhashes = set()
1115 lfhashes = set()
1113 def addfunc(fn, lfhash):
1116 def addfunc(fn, lfhash):
1114 toupload.add(fn)
1117 toupload.add(fn)
1115 lfhashes.add(lfhash)
1118 lfhashes.add(lfhash)
1116 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1119 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1117
1120
1118 if not toupload:
1121 if not toupload:
1119 # i18n: column positioning for "hg summary"
1122 # i18n: column positioning for "hg summary"
1120 ui.status(_('largefiles: (no files to upload)\n'))
1123 ui.status(_('largefiles: (no files to upload)\n'))
1121 else:
1124 else:
1122 # i18n: column positioning for "hg summary"
1125 # i18n: column positioning for "hg summary"
1123 ui.status(_('largefiles: %d entities for %d files to upload\n')
1126 ui.status(_('largefiles: %d entities for %d files to upload\n')
1124 % (len(lfhashes), len(toupload)))
1127 % (len(lfhashes), len(toupload)))
1125
1128
1126 def overridesummary(orig, ui, repo, *pats, **opts):
1129 def overridesummary(orig, ui, repo, *pats, **opts):
1127 try:
1130 try:
1128 repo.lfstatus = True
1131 repo.lfstatus = True
1129 orig(ui, repo, *pats, **opts)
1132 orig(ui, repo, *pats, **opts)
1130 finally:
1133 finally:
1131 repo.lfstatus = False
1134 repo.lfstatus = False
1132
1135
1133 def scmutiladdremove(orig, repo, matcher, prefix, opts={}, dry_run=None,
1136 def scmutiladdremove(orig, repo, matcher, prefix, opts={}, dry_run=None,
1134 similarity=None):
1137 similarity=None):
1135 if not lfutil.islfilesrepo(repo):
1138 if not lfutil.islfilesrepo(repo):
1136 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1139 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1137 # Get the list of missing largefiles so we can remove them
1140 # Get the list of missing largefiles so we can remove them
1138 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1141 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1139 unsure, s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
1142 unsure, s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
1140 False, False, False)
1143 False, False, False)
1141
1144
1142 # Call into the normal remove code, but the removing of the standin, we want
1145 # Call into the normal remove code, but the removing of the standin, we want
1143 # to have handled by original addremove. Monkey patching here makes sure
1146 # to have handled by original addremove. Monkey patching here makes sure
1144 # we don't remove the standin in the largefiles code, preventing a very
1147 # we don't remove the standin in the largefiles code, preventing a very
1145 # confused state later.
1148 # confused state later.
1146 if s.deleted:
1149 if s.deleted:
1147 m = copy.copy(matcher)
1150 m = copy.copy(matcher)
1148
1151
1149 # The m._files and m._map attributes are not changed to the deleted list
1152 # The m._files and m._map attributes are not changed to the deleted list
1150 # because that affects the m.exact() test, which in turn governs whether
1153 # because that affects the m.exact() test, which in turn governs whether
1151 # or not the file name is printed, and how. Simply limit the original
1154 # or not the file name is printed, and how. Simply limit the original
1152 # matches to those in the deleted status list.
1155 # matches to those in the deleted status list.
1153 matchfn = m.matchfn
1156 matchfn = m.matchfn
1154 m.matchfn = lambda f: f in s.deleted and matchfn(f)
1157 m.matchfn = lambda f: f in s.deleted and matchfn(f)
1155
1158
1156 removelargefiles(repo.ui, repo, True, m, **opts)
1159 removelargefiles(repo.ui, repo, True, m, **opts)
1157 # Call into the normal add code, and any files that *should* be added as
1160 # Call into the normal add code, and any files that *should* be added as
1158 # largefiles will be
1161 # largefiles will be
1159 added, bad = addlargefiles(repo.ui, repo, True, matcher, **opts)
1162 added, bad = addlargefiles(repo.ui, repo, True, matcher, **opts)
1160 # Now that we've handled largefiles, hand off to the original addremove
1163 # Now that we've handled largefiles, hand off to the original addremove
1161 # function to take care of the rest. Make sure it doesn't do anything with
1164 # function to take care of the rest. Make sure it doesn't do anything with
1162 # largefiles by passing a matcher that will ignore them.
1165 # largefiles by passing a matcher that will ignore them.
1163 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
1166 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
1164 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1167 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1165
1168
1166 # Calling purge with --all will cause the largefiles to be deleted.
1169 # Calling purge with --all will cause the largefiles to be deleted.
1167 # Override repo.status to prevent this from happening.
1170 # Override repo.status to prevent this from happening.
1168 def overridepurge(orig, ui, repo, *dirs, **opts):
1171 def overridepurge(orig, ui, repo, *dirs, **opts):
1169 # XXX Monkey patching a repoview will not work. The assigned attribute will
1172 # XXX Monkey patching a repoview will not work. The assigned attribute will
1170 # be set on the unfiltered repo, but we will only lookup attributes in the
1173 # be set on the unfiltered repo, but we will only lookup attributes in the
1171 # unfiltered repo if the lookup in the repoview object itself fails. As the
1174 # unfiltered repo if the lookup in the repoview object itself fails. As the
1172 # monkey patched method exists on the repoview class the lookup will not
1175 # monkey patched method exists on the repoview class the lookup will not
1173 # fail. As a result, the original version will shadow the monkey patched
1176 # fail. As a result, the original version will shadow the monkey patched
1174 # one, defeating the monkey patch.
1177 # one, defeating the monkey patch.
1175 #
1178 #
1176 # As a work around we use an unfiltered repo here. We should do something
1179 # As a work around we use an unfiltered repo here. We should do something
1177 # cleaner instead.
1180 # cleaner instead.
1178 repo = repo.unfiltered()
1181 repo = repo.unfiltered()
1179 oldstatus = repo.status
1182 oldstatus = repo.status
1180 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1183 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1181 clean=False, unknown=False, listsubrepos=False):
1184 clean=False, unknown=False, listsubrepos=False):
1182 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1185 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1183 listsubrepos)
1186 listsubrepos)
1184 lfdirstate = lfutil.openlfdirstate(ui, repo)
1187 lfdirstate = lfutil.openlfdirstate(ui, repo)
1185 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1188 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1186 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1189 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1187 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1190 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1188 unknown, ignored, r.clean)
1191 unknown, ignored, r.clean)
1189 repo.status = overridestatus
1192 repo.status = overridestatus
1190 orig(ui, repo, *dirs, **opts)
1193 orig(ui, repo, *dirs, **opts)
1191 repo.status = oldstatus
1194 repo.status = oldstatus
1192 def overriderollback(orig, ui, repo, **opts):
1195 def overriderollback(orig, ui, repo, **opts):
1193 wlock = repo.wlock()
1196 wlock = repo.wlock()
1194 try:
1197 try:
1195 before = repo.dirstate.parents()
1198 before = repo.dirstate.parents()
1196 orphans = set(f for f in repo.dirstate
1199 orphans = set(f for f in repo.dirstate
1197 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1200 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1198 result = orig(ui, repo, **opts)
1201 result = orig(ui, repo, **opts)
1199 after = repo.dirstate.parents()
1202 after = repo.dirstate.parents()
1200 if before == after:
1203 if before == after:
1201 return result # no need to restore standins
1204 return result # no need to restore standins
1202
1205
1203 pctx = repo['.']
1206 pctx = repo['.']
1204 for f in repo.dirstate:
1207 for f in repo.dirstate:
1205 if lfutil.isstandin(f):
1208 if lfutil.isstandin(f):
1206 orphans.discard(f)
1209 orphans.discard(f)
1207 if repo.dirstate[f] == 'r':
1210 if repo.dirstate[f] == 'r':
1208 repo.wvfs.unlinkpath(f, ignoremissing=True)
1211 repo.wvfs.unlinkpath(f, ignoremissing=True)
1209 elif f in pctx:
1212 elif f in pctx:
1210 fctx = pctx[f]
1213 fctx = pctx[f]
1211 repo.wwrite(f, fctx.data(), fctx.flags())
1214 repo.wwrite(f, fctx.data(), fctx.flags())
1212 else:
1215 else:
1213 # content of standin is not so important in 'a',
1216 # content of standin is not so important in 'a',
1214 # 'm' or 'n' (coming from the 2nd parent) cases
1217 # 'm' or 'n' (coming from the 2nd parent) cases
1215 lfutil.writestandin(repo, f, '', False)
1218 lfutil.writestandin(repo, f, '', False)
1216 for standin in orphans:
1219 for standin in orphans:
1217 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1220 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1218
1221
1219 lfdirstate = lfutil.openlfdirstate(ui, repo)
1222 lfdirstate = lfutil.openlfdirstate(ui, repo)
1220 orphans = set(lfdirstate)
1223 orphans = set(lfdirstate)
1221 lfiles = lfutil.listlfiles(repo)
1224 lfiles = lfutil.listlfiles(repo)
1222 for file in lfiles:
1225 for file in lfiles:
1223 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1226 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1224 orphans.discard(file)
1227 orphans.discard(file)
1225 for lfile in orphans:
1228 for lfile in orphans:
1226 lfdirstate.drop(lfile)
1229 lfdirstate.drop(lfile)
1227 lfdirstate.write()
1230 lfdirstate.write()
1228 finally:
1231 finally:
1229 wlock.release()
1232 wlock.release()
1230 return result
1233 return result
1231
1234
1232 def overridetransplant(orig, ui, repo, *revs, **opts):
1235 def overridetransplant(orig, ui, repo, *revs, **opts):
1233 resuming = opts.get('continue')
1236 resuming = opts.get('continue')
1234 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1237 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1235 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1238 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1236 try:
1239 try:
1237 result = orig(ui, repo, *revs, **opts)
1240 result = orig(ui, repo, *revs, **opts)
1238 finally:
1241 finally:
1239 repo._lfstatuswriters.pop()
1242 repo._lfstatuswriters.pop()
1240 repo._lfcommithooks.pop()
1243 repo._lfcommithooks.pop()
1241 return result
1244 return result
1242
1245
1243 def overridecat(orig, ui, repo, file1, *pats, **opts):
1246 def overridecat(orig, ui, repo, file1, *pats, **opts):
1244 ctx = scmutil.revsingle(repo, opts.get('rev'))
1247 ctx = scmutil.revsingle(repo, opts.get('rev'))
1245 err = 1
1248 err = 1
1246 notbad = set()
1249 notbad = set()
1247 m = scmutil.match(ctx, (file1,) + pats, opts)
1250 m = scmutil.match(ctx, (file1,) + pats, opts)
1248 origmatchfn = m.matchfn
1251 origmatchfn = m.matchfn
1249 def lfmatchfn(f):
1252 def lfmatchfn(f):
1250 if origmatchfn(f):
1253 if origmatchfn(f):
1251 return True
1254 return True
1252 lf = lfutil.splitstandin(f)
1255 lf = lfutil.splitstandin(f)
1253 if lf is None:
1256 if lf is None:
1254 return False
1257 return False
1255 notbad.add(lf)
1258 notbad.add(lf)
1256 return origmatchfn(lf)
1259 return origmatchfn(lf)
1257 m.matchfn = lfmatchfn
1260 m.matchfn = lfmatchfn
1258 origbadfn = m.bad
1261 origbadfn = m.bad
1259 def lfbadfn(f, msg):
1262 def lfbadfn(f, msg):
1260 if not f in notbad:
1263 if not f in notbad:
1261 origbadfn(f, msg)
1264 origbadfn(f, msg)
1262 m.bad = lfbadfn
1265 m.bad = lfbadfn
1263 for f in ctx.walk(m):
1266 for f in ctx.walk(m):
1264 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1267 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1265 pathname=f)
1268 pathname=f)
1266 lf = lfutil.splitstandin(f)
1269 lf = lfutil.splitstandin(f)
1267 if lf is None or origmatchfn(f):
1270 if lf is None or origmatchfn(f):
1268 # duplicating unreachable code from commands.cat
1271 # duplicating unreachable code from commands.cat
1269 data = ctx[f].data()
1272 data = ctx[f].data()
1270 if opts.get('decode'):
1273 if opts.get('decode'):
1271 data = repo.wwritedata(f, data)
1274 data = repo.wwritedata(f, data)
1272 fp.write(data)
1275 fp.write(data)
1273 else:
1276 else:
1274 hash = lfutil.readstandin(repo, lf, ctx.rev())
1277 hash = lfutil.readstandin(repo, lf, ctx.rev())
1275 if not lfutil.inusercache(repo.ui, hash):
1278 if not lfutil.inusercache(repo.ui, hash):
1276 store = basestore._openstore(repo)
1279 store = basestore._openstore(repo)
1277 success, missing = store.get([(lf, hash)])
1280 success, missing = store.get([(lf, hash)])
1278 if len(success) != 1:
1281 if len(success) != 1:
1279 raise util.Abort(
1282 raise util.Abort(
1280 _('largefile %s is not in cache and could not be '
1283 _('largefile %s is not in cache and could not be '
1281 'downloaded') % lf)
1284 'downloaded') % lf)
1282 path = lfutil.usercachepath(repo.ui, hash)
1285 path = lfutil.usercachepath(repo.ui, hash)
1283 fpin = open(path, "rb")
1286 fpin = open(path, "rb")
1284 for chunk in util.filechunkiter(fpin, 128 * 1024):
1287 for chunk in util.filechunkiter(fpin, 128 * 1024):
1285 fp.write(chunk)
1288 fp.write(chunk)
1286 fpin.close()
1289 fpin.close()
1287 fp.close()
1290 fp.close()
1288 err = 0
1291 err = 0
1289 return err
1292 return err
1290
1293
1291 def mergeupdate(orig, repo, node, branchmerge, force, partial,
1294 def mergeupdate(orig, repo, node, branchmerge, force, partial,
1292 *args, **kwargs):
1295 *args, **kwargs):
1293 wlock = repo.wlock()
1296 wlock = repo.wlock()
1294 try:
1297 try:
1295 # branch | | |
1298 # branch | | |
1296 # merge | force | partial | action
1299 # merge | force | partial | action
1297 # -------+-------+---------+--------------
1300 # -------+-------+---------+--------------
1298 # x | x | x | linear-merge
1301 # x | x | x | linear-merge
1299 # o | x | x | branch-merge
1302 # o | x | x | branch-merge
1300 # x | o | x | overwrite (as clean update)
1303 # x | o | x | overwrite (as clean update)
1301 # o | o | x | force-branch-merge (*1)
1304 # o | o | x | force-branch-merge (*1)
1302 # x | x | o | (*)
1305 # x | x | o | (*)
1303 # o | x | o | (*)
1306 # o | x | o | (*)
1304 # x | o | o | overwrite (as revert)
1307 # x | o | o | overwrite (as revert)
1305 # o | o | o | (*)
1308 # o | o | o | (*)
1306 #
1309 #
1307 # (*) don't care
1310 # (*) don't care
1308 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1311 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1309
1312
1310 linearmerge = not branchmerge and not force and not partial
1313 linearmerge = not branchmerge and not force and not partial
1311
1314
1312 if linearmerge or (branchmerge and force and not partial):
1315 if linearmerge or (branchmerge and force and not partial):
1313 # update standins for linear-merge or force-branch-merge,
1316 # update standins for linear-merge or force-branch-merge,
1314 # because largefiles in the working directory may be modified
1317 # because largefiles in the working directory may be modified
1315 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1318 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1316 unsure, s = lfdirstate.status(match_.always(repo.root,
1319 unsure, s = lfdirstate.status(match_.always(repo.root,
1317 repo.getcwd()),
1320 repo.getcwd()),
1318 [], False, False, False)
1321 [], False, False, False)
1319 pctx = repo['.']
1322 pctx = repo['.']
1320 for lfile in unsure + s.modified:
1323 for lfile in unsure + s.modified:
1321 lfileabs = repo.wvfs.join(lfile)
1324 lfileabs = repo.wvfs.join(lfile)
1322 if not os.path.exists(lfileabs):
1325 if not os.path.exists(lfileabs):
1323 continue
1326 continue
1324 lfhash = lfutil.hashrepofile(repo, lfile)
1327 lfhash = lfutil.hashrepofile(repo, lfile)
1325 standin = lfutil.standin(lfile)
1328 standin = lfutil.standin(lfile)
1326 lfutil.writestandin(repo, standin, lfhash,
1329 lfutil.writestandin(repo, standin, lfhash,
1327 lfutil.getexecutable(lfileabs))
1330 lfutil.getexecutable(lfileabs))
1328 if (standin in pctx and
1331 if (standin in pctx and
1329 lfhash == lfutil.readstandin(repo, lfile, '.')):
1332 lfhash == lfutil.readstandin(repo, lfile, '.')):
1330 lfdirstate.normal(lfile)
1333 lfdirstate.normal(lfile)
1331 for lfile in s.added:
1334 for lfile in s.added:
1332 lfutil.updatestandin(repo, lfutil.standin(lfile))
1335 lfutil.updatestandin(repo, lfutil.standin(lfile))
1333 lfdirstate.write()
1336 lfdirstate.write()
1334
1337
1335 if linearmerge:
1338 if linearmerge:
1336 # Only call updatelfiles on the standins that have changed
1339 # Only call updatelfiles on the standins that have changed
1337 # to save time
1340 # to save time
1338 oldstandins = lfutil.getstandinsstate(repo)
1341 oldstandins = lfutil.getstandinsstate(repo)
1339
1342
1340 result = orig(repo, node, branchmerge, force, partial, *args, **kwargs)
1343 result = orig(repo, node, branchmerge, force, partial, *args, **kwargs)
1341
1344
1342 filelist = None
1345 filelist = None
1343 if linearmerge:
1346 if linearmerge:
1344 newstandins = lfutil.getstandinsstate(repo)
1347 newstandins = lfutil.getstandinsstate(repo)
1345 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1348 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1346
1349
1347 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1350 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1348 normallookup=partial, checked=linearmerge)
1351 normallookup=partial, checked=linearmerge)
1349
1352
1350 return result
1353 return result
1351 finally:
1354 finally:
1352 wlock.release()
1355 wlock.release()
1353
1356
1354 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1357 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1355 result = orig(repo, files, *args, **kwargs)
1358 result = orig(repo, files, *args, **kwargs)
1356
1359
1357 filelist = [lfutil.splitstandin(f) for f in files if lfutil.isstandin(f)]
1360 filelist = [lfutil.splitstandin(f) for f in files if lfutil.isstandin(f)]
1358 if filelist:
1361 if filelist:
1359 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1362 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1360 printmessage=False, normallookup=True)
1363 printmessage=False, normallookup=True)
1361
1364
1362 return result
1365 return result
@@ -1,371 +1,374 b''
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''setup for largefiles repositories: reposetup'''
9 '''setup for largefiles repositories: reposetup'''
10 import copy
10 import copy
11 import os
11 import os
12
12
13 from mercurial import error, manifest, match as match_, util
13 from mercurial import error, manifest, match as match_, util
14 from mercurial.i18n import _
14 from mercurial.i18n import _
15 from mercurial import scmutil, localrepo
15 from mercurial import scmutil, localrepo
16
16
17 import lfcommands
17 import lfcommands
18 import lfutil
18 import lfutil
19
19
20 def reposetup(ui, repo):
20 def reposetup(ui, repo):
21 # wire repositories should be given new wireproto functions
21 # wire repositories should be given new wireproto functions
22 # by "proto.wirereposetup()" via "hg.wirepeersetupfuncs"
22 # by "proto.wirereposetup()" via "hg.wirepeersetupfuncs"
23 if not repo.local():
23 if not repo.local():
24 return
24 return
25
25
26 class lfilesrepo(repo.__class__):
26 class lfilesrepo(repo.__class__):
27 # the mark to examine whether "repo" object enables largefiles or not
28 _largefilesenabled = True
29
27 lfstatus = False
30 lfstatus = False
28 def status_nolfiles(self, *args, **kwargs):
31 def status_nolfiles(self, *args, **kwargs):
29 return super(lfilesrepo, self).status(*args, **kwargs)
32 return super(lfilesrepo, self).status(*args, **kwargs)
30
33
31 # When lfstatus is set, return a context that gives the names
34 # When lfstatus is set, return a context that gives the names
32 # of largefiles instead of their corresponding standins and
35 # of largefiles instead of their corresponding standins and
33 # identifies the largefiles as always binary, regardless of
36 # identifies the largefiles as always binary, regardless of
34 # their actual contents.
37 # their actual contents.
35 def __getitem__(self, changeid):
38 def __getitem__(self, changeid):
36 ctx = super(lfilesrepo, self).__getitem__(changeid)
39 ctx = super(lfilesrepo, self).__getitem__(changeid)
37 if self.lfstatus:
40 if self.lfstatus:
38 class lfilesmanifestdict(manifest.manifestdict):
41 class lfilesmanifestdict(manifest.manifestdict):
39 def __contains__(self, filename):
42 def __contains__(self, filename):
40 orig = super(lfilesmanifestdict, self).__contains__
43 orig = super(lfilesmanifestdict, self).__contains__
41 return orig(filename) or orig(lfutil.standin(filename))
44 return orig(filename) or orig(lfutil.standin(filename))
42 class lfilesctx(ctx.__class__):
45 class lfilesctx(ctx.__class__):
43 def files(self):
46 def files(self):
44 filenames = super(lfilesctx, self).files()
47 filenames = super(lfilesctx, self).files()
45 return [lfutil.splitstandin(f) or f for f in filenames]
48 return [lfutil.splitstandin(f) or f for f in filenames]
46 def manifest(self):
49 def manifest(self):
47 man1 = super(lfilesctx, self).manifest()
50 man1 = super(lfilesctx, self).manifest()
48 man1.__class__ = lfilesmanifestdict
51 man1.__class__ = lfilesmanifestdict
49 return man1
52 return man1
50 def filectx(self, path, fileid=None, filelog=None):
53 def filectx(self, path, fileid=None, filelog=None):
51 orig = super(lfilesctx, self).filectx
54 orig = super(lfilesctx, self).filectx
52 try:
55 try:
53 if filelog is not None:
56 if filelog is not None:
54 result = orig(path, fileid, filelog)
57 result = orig(path, fileid, filelog)
55 else:
58 else:
56 result = orig(path, fileid)
59 result = orig(path, fileid)
57 except error.LookupError:
60 except error.LookupError:
58 # Adding a null character will cause Mercurial to
61 # Adding a null character will cause Mercurial to
59 # identify this as a binary file.
62 # identify this as a binary file.
60 if filelog is not None:
63 if filelog is not None:
61 result = orig(lfutil.standin(path), fileid,
64 result = orig(lfutil.standin(path), fileid,
62 filelog)
65 filelog)
63 else:
66 else:
64 result = orig(lfutil.standin(path), fileid)
67 result = orig(lfutil.standin(path), fileid)
65 olddata = result.data
68 olddata = result.data
66 result.data = lambda: olddata() + '\0'
69 result.data = lambda: olddata() + '\0'
67 return result
70 return result
68 ctx.__class__ = lfilesctx
71 ctx.__class__ = lfilesctx
69 return ctx
72 return ctx
70
73
71 # Figure out the status of big files and insert them into the
74 # Figure out the status of big files and insert them into the
72 # appropriate list in the result. Also removes standin files
75 # appropriate list in the result. Also removes standin files
73 # from the listing. Revert to the original status if
76 # from the listing. Revert to the original status if
74 # self.lfstatus is False.
77 # self.lfstatus is False.
75 # XXX large file status is buggy when used on repo proxy.
78 # XXX large file status is buggy when used on repo proxy.
76 # XXX this needs to be investigated.
79 # XXX this needs to be investigated.
77 @localrepo.unfilteredmethod
80 @localrepo.unfilteredmethod
78 def status(self, node1='.', node2=None, match=None, ignored=False,
81 def status(self, node1='.', node2=None, match=None, ignored=False,
79 clean=False, unknown=False, listsubrepos=False):
82 clean=False, unknown=False, listsubrepos=False):
80 listignored, listclean, listunknown = ignored, clean, unknown
83 listignored, listclean, listunknown = ignored, clean, unknown
81 orig = super(lfilesrepo, self).status
84 orig = super(lfilesrepo, self).status
82 if not self.lfstatus:
85 if not self.lfstatus:
83 return orig(node1, node2, match, listignored, listclean,
86 return orig(node1, node2, match, listignored, listclean,
84 listunknown, listsubrepos)
87 listunknown, listsubrepos)
85
88
86 # some calls in this function rely on the old version of status
89 # some calls in this function rely on the old version of status
87 self.lfstatus = False
90 self.lfstatus = False
88 ctx1 = self[node1]
91 ctx1 = self[node1]
89 ctx2 = self[node2]
92 ctx2 = self[node2]
90 working = ctx2.rev() is None
93 working = ctx2.rev() is None
91 parentworking = working and ctx1 == self['.']
94 parentworking = working and ctx1 == self['.']
92
95
93 if match is None:
96 if match is None:
94 match = match_.always(self.root, self.getcwd())
97 match = match_.always(self.root, self.getcwd())
95
98
96 wlock = None
99 wlock = None
97 try:
100 try:
98 try:
101 try:
99 # updating the dirstate is optional
102 # updating the dirstate is optional
100 # so we don't wait on the lock
103 # so we don't wait on the lock
101 wlock = self.wlock(False)
104 wlock = self.wlock(False)
102 except error.LockError:
105 except error.LockError:
103 pass
106 pass
104
107
105 # First check if paths or patterns were specified on the
108 # First check if paths or patterns were specified on the
106 # command line. If there were, and they don't match any
109 # command line. If there were, and they don't match any
107 # largefiles, we should just bail here and let super
110 # largefiles, we should just bail here and let super
108 # handle it -- thus gaining a big performance boost.
111 # handle it -- thus gaining a big performance boost.
109 lfdirstate = lfutil.openlfdirstate(ui, self)
112 lfdirstate = lfutil.openlfdirstate(ui, self)
110 if not match.always():
113 if not match.always():
111 for f in lfdirstate:
114 for f in lfdirstate:
112 if match(f):
115 if match(f):
113 break
116 break
114 else:
117 else:
115 return orig(node1, node2, match, listignored, listclean,
118 return orig(node1, node2, match, listignored, listclean,
116 listunknown, listsubrepos)
119 listunknown, listsubrepos)
117
120
118 # Create a copy of match that matches standins instead
121 # Create a copy of match that matches standins instead
119 # of largefiles.
122 # of largefiles.
120 def tostandins(files):
123 def tostandins(files):
121 if not working:
124 if not working:
122 return files
125 return files
123 newfiles = []
126 newfiles = []
124 dirstate = self.dirstate
127 dirstate = self.dirstate
125 for f in files:
128 for f in files:
126 sf = lfutil.standin(f)
129 sf = lfutil.standin(f)
127 if sf in dirstate:
130 if sf in dirstate:
128 newfiles.append(sf)
131 newfiles.append(sf)
129 elif sf in dirstate.dirs():
132 elif sf in dirstate.dirs():
130 # Directory entries could be regular or
133 # Directory entries could be regular or
131 # standin, check both
134 # standin, check both
132 newfiles.extend((f, sf))
135 newfiles.extend((f, sf))
133 else:
136 else:
134 newfiles.append(f)
137 newfiles.append(f)
135 return newfiles
138 return newfiles
136
139
137 m = copy.copy(match)
140 m = copy.copy(match)
138 m._files = tostandins(m._files)
141 m._files = tostandins(m._files)
139
142
140 result = orig(node1, node2, m, ignored, clean, unknown,
143 result = orig(node1, node2, m, ignored, clean, unknown,
141 listsubrepos)
144 listsubrepos)
142 if working:
145 if working:
143
146
144 def sfindirstate(f):
147 def sfindirstate(f):
145 sf = lfutil.standin(f)
148 sf = lfutil.standin(f)
146 dirstate = self.dirstate
149 dirstate = self.dirstate
147 return sf in dirstate or sf in dirstate.dirs()
150 return sf in dirstate or sf in dirstate.dirs()
148
151
149 match._files = [f for f in match._files
152 match._files = [f for f in match._files
150 if sfindirstate(f)]
153 if sfindirstate(f)]
151 # Don't waste time getting the ignored and unknown
154 # Don't waste time getting the ignored and unknown
152 # files from lfdirstate
155 # files from lfdirstate
153 unsure, s = lfdirstate.status(match, [], False, listclean,
156 unsure, s = lfdirstate.status(match, [], False, listclean,
154 False)
157 False)
155 (modified, added, removed, clean) = (s.modified, s.added,
158 (modified, added, removed, clean) = (s.modified, s.added,
156 s.removed, s.clean)
159 s.removed, s.clean)
157 if parentworking:
160 if parentworking:
158 for lfile in unsure:
161 for lfile in unsure:
159 standin = lfutil.standin(lfile)
162 standin = lfutil.standin(lfile)
160 if standin not in ctx1:
163 if standin not in ctx1:
161 # from second parent
164 # from second parent
162 modified.append(lfile)
165 modified.append(lfile)
163 elif ctx1[standin].data().strip() \
166 elif ctx1[standin].data().strip() \
164 != lfutil.hashfile(self.wjoin(lfile)):
167 != lfutil.hashfile(self.wjoin(lfile)):
165 modified.append(lfile)
168 modified.append(lfile)
166 else:
169 else:
167 if listclean:
170 if listclean:
168 clean.append(lfile)
171 clean.append(lfile)
169 lfdirstate.normal(lfile)
172 lfdirstate.normal(lfile)
170 else:
173 else:
171 tocheck = unsure + modified + added + clean
174 tocheck = unsure + modified + added + clean
172 modified, added, clean = [], [], []
175 modified, added, clean = [], [], []
173 checkexec = self.dirstate._checkexec
176 checkexec = self.dirstate._checkexec
174
177
175 for lfile in tocheck:
178 for lfile in tocheck:
176 standin = lfutil.standin(lfile)
179 standin = lfutil.standin(lfile)
177 if standin in ctx1:
180 if standin in ctx1:
178 abslfile = self.wjoin(lfile)
181 abslfile = self.wjoin(lfile)
179 if ((ctx1[standin].data().strip() !=
182 if ((ctx1[standin].data().strip() !=
180 lfutil.hashfile(abslfile)) or
183 lfutil.hashfile(abslfile)) or
181 (checkexec and
184 (checkexec and
182 ('x' in ctx1.flags(standin)) !=
185 ('x' in ctx1.flags(standin)) !=
183 bool(lfutil.getexecutable(abslfile)))):
186 bool(lfutil.getexecutable(abslfile)))):
184 modified.append(lfile)
187 modified.append(lfile)
185 elif listclean:
188 elif listclean:
186 clean.append(lfile)
189 clean.append(lfile)
187 else:
190 else:
188 added.append(lfile)
191 added.append(lfile)
189
192
190 # at this point, 'removed' contains largefiles
193 # at this point, 'removed' contains largefiles
191 # marked as 'R' in the working context.
194 # marked as 'R' in the working context.
192 # then, largefiles not managed also in the target
195 # then, largefiles not managed also in the target
193 # context should be excluded from 'removed'.
196 # context should be excluded from 'removed'.
194 removed = [lfile for lfile in removed
197 removed = [lfile for lfile in removed
195 if lfutil.standin(lfile) in ctx1]
198 if lfutil.standin(lfile) in ctx1]
196
199
197 # Standins no longer found in lfdirstate has been
200 # Standins no longer found in lfdirstate has been
198 # removed
201 # removed
199 for standin in ctx1.walk(lfutil.getstandinmatcher(self)):
202 for standin in ctx1.walk(lfutil.getstandinmatcher(self)):
200 lfile = lfutil.splitstandin(standin)
203 lfile = lfutil.splitstandin(standin)
201 if not match(lfile):
204 if not match(lfile):
202 continue
205 continue
203 if lfile not in lfdirstate:
206 if lfile not in lfdirstate:
204 removed.append(lfile)
207 removed.append(lfile)
205
208
206 # Filter result lists
209 # Filter result lists
207 result = list(result)
210 result = list(result)
208
211
209 # Largefiles are not really removed when they're
212 # Largefiles are not really removed when they're
210 # still in the normal dirstate. Likewise, normal
213 # still in the normal dirstate. Likewise, normal
211 # files are not really removed if they are still in
214 # files are not really removed if they are still in
212 # lfdirstate. This happens in merges where files
215 # lfdirstate. This happens in merges where files
213 # change type.
216 # change type.
214 removed = [f for f in removed
217 removed = [f for f in removed
215 if f not in self.dirstate]
218 if f not in self.dirstate]
216 result[2] = [f for f in result[2]
219 result[2] = [f for f in result[2]
217 if f not in lfdirstate]
220 if f not in lfdirstate]
218
221
219 lfiles = set(lfdirstate._map)
222 lfiles = set(lfdirstate._map)
220 # Unknown files
223 # Unknown files
221 result[4] = set(result[4]).difference(lfiles)
224 result[4] = set(result[4]).difference(lfiles)
222 # Ignored files
225 # Ignored files
223 result[5] = set(result[5]).difference(lfiles)
226 result[5] = set(result[5]).difference(lfiles)
224 # combine normal files and largefiles
227 # combine normal files and largefiles
225 normals = [[fn for fn in filelist
228 normals = [[fn for fn in filelist
226 if not lfutil.isstandin(fn)]
229 if not lfutil.isstandin(fn)]
227 for filelist in result]
230 for filelist in result]
228 lfstatus = (modified, added, removed, s.deleted, [], [],
231 lfstatus = (modified, added, removed, s.deleted, [], [],
229 clean)
232 clean)
230 result = [sorted(list1 + list2)
233 result = [sorted(list1 + list2)
231 for (list1, list2) in zip(normals, lfstatus)]
234 for (list1, list2) in zip(normals, lfstatus)]
232 else: # not against working directory
235 else: # not against working directory
233 result = [[lfutil.splitstandin(f) or f for f in items]
236 result = [[lfutil.splitstandin(f) or f for f in items]
234 for items in result]
237 for items in result]
235
238
236 if wlock:
239 if wlock:
237 lfdirstate.write()
240 lfdirstate.write()
238
241
239 finally:
242 finally:
240 if wlock:
243 if wlock:
241 wlock.release()
244 wlock.release()
242
245
243 self.lfstatus = True
246 self.lfstatus = True
244 return scmutil.status(*result)
247 return scmutil.status(*result)
245
248
246 def commitctx(self, ctx, *args, **kwargs):
249 def commitctx(self, ctx, *args, **kwargs):
247 node = super(lfilesrepo, self).commitctx(ctx, *args, **kwargs)
250 node = super(lfilesrepo, self).commitctx(ctx, *args, **kwargs)
248 class lfilesctx(ctx.__class__):
251 class lfilesctx(ctx.__class__):
249 def markcommitted(self, node):
252 def markcommitted(self, node):
250 orig = super(lfilesctx, self).markcommitted
253 orig = super(lfilesctx, self).markcommitted
251 return lfutil.markcommitted(orig, self, node)
254 return lfutil.markcommitted(orig, self, node)
252 ctx.__class__ = lfilesctx
255 ctx.__class__ = lfilesctx
253 return node
256 return node
254
257
255 # Before commit, largefile standins have not had their
258 # Before commit, largefile standins have not had their
256 # contents updated to reflect the hash of their largefile.
259 # contents updated to reflect the hash of their largefile.
257 # Do that here.
260 # Do that here.
258 def commit(self, text="", user=None, date=None, match=None,
261 def commit(self, text="", user=None, date=None, match=None,
259 force=False, editor=False, extra={}):
262 force=False, editor=False, extra={}):
260 orig = super(lfilesrepo, self).commit
263 orig = super(lfilesrepo, self).commit
261
264
262 wlock = self.wlock()
265 wlock = self.wlock()
263 try:
266 try:
264 lfcommithook = self._lfcommithooks[-1]
267 lfcommithook = self._lfcommithooks[-1]
265 match = lfcommithook(self, match)
268 match = lfcommithook(self, match)
266 result = orig(text=text, user=user, date=date, match=match,
269 result = orig(text=text, user=user, date=date, match=match,
267 force=force, editor=editor, extra=extra)
270 force=force, editor=editor, extra=extra)
268 return result
271 return result
269 finally:
272 finally:
270 wlock.release()
273 wlock.release()
271
274
272 def push(self, remote, force=False, revs=None, newbranch=False):
275 def push(self, remote, force=False, revs=None, newbranch=False):
273 if remote.local():
276 if remote.local():
274 missing = set(self.requirements) - remote.local().supported
277 missing = set(self.requirements) - remote.local().supported
275 if missing:
278 if missing:
276 msg = _("required features are not"
279 msg = _("required features are not"
277 " supported in the destination:"
280 " supported in the destination:"
278 " %s") % (', '.join(sorted(missing)))
281 " %s") % (', '.join(sorted(missing)))
279 raise util.Abort(msg)
282 raise util.Abort(msg)
280 return super(lfilesrepo, self).push(remote, force=force, revs=revs,
283 return super(lfilesrepo, self).push(remote, force=force, revs=revs,
281 newbranch=newbranch)
284 newbranch=newbranch)
282
285
283 # TODO: _subdirlfs should be moved into "lfutil.py", because
286 # TODO: _subdirlfs should be moved into "lfutil.py", because
284 # it is referred only from "lfutil.updatestandinsbymatch"
287 # it is referred only from "lfutil.updatestandinsbymatch"
285 def _subdirlfs(self, files, lfiles):
288 def _subdirlfs(self, files, lfiles):
286 '''
289 '''
287 Adjust matched file list
290 Adjust matched file list
288 If we pass a directory to commit whose only committable files
291 If we pass a directory to commit whose only committable files
289 are largefiles, the core commit code aborts before finding
292 are largefiles, the core commit code aborts before finding
290 the largefiles.
293 the largefiles.
291 So we do the following:
294 So we do the following:
292 For directories that only have largefiles as matches,
295 For directories that only have largefiles as matches,
293 we explicitly add the largefiles to the match list and remove
296 we explicitly add the largefiles to the match list and remove
294 the directory.
297 the directory.
295 In other cases, we leave the match list unmodified.
298 In other cases, we leave the match list unmodified.
296 '''
299 '''
297 actualfiles = []
300 actualfiles = []
298 dirs = []
301 dirs = []
299 regulars = []
302 regulars = []
300
303
301 for f in files:
304 for f in files:
302 if lfutil.isstandin(f + '/'):
305 if lfutil.isstandin(f + '/'):
303 raise util.Abort(
306 raise util.Abort(
304 _('file "%s" is a largefile standin') % f,
307 _('file "%s" is a largefile standin') % f,
305 hint=('commit the largefile itself instead'))
308 hint=('commit the largefile itself instead'))
306 # Scan directories
309 # Scan directories
307 if os.path.isdir(self.wjoin(f)):
310 if os.path.isdir(self.wjoin(f)):
308 dirs.append(f)
311 dirs.append(f)
309 else:
312 else:
310 regulars.append(f)
313 regulars.append(f)
311
314
312 for f in dirs:
315 for f in dirs:
313 matcheddir = False
316 matcheddir = False
314 d = self.dirstate.normalize(f) + '/'
317 d = self.dirstate.normalize(f) + '/'
315 # Check for matched normal files
318 # Check for matched normal files
316 for mf in regulars:
319 for mf in regulars:
317 if self.dirstate.normalize(mf).startswith(d):
320 if self.dirstate.normalize(mf).startswith(d):
318 actualfiles.append(f)
321 actualfiles.append(f)
319 matcheddir = True
322 matcheddir = True
320 break
323 break
321 if not matcheddir:
324 if not matcheddir:
322 # If no normal match, manually append
325 # If no normal match, manually append
323 # any matching largefiles
326 # any matching largefiles
324 for lf in lfiles:
327 for lf in lfiles:
325 if self.dirstate.normalize(lf).startswith(d):
328 if self.dirstate.normalize(lf).startswith(d):
326 actualfiles.append(lf)
329 actualfiles.append(lf)
327 if not matcheddir:
330 if not matcheddir:
328 # There may still be normal files in the dir, so
331 # There may still be normal files in the dir, so
329 # make sure _a_ directory is in the list, which
332 # make sure _a_ directory is in the list, which
330 # forces status/dirstate to walk all files and
333 # forces status/dirstate to walk all files and
331 # call the match function on the matcher, even
334 # call the match function on the matcher, even
332 # on case sensitive filesytems.
335 # on case sensitive filesytems.
333 actualfiles.append('.')
336 actualfiles.append('.')
334 matcheddir = True
337 matcheddir = True
335 # Nothing in dir, so readd it
338 # Nothing in dir, so readd it
336 # and let commit reject it
339 # and let commit reject it
337 if not matcheddir:
340 if not matcheddir:
338 actualfiles.append(f)
341 actualfiles.append(f)
339
342
340 # Always add normal files
343 # Always add normal files
341 actualfiles += regulars
344 actualfiles += regulars
342 return actualfiles
345 return actualfiles
343
346
344 repo.__class__ = lfilesrepo
347 repo.__class__ = lfilesrepo
345
348
346 # stack of hooks being executed before committing.
349 # stack of hooks being executed before committing.
347 # only last element ("_lfcommithooks[-1]") is used for each committing.
350 # only last element ("_lfcommithooks[-1]") is used for each committing.
348 repo._lfcommithooks = [lfutil.updatestandinsbymatch]
351 repo._lfcommithooks = [lfutil.updatestandinsbymatch]
349
352
350 # Stack of status writer functions taking "*msg, **opts" arguments
353 # Stack of status writer functions taking "*msg, **opts" arguments
351 # like "ui.status()". Only last element ("_lfstatuswriters[-1]")
354 # like "ui.status()". Only last element ("_lfstatuswriters[-1]")
352 # is used to write status out.
355 # is used to write status out.
353 repo._lfstatuswriters = [ui.status]
356 repo._lfstatuswriters = [ui.status]
354
357
355 def prepushoutgoinghook(local, remote, outgoing):
358 def prepushoutgoinghook(local, remote, outgoing):
356 if outgoing.missing:
359 if outgoing.missing:
357 toupload = set()
360 toupload = set()
358 addfunc = lambda fn, lfhash: toupload.add(lfhash)
361 addfunc = lambda fn, lfhash: toupload.add(lfhash)
359 lfutil.getlfilestoupload(local, outgoing.missing, addfunc)
362 lfutil.getlfilestoupload(local, outgoing.missing, addfunc)
360 lfcommands.uploadlfiles(ui, local, remote, toupload)
363 lfcommands.uploadlfiles(ui, local, remote, toupload)
361 repo.prepushoutgoinghooks.add("largefiles", prepushoutgoinghook)
364 repo.prepushoutgoinghooks.add("largefiles", prepushoutgoinghook)
362
365
363 def checkrequireslfiles(ui, repo, **kwargs):
366 def checkrequireslfiles(ui, repo, **kwargs):
364 if 'largefiles' not in repo.requirements and util.any(
367 if 'largefiles' not in repo.requirements and util.any(
365 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
368 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
366 repo.requirements.add('largefiles')
369 repo.requirements.add('largefiles')
367 repo._writerequirements()
370 repo._writerequirements()
368
371
369 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles,
372 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles,
370 'largefiles')
373 'largefiles')
371 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles, 'largefiles')
374 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles, 'largefiles')
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now