././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1757584919.4634936 mercurial-7.1.1/0000775000175000017500000000000015060517027013362 5ustar00alpharealphare././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/.arcconfig0000664000175000017500000000031615060516737015325 0ustar00alpharealphare{ "conduit_uri": "https://phab.mercurial-scm.org/api", "phabricator.uri": "https://phab.mercurial-scm.org/", "repository.callsign": "HG", "arc.land.onto.default": "@", "base": "hg:.^" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/.clang-format0000664000175000017500000000052715060516737015750 0ustar00alpharealphareBasedOnStyle: LLVM IndentWidth: 8 UseTab: ForIndentation BreakBeforeBraces: Linux AllowShortIfStatementsOnASingleLine: false IndentCaseLabels: false AllowShortBlocksOnASingleLine: false AllowShortFunctionsOnASingleLine: false IncludeCategories: - Regex: '^<' Priority: 1 - Regex: '^"' Priority: 2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/.editorconfig0000664000175000017500000000053415060516737016050 0ustar00alpharealphare# See http://EditorConfig.org for the specification root = true [*.py] indent_size = 4 indent_style = space trim_trailing_whitespace = true end_of_line = lf [*.{c,h}] indent_size = 8 indent_style = tab trim_trailing_whitespace = true end_of_line = lf [*.t] indent_size = 2 indent_style = space trim_trailing_whitespace = false end_of_line = lf ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/.flake80000664000175000017500000000003615060516737014543 0ustar00alpharealphare[flake8] max-line-length = 80 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/.gitattributes0000664000175000017500000000011415060516737016260 0ustar00alpharealphare# So GitLab doesn't think we're using tons of Perl *.t -linguist-detectable ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1757584919.2947147 mercurial-7.1.1/.gitlab/0000775000175000017500000000000015060517027014702 5ustar00alpharealphare././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1757584919.3006215 mercurial-7.1.1/.gitlab/merge_request_templates/0000775000175000017500000000000015060517027021627 5ustar00alpharealphare././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/.gitlab/merge_request_templates/Default.md0000664000175000017500000000104615060516737023545 0ustar00alpharealphare/assign_reviewer @mercurial.review ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/.hgignore0000664000175000017500000000221715060516737015176 0ustar00alpharealpharesyntax: glob *.elc *.tmp *.orig *.rej *~ *.mergebackup *.o *.so *.dll *.exe *.pyd *.pyc *.pyo *$py.class *.swp *.prof *.zip \#*\# .\#* .venv* result/ tests/artifacts/cache/big-file-churn.hg tests/.coverage* tests/.testtimes* # the file is written in the CWD when run-tests is run. .testtimes tests/.hypothesis tests/hypothesis-generated tests/annotated tests/exceptions tests/python3 tests/*.err tests/htmlcov build contrib/chg/chg contrib/hgsh/hgsh contrib/vagrant/.vagrant contrib/merge-lists/target/ dist packages doc/common.txt doc/commandlist.txt doc/extensionlist.txt doc/topiclist.txt doc/*.mk doc/*.[0-9] doc/*.[0-9].txt doc/*.[0-9].gendoc.txt doc/*.[0-9].{x,ht}ml doc/build doc/html doc/man patches mercurial/__modulepolicy__.py mercurial/__version__.py mercurial/hgpythonlib.h mercurial.egg-info .DS_Store tags cscope.* .vscode/* .idea/* .asv/* .pytype/* .mypy_cache i18n/hg.pot locale/*/LC_MESSAGES/hg.mo hgext/__index__.py rust/target/ rust/*/target/ # Generated wheels wheelhouse/ syntax: rootglob # See Profiling in rust/README.md .cargo/config syntax: regexp ^\.pc/ ^\.(pydev)?project # hackable windows distribution additions ^hg-python ^hg.py$ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584869.0 mercurial-7.1.1/.hgsigs0000664000175000017500000050714015060516745014664 0ustar00alpharealphare35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A= 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk= 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys= 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4= fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I= 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU= bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0= d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE= d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc= 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A= 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4= 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo= 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw= 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug= e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8= a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok= 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg= 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4= aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0= b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is= 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI= 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU= de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4= 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik= d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM= 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg= 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI= 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4= 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo= 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0= db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y= 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q= 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q= b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc= d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono= 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg= 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0= 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w= b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA= 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM= 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc= b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k= d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38= 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0= 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM= a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0= f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg= a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA= 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM= 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg= 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I= 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU= 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM= 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI= ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI= cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk= 009794acc6e37a650f0fae37872e733382ac1c0c 0 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584869.0 mercurial-7.1.1/.hgtags0000664000175000017500000003336115060516745014654 0ustar00alpharealphared40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7 3a56574f329a368d645853e0f9e09472aee62349 0.8 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5 bae2e9c838e90a393bae3973a7850280413e091a 1.0 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1 3773e510d433969e277b1863c317b674cbee2065 1.1.1 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4 2b2155623ee2559caf288fd333f30475966c4525 1.7.5 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1 d629f1e89021103f1753addcef6b310e4435b184 1.9.2 351a9292e430e35766c552066ed3e87c557b803b 1.9.3 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc 41453d55b481ddfcc1dacb445179649e24ca861d 2.0 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1 6344043924497cd06d781d9014c66802285072e4 2.0.2 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7 335a558f81dc73afeab4d7be63617392b130117f 2.7.1 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc d825e4025e39d1c39db943cdc89818abd0a87c27 2.8 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc 2195ac506c6ababe86985b932f4948837c0891b5 3.0 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc 3178e49892020336491cdc6945885c4de26ffa8b 3.1 5dc91146f35369949ea56b40172308158b59063a 3.1.1 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc ced632394371a36953ce4d394f86278ae51a2aae 3.2 643c58303fb0ec020907af28b9e486be299ba043 3.2.1 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc fbdd5195528fae4f41feebc1838215c110b25d6a 3.3 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2 ea389970c08449440587712117f178d33bab3f1e 3.6.3 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc f85de28eae32e7d3064b1a1321309071bbaaa069 3.8 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc eab27446995210c334c3d06f1a659e3b9b5da769 4.0 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc bb96d4a497432722623ae60d9bc734a1e360179e 4.2 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc 5544af8622863796a0027566f6b646e10d522c4c 4.3 943c91326b23954e6e1c6960d0239511f9530258 4.2.3 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc d334afc585e29577f271c5eda03378736a16ca6b 4.5 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1 8bba684efde7f45add05f737952093bb2aa07155 4.5.2 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4 065704cbdbdbb05dcd6bb814eb9bbdd982211b28 5.4.1 0ea9c86fac8974cd74dc12ea681c8986eb6da6c4 5.4.2 28163c5de797e5416f9b588940f4608269b4d50a 5.5rc0 7fc3c5fbc65f6fe85d70ea63923b8767dda4f2e0 5.5 f62bb5d07848ca598aa860a517394130b61bf2ee 5.5.1 07731064ac41dacdf0ec869ebd05c2e848c14fbf 5.5.2 0e06a7ab9e0d5c65af4e511aee1e0342998799df 5.6rc0 18c17d63fdabd009e70bf994e5efb7db422f4f7f 5.6 1d5189a57405ceca5aa244052c9f948977f4699b 5.6.1 9da65e3cf3706ff41e08b311381c588440c27baf 5.7rc0 0e2e7300f4302b02412b0b734717697049494c4c 5.7 d5d9177c0045d206db575bae6daa98e2cb2fe5bc 5.7.1 f67b8946bb1b6cfa8328dbf8d6a9128b69ccdcb4 5.8rc0 8d2b62d716b095507effaa8d56f87cd27ba659ab 5.8rc1 067f2c53fb24506c9e9fb4639871b13b19a85f8a 5.8 411dc27fd9fd076d6a031a08fcaace659afe2fe3 5.8.1 d7515d29761d5ada7d9c765f517db67db75dea9a 5.9rc0 2813d406b03607cdb8c06cb04c44efcc9a79d9a2 5.9rc1 53221078e0de65d1a821ce5311dec45a7a978301 5.9 86a60679cf619e14cee9442f865fcf31b142cb9f 5.9.1 750920b18aaaddd654756be40dec59d90f2643be 5.9.2 6ee0244fc1cf889ae543d2ce0ec45201ae0be6e1 5.9.3 a44bb185f6bdbecc754996d8386722e2f0123b0a 6.0rc0 5d08b289e2e526259d7d5ea32b70fe76d5b327d7 6.0 799fdf4cca80cb9ae40537a90995e6bd163ebc0b 6.0.1 75676122c2bf7594ac732b7388db4c74c648b365 6.0.2 dcec16e799ddb6d33fcd11b04af530250a417a58 6.0.3 c00d3ce4e94bb0ee8d809e25e1dcb2a5fab84e2c 6.1rc0 d4486810a1795fba9521449b8885ced034f3a6dd 6.1 5bd6bcd31dd1ebb63b8914b00064f96297267af7 6.1.1 0ddd5e1f5f67438af85d12e4ce6c39021dde9916 6.1.2 6b10151b962108f65bfa12b3918b1021ca334f73 6.1.3 0cc5f74ff7f0f4ac2427096bddbe102dbc2453ae 6.1.4 288de6f5d724bba7bf1669e2838f196962bb7528 6.2rc0 094a5fa3cf52f936e0de3f1e507c818bee5ece6b 6.2 f69bffd00abe3a1b94d1032eb2c92e611d16a192 6.2.1 b5c8524827d20fe2e0ca8fb1234a0fe35a1a36c7 6.2.2 dbdee8ac3e3fcdda1fa55b90c0a235125b7f8e6f 6.2.3 a3356ab610fc50000cf0ba55c424a4d96da11db7 6.3rc0 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0 0000000000000000000000000000000000000000 6.3.0 c890d8b8bc59b18e5febf60caada629df5356ee2 6.3.1 59466b13a3ae0e29a5d4f485393e516cfbb057d0 6.3.2 8830004967ad865ead89c28a410405a6e71e0796 6.3.3 05de4896508e8ec387b33eb30d8aab78d1c8e9e4 6.4rc0 f14864fffdcab725d9eac6d4f4c07be05a35f59a 6.4 83ea6ce48b4fd09fb79c4e34cc5750c805699a53 6.4.1 f952be90b0514a576dcc8bbe758ce3847faba9bb 6.4.2 fc445f8abcf90b33db7c463816a1b3560681767f 6.4.3 da372c745e0f053bb7a64e74cccd15810d96341d 6.4.4 271a4ab29605ffa0bae5d3208eaa21a95427ff92 6.4.5 bb42988c7e156931b0ff1e93732b98173ebbcb7f 6.5rc0 3ffc7209bbae5804a53084c9dc2d41139e88c867 6.5 787af4e0e8b787e1b77a8059926b123730a4cd01 6.5.1 5a8b5420103937fca97c584c5162178eed828ada 6.5.2 c083d9776cb2fb6056715b2988d1ea48055f3162 6.5.3 27055614b68538576fb0439007009acf93fe0a49 6.6rc0 26c57e7a0890b96e2c473b394de380d6753c9230 6.6 71bd09bebbe36a09569cbfb388f371433360056b 6.6.1 136902b3a95db38854ebaf5198a627641065c2ea 6.6.2 3fd1efb3ad124e6686c0fb66e6943cd8aeea5681 6.6.3 d1d48d18db37106b801ef6cb90955536458e7ffc 6.7rc0 c9ceb4f6025690167bdb245e530de6bac8baae95 6.7 2e6fde2ed01e63f0de6a5966994fbb60b1f87057 6.7.1 803e61387e86f103483120df35619bdb175e3482 6.7.2 028dc3f92dbd0f93bb78f9848c94ba5eecd72e71 6.7.3 a1a011d4b148955975cb40d619d285fdd4ee8713 6.7.4 6454c117c6a4003f07d8f4281dd90038955123e4 6.8rc0 11f41248595b6dd7e0fbb434ecbf75c418785a4c 6.8 11a9e2fc0caf0800625612e374139e4d825349a6 6.8.1 eae3ec345e5e62e653de32a87a70f6fa7241afde 6.8.2 dc97e8670decc9925c2f570bdca636778184b199 6.9rc0 31d45a1cbc479ac73fc8b355abe99e090eb6c747 6.9rc1 b267c5764cc6b804c619a42067405f27e8705beb 6.9 9751b9ccd74d8386687f88fbdfe280877840ec7d 6.9.1 b964f92261d4fbb64f19aa6af2b072f7730b913a 6.9.2 89ab2459f62ac8da3eb4f3ee2120d1814ce805d5 6.9.3 4654407c6df8510f8c84741c61b905d71f6adc8f 6.9.4 3d34a380ea3aecef2db1a468d487f675ae0b45f5 6.9.5 ed68f9a47a090cc6450a7d5617baf123ba5fc42a 7.0rc0 cb2b2242428df5be87693b8acaac71deafcff2c5 7.0rc1 9b285d51e4b6fb01eb9de357092b993311bd1152 7.0 010a86744bfc6ede2e3ed3ecef3faee0de804f47 7.0.1 a498a90c2455a9da9b71cf208274572152b9826e 7.0.2 a9b453aa7524ef3af2245e12e8008d0d730e8fbb 7.0.3 eefe5b2748c259a881e914c9cd306cba8516d2b7 7.1rc0 0136cabb3bb6ab39defb47e4c368a0207c35cc71 7.1rc1 fb9a0c2a0d1bc0aab0a6c840db6e7721bdf35315 7.1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/.jshintrc0000664000175000017500000000114615060516737015220 0ustar00alpharealphare{ // Enforcing "eqeqeq" : true, // true: Require triple equals (===) for comparison "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc. "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters. "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) // Environments "browser" : true // Web Browser (window, document, etc) } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/CONTRIBUTING.md0000664000175000017500000000320515060516737015622 0ustar00alpharealphare# Mercurial's Contributing guidelines Our full contribution guidelines are in our wiki, please see: If you just want a checklist to follow, you can go straight to If you can't run the entire testsuite for some reason (it can be difficult on Windows), please at least run `contrib/check-code.py` on any files you've modified and run `python contrib/check-commit` on any commits you've made (for example, `python contrib/check-commit 273ce12ad8f1` will report some style violations on a very old commit). ## Development dependencies ### Required dependencies - Python (see `project.requires-python` in `pyproject.toml`) with `venv` and `pip` - `make` with few other standard Unix tools (`diff`, `grep`, `unzip`, `gunzip`, `bunzip2` and `sed`) For Windows, see `contrib/install-windows-dependencies.ps1`. ### Optional dependencies - Mercurial contributors should install a quite recent Mercurial with the extensions `evolve` and `topic` activated. - A C compiler and Python headers (typically Debian package `python3-dev` or Microsoft Build Tools for Visual Studio on Windows) - `msgfmt` from the Debian package `gettext` (used to build the translations) - [Rust tools](https://www.rust-lang.org/tools/install) (see `rust/README.md`) #### Note on installation Mercurial is a Python application that can be installed with [pipx](https://pipx.pypa.io) and `uv tool`. UV is a Rust application that can also be installed with pipx or with [its own installer](https://docs.astral.sh/uv/getting-started/installation/). ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/CONTRIBUTORS0000664000175000017500000000317715060516737015261 0ustar00alpharealphare[This file is here for historical purposes, all recent contributors should appear in the changelog directly] Andrea Arcangeli Thomas Arendsen Hein Goffredo Baroncelli Muli Ben-Yehuda Mikael Berthe Benoit Boissinot Brendan Cully Vincent Danjean Jake Edge Michael Fetterman Edouard Gomez Eric Hopper Alecs King Volker Kleinfeld Vadim Lebedev Christopher Li Chris Mason Colin McMillen Wojciech Milkowski Chad Netzer Bryan O'Sullivan Vicent Seguí Pascual Sean Perry Nguyen Anh Quynh Ollivier Robert Alexander Schremmer Arun Sharma Josef "Jeff" Sipek Kevin Smith TK Soh Radoslaw Szkodzinski Samuel Tardieu K Thananchayan Andrew Thompson Michael S. Tsirkin Rafael Villar Burke Tristan Wibberley Mark Williamson ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/COPYING0000664000175000017500000004325415060516737014434 0ustar00alpharealphare GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/MANIFEST.in0000664000175000017500000000020015060516737015117 0ustar00alpharealphareinclude mercurial/__version__.py include doc/*.html include doc/*.1 doc/*.5 doc/*.8 include doc/html/*.html include doc/man/*.1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/Makefile0000664000175000017500000002355215060516737015040 0ustar00alpharealphare# If you want to change PREFIX, do not just edit it below. The changed # value wont get passed on to recursive make calls. You should instead # override the variable on the command like: # # % make PREFIX=/opt/ install export PREFIX=/usr/local # Default to Python 3. # # Windows ships Python 3 as `python.exe`, which may not be on PATH. py.exe is. ifeq ($(OS),Windows_NT) PYTHON?=py -3 else PYTHON?=python3 endif PYOXIDIZER?=pyoxidizer $(eval HGROOT := $(shell pwd)) HGPYTHONS ?= $(HGROOT)/build/pythons PURE= PIP_OPTIONS_PURE=--config-settings --global-option="$(PURE)" PIP_OPTIONS_INSTALL=--no-deps --ignore-installed --no-build-isolation PIP_PREFIX=$(PREFIX) PYFILESCMD=find mercurial hgext doc -name '*.py' PYFILES:=$(shell $(PYFILESCMD)) DOCFILES=mercurial/helptext/*.txt export LANGUAGE=C export LC_ALL=C TESTFLAGS ?= $(shell echo $$HGTESTFLAGS) CARGO = cargo VENV_NAME=$(shell $(PYTHON) -c "import sys; v = sys.version_info; print(f'.venv_{sys.implementation.name}{v.major}.{v.minor}')") PYBINDIRNAME=$(shell $(PYTHON) -c "import os; print('Scripts' if os.name == 'nt' else 'bin')") .PHONY: help help: @echo 'Commonly used make targets:' @echo ' install - install program and man pages to $$PREFIX ($(PREFIX))' @echo ' install-home - install with pip install --user' @echo ' local - build for inplace usage' @echo ' tests - run all tests in the automatic test suite' @echo ' test-foo - run only specified tests (e.g. test-merge1.t)' @echo ' dist - run all tests and create a source tarball in dist/' @echo ' clean - remove files created by other targets' @echo ' (except installed files or dist source tarball)' @echo ' update-pot - update i18n/hg.pot' @echo @echo 'See CONTRIBUTING.md for the build and development dependencies.' @echo @echo 'Example for a system-wide installation under /usr/local for' @echo 'downstream packaging (build and runtime deps have to be installed by hand)' @echo ' su -c "make install" && hg version' @echo @echo 'Example for a system-wide installation under /usr/local:' @echo ' make doc' @echo ' su -c "make install PIP_OPTIONS_INSTALL=" && hg version' @echo @echo 'On some Linux distributions, you might need to specify both' @echo 'PREFIX and PIP_PREFIX (here to install everything in /data/local)' @echo ' make install PREFIX=/data/local PIP_PREFIX=/data PIP_OPTIONS_INSTALL=' @echo @echo 'Example for a local installation (usable in this directory):' @echo ' make local && ./hg version' .PHONY: local local: $(PYTHON) -m venv $(VENV_NAME) --clear --upgrade-deps --system-site-packages $(VENV_NAME)/$(PYBINDIRNAME)/python -m \ pip install -e . -v $(PIP_OPTIONS_PURE) env HGRCPATH= $(VENV_NAME)/$(PYBINDIRNAME)/hg version .PHONY: build-chg build-chg: make -C contrib/chg .PHONY: build-rhg build-rhg: (cd rust/rhg; cargo build --release --features "$(HG_RUST_FEATURES)") .PHONY: wheel wheel: $(PYTHON) -m build --config-setting=--global-option="$(PURE)" .PHONY: doc doc: $(MAKE) -C doc .PHONY: cleanbutpackages cleanbutpackages: rm -f hg.exe rm -rf mercurial.egg-info find contrib doc hgext hgext3rd i18n mercurial tests hgdemandimport \ \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';' rm -rf .venv_* rm -f hgext/__index__.py tests/*.err rm -f mercurial/__modulepolicy__.py if test -d .hg; then rm -f mercurial/__version__.py; fi rm -rf build mercurial/locale $(MAKE) -C doc clean $(MAKE) -C contrib/chg distclean rm -rf rust/target .PHONY: clean clean: cleanbutpackages rm -rf packages .PHONY: install install: install-bin install-doc .PHONY: install-bin install-bin: $(PYTHON) -m pip install . --prefix="$(PIP_PREFIX)" --force -v $(PIP_OPTIONS_PURE) $(PIP_OPTIONS_INSTALL) .PHONY: install-chg install-chg: build-chg make -C contrib/chg install PREFIX="$(PREFIX)" .PHONY: install-doc install-doc: $(MAKE) -C doc $(MFLAGS) PREFIX="$(PREFIX)" install .PHONY: install-home install-home: install-home-bin install-home-doc .PHONY: install-home-bin install-home-bin: $(PYTHON) -m pip install . --user --force -v $(PIP_OPTIONS_PURE) $(PIP_OPTIONS_INSTALL) .PHONY: install-home-doc install-home-doc: $(MAKE) -C doc $(MFLAGS) PREFIX="$(HOME)" install .PHONY: install-rhg install-rhg: build-rhg install -m 755 rust/target/release/rhg "$(PREFIX)"/bin/ .PHONY: dist dist: tests dist-notests .PHONY: dist-notests dist-notests: doc TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) -m build --sdist .PHONY: check check: tests .PHONY: tests tests: # Run Rust tests if cargo is installed if command -v $(CARGO) >/dev/null 2>&1; then \ $(MAKE) rust-tests; \ $(MAKE) cargo-clippy; \ fi cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) .PHONY: test-% test-%: cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@ .PHONY: testpy-% testpy-%: @echo Looking for Python $* in $(HGPYTHONS) [ -e $(HGPYTHONS)/$*/bin/python ] || ( \ cd $$(mktemp --directory --tmpdir) && \ $(MAKE) -f $(HGROOT)/contrib/Makefile.python PYTHONVER=$* PREFIX=$(HGPYTHONS)/$* python ) cd tests && $(HGPYTHONS)/$*/bin/python run-tests.py $(TESTFLAGS) .PHONY: rust-tests rust-tests: cd $(HGROOT)/rust \ && $(CARGO) test --quiet --all \ --features "full-tracing" --no-default-features \ && $(CARGO) test --quiet --all --no-default-features .PHONY: cargo-clippy cargo-clippy: cd $(HGROOT)/rust \ && $(CARGO) clippy --all -- -D warnings \ && $(CARGO) clippy --all --features "full-tracing" -- -D warnings .PHONY: check-code check-code: hg manifest | xargs python contrib/check-code.py .PHONY: setup-format setup-format: .hg/dev-tools/fix-conf.rc # the format target exist as an entry point for new devs, but it is expected # that they run `hg fix` directly. .PHONY: format-wdir format-wdir: .hg/dev-tools/fix-conf.rc hg --config extensions.fix= fix --working-dir # requires topic to have a stack in the first place. .PHONY: format-stack format-stack: .hg/dev-tools/fix-conf.rc hg --config extensions.fix= fix --rev ".#stack" --rev "wdir()" .hg/dev-tools/fix-conf.rc: contrib/fix-conf.rc contrib/setup-dev-tool.sh ./contrib/setup-dev-tool.sh .PHONY: format-c format-c: clang-format --style file -i \ `hg files 'set:(**.c or **.cc or **.h) and not "listfile:contrib/clang-format-ignorelist"'` .PHONY: update-pot update-pot: i18n/hg.pot i18n/hg.pot: $(PYFILES) $(DOCFILES) i18n/posplit i18n/hggettext $(PYTHON) i18n/hggettext mercurial/commands.py \ hgext/*.py hgext/*/__init__.py \ mercurial/fileset.py mercurial/revset.py \ mercurial/templatefilters.py \ mercurial/templatefuncs.py \ mercurial/templatekw.py \ mercurial/filemerge.py \ mercurial/hgweb/webcommands.py \ mercurial/util.py \ $(DOCFILES) > i18n/hg.pot.tmp # All strings marked for translation in Mercurial contain # ASCII characters only. But some files contain string # literals like this '\037\213'. xgettext thinks it has to # parse them even though they are not marked for translation. # Extracting with an explicit encoding of ISO-8859-1 will make # xgettext "parse" and ignore them. $(PYFILESCMD) | xargs \ xgettext --package-name "Mercurial" \ --msgid-bugs-address "" \ --copyright-holder "Olivia Mackall and others" \ --from-code ISO-8859-1 --join --sort-by-file --add-comments=i18n: \ -d hg -p i18n -o hg.pot.tmp $(PYTHON) i18n/posplit i18n/hg.pot.tmp # The target file is not created before the last step. So it never is in # an intermediate state. mv -f i18n/hg.pot.tmp i18n/hg.pot %.po: i18n/hg.pot # work on a temporary copy for never having a half completed target cp $@ $@.tmp msgmerge --no-location --update $@.tmp $^ mv -f $@.tmp $@ # Packaging targets packaging_targets := \ rhel7 \ rhel8 \ rhel9 \ rhel10 \ deb \ docker-rhel7 \ docker-rhel8 \ docker-rhel9 \ docker-rhel10 \ docker-debian-bullseye \ docker-debian-buster \ docker-debian-stretch \ docker-fedora \ docker-ubuntu-xenial \ docker-ubuntu-xenial-ppa \ docker-ubuntu-bionic \ docker-ubuntu-bionic-ppa \ docker-ubuntu-focal \ docker-ubuntu-focal-ppa \ fedora \ linux-wheels \ linux-wheels-x86_64 \ linux-wheels-x86_64-musl \ linux-wheels-i686 \ linux-wheels-i686-musl \ ppa # Forward packaging targets for convenience. .PHONY: $(packaging_targets) $(packaging_targets): $(MAKE) -C contrib/packaging $(MAKEFLAGS) $@ .PHONY: pyoxidizer pyoxidizer: $(PYOXIDIZER) build --path ./rust/hgcli --release # a temporary target to setup all we need for run-tests.py --pyoxidizer # (should go away as the run-tests implementation improves .PHONY: pyoxidizer-windows-tests pyoxidizer-windows-tests: PYOX_DIR=build/pyoxidizer/x86_64-pc-windows-msvc/release/app pyoxidizer-windows-tests: pyoxidizer rm -rf $(PYOX_DIR)/templates cp -ar $(PYOX_DIR)/lib/mercurial/templates $(PYOX_DIR)/templates rm -rf $(PYOX_DIR)/helptext cp -ar $(PYOX_DIR)/lib/mercurial/helptext $(PYOX_DIR)/helptext rm -rf $(PYOX_DIR)/defaultrc cp -ar $(PYOX_DIR)/lib/mercurial/defaultrc $(PYOX_DIR)/defaultrc rm -rf $(PYOX_DIR)/contrib cp -ar contrib $(PYOX_DIR)/contrib rm -rf $(PYOX_DIR)/doc cp -ar doc $(PYOX_DIR)/doc # a temporary target to setup all we need for run-tests.py --pyoxidizer # (should go away as the run-tests implementation improves .PHONY: pyoxidizer-macos-tests pyoxidizer-macos-tests: PYOX_DIR=build/pyoxidizer/x86_64-apple-darwin/release/app pyoxidizer-macos-tests: pyoxidizer rm -rf $(PYOX_DIR)/templates cp -a mercurial/templates $(PYOX_DIR)/templates rm -rf $(PYOX_DIR)/helptext cp -a mercurial/helptext $(PYOX_DIR)/helptext rm -rf $(PYOX_DIR)/defaultrc cp -a mercurial/defaultrc $(PYOX_DIR)/defaultrc rm -rf $(PYOX_DIR)/contrib cp -a contrib $(PYOX_DIR)/contrib rm -rf $(PYOX_DIR)/doc cp -a doc $(PYOX_DIR)/doc .PHONY: pytype-docker pytype-docker: contrib/docker/pytype/recipe.sh .PHONY: pytype-graph-docker pytype-graph-docker: contrib/docker/pytype/recipe.sh --import-graph ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1757584919.4634788 mercurial-7.1.1/PKG-INFO0000644000175000017500000000412315060517027014455 0ustar00alpharealphareMetadata-Version: 2.4 Name: mercurial Version: 7.1.1 Summary: Fast scalable distributed SCM (revision control, version control) system Author-email: Olivia Mackall and many others License-Expression: GPL-2.0-or-later Project-URL: home, https://mercurial-scm.org/ Project-URL: download_url, https://mercurial-scm.org/release/ Classifier: Development Status :: 6 - Mature Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: Natural Language :: Danish Classifier: Natural Language :: English Classifier: Natural Language :: German Classifier: Natural Language :: Italian Classifier: Natural Language :: Japanese Classifier: Natural Language :: Portuguese (Brazilian) Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: OS Independent Classifier: Operating System :: POSIX Classifier: Programming Language :: C Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Version Control Requires-Python: >=3.9 Description-Content-Type: text/x-rst License-File: COPYING Dynamic: license-file Mercurial ========= Mercurial is a fast, easy to use, distributed revision control tool for software developers. Basic install:: $ make # see install targets $ make install # do a system-wide install $ hg debuginstall # sanity-check setup $ hg # see help Running without installing:: $ make local # build for inplace usage $ ./hg --version # should show the latest version See https://mercurial-scm.org/ for detailed installation instructions, platform-specific notes, and Mercurial user information. Notes for packagers =================== Mercurial ships a copy of the python-zstandard sources. This is used to provide support for zstd compression and decompression functionality. The module is not intended to be replaced by the plain python-zstandard nor is it intended to use a system zstd library. Patches can result in hard to diagnose errors and are explicitly discouraged as unsupported configuration. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/README.rst0000664000175000017500000000167615060516737015072 0ustar00alpharealphareMercurial ========= Mercurial is a fast, easy to use, distributed revision control tool for software developers. Basic install:: $ make # see install targets $ make install # do a system-wide install $ hg debuginstall # sanity-check setup $ hg # see help Running without installing:: $ make local # build for inplace usage $ ./hg --version # should show the latest version See https://mercurial-scm.org/ for detailed installation instructions, platform-specific notes, and Mercurial user information. Notes for packagers =================== Mercurial ships a copy of the python-zstandard sources. This is used to provide support for zstd compression and decompression functionality. The module is not intended to be replaced by the plain python-zstandard nor is it intended to use a system zstd library. Patches can result in hard to diagnose errors and are explicitly discouraged as unsupported configuration. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1757584919.3043082 mercurial-7.1.1/contrib/0000775000175000017500000000000015060517027015022 5ustar00alpharealphare././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/Makefile.python0000664000175000017500000000622315060516737020014 0ustar00alpharealpharePYTHONVER=2.7.16 PYTHONNAME=python- PREFIX=$(HOME)/bin/prefix-$(PYTHONNAME)$(PYTHONVER) SYMLINKDIR=$(HOME)/bin help: @echo @echo 'Make a custom installation of a Python version' @echo @echo 'Common make parameters:' @echo ' PYTHONVER=... [$(PYTHONVER)]' @echo ' PREFIX=... [$(PREFIX)]' @echo ' SYMLINKDIR=... [$(SYMLINKDIR) creating $(PYTHONNAME)$(PYTHONVER)]' @echo @echo 'Common make targets:' @echo ' python - install Python $$PYTHONVER in $$PREFIX' @echo ' symlink - create a $$SYMLINKDIR/$(PYTHONNAME)$$PYTHONVER symlink' @echo @echo 'Example: create a temporary Python installation:' @echo ' $$ make -f Makefile.python python PYTHONVER=${PYTHONVER} PREFIX=/tmp/p27' @echo ' $$ /tmp/p27/bin/python -V' @echo ' Python 2.7' @echo @echo 'Some external libraries are required for building Python: zlib bzip2 openssl.' @echo 'Make sure their development packages are installed systemwide.' # fedora: yum install zlib-devel bzip2-devel openssl-devel # debian: apt-get install zlib1g-dev libbz2-dev libssl-dev @echo @echo 'To build a nice collection of interesting Python versions:' @echo ' $$ for v in 2.{6{,.1,.2,.9},7{,.8,.10}}; do' @echo ' make -f Makefile.python symlink PYTHONVER=$$v || break; done' @echo 'To run a Mercurial test on all these Python versions:' @echo ' $$ for py in `cd ~/bin && ls $(PYTHONNAME)2.*`; do' @echo ' echo $$py; $$py run-tests.py test-http.t; echo; done' @echo export LANGUAGE=C export LC_ALL=C python: $(PREFIX)/bin/python docutils printf 'import sys, zlib, bz2, docutils, ssl' | $(PREFIX)/bin/python PYTHON_SRCDIR=Python-$(PYTHONVER) PYTHON_SRCFILE=$(PYTHON_SRCDIR).tgz $(PREFIX)/bin/python: [ -f $(PYTHON_SRCFILE) ] || wget http://www.python.org/ftp/python/$(PYTHONVER)/$(PYTHON_SRCFILE) || curl -OL http://www.python.org/ftp/python/$(PYTHONVER)/$(PYTHON_SRCFILE) || [ -f $(PYTHON_SRCFILE) ] rm -rf $(PYTHON_SRCDIR) tar xf $(PYTHON_SRCFILE) # Debian/Ubuntu disables SSLv2,3 the hard way, disable it on old Pythons too -sed -i 's,self.*SSLv[23]_method(),0;//\0,g' $(PYTHON_SRCDIR)/Modules/_ssl.c # Find multiarch system libraries on Ubuntu and disable fortify error when setting argv LDFLAGS="-L/usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH`"; \ BASECFLAGS=-U_FORTIFY_SOURCE; \ export LDFLAGS BASECFLAGS; \ cd $(PYTHON_SRCDIR) && ./configure --prefix=$(PREFIX) && make all SVNVERSION=pwd && make install printf 'import sys, zlib, bz2, ssl' | $(PREFIX)/bin/python rm -rf $(PYTHON_SRCDIR) DOCUTILSVER=0.12 DOCUTILS_SRCDIR=docutils-$(DOCUTILSVER) DOCUTILS_SRCFILE=$(DOCUTILS_SRCDIR).tar.gz docutils: $(PREFIX)/bin/python @$(PREFIX)/bin/python -c 'import docutils' || ( set -ex; \ [ -f $(DOCUTILS_SRCFILE) ] || wget http://downloads.sourceforge.net/project/docutils/docutils/$(DOCUTILSVER)/$(DOCUTILS_SRCFILE) || [ -f $(DOCUTILS_SRCFILE) ]; \ rm -rf $(DOCUTILS_SRCDIR); \ tar xf $(DOCUTILS_SRCFILE); \ cd $(DOCUTILS_SRCDIR) && $(PREFIX)/bin/python setup.py install --prefix=$(PREFIX); \ $(PREFIX)/bin/python -c 'import docutils'; \ rm -rf $(DOCUTILS_SRCDIR); ) symlink: python $(SYMLINKDIR) ln -sf $(PREFIX)/bin/python $(SYMLINKDIR)/$(PYTHONNAME)$(PYTHONVER) .PHONY: help python docutils symlink ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/adjust-pytype-cache.sh0000755000175000017500000000207515060516737021255 0ustar00alpharealphare#!/bin/bash set -e set -u set -o pipefail cd "$(hg root)" if [ ! -e .pytype ]; then echo "no cache available" >&2 exit 0 fi if [ ! -e .pytype/CACHE_COMMIT ]; then echo "no cache origin information" >&2 echo "purging the cache" >&2 rm -rf .pytype exit 0 fi SOURCE_COMMIT=`cat .pytype/CACHE_COMMIT` if ! hg log --rev "id($SOURCE_COMMIT)" -T 'HAS MATCH' | grep -q 'HAS MATCH' ; then echo "unknown cache source" >&2 echo "purging the cache" >&2 rm -rf .pytype exit 0 fi ### lets fiddle with time stamp ! # ninja use timestamp for its cache validation changed=`hg status --no-status --removed --added --modified --rev "id($SOURCE_COMMIT)" | wc -l` echo "reusing cache from $SOURCE_COMMIT ($changed file changes)" >&2 # first mark the cache content as newer than the repostiory content sleep 1 find .pytype -exec touch '{}' ';' # then update the timestamp of the file changed between the cache source and the changeset we test sleep 1 hg status --no-status --added --modified --rev "id($SOURCE_COMMIT)" | while read f; do touch "$f" done ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/all-revsets.txt0000664000175000017500000000777515060516737020053 0ustar00alpharealphare# All revsets ever used with revsetbenchmarks.py script # # The goal of this file is to gather all revsets ever used for benchmarking # revset's performance. It should be used to gather revsets that test a # specific usecase or a specific implementation of revset predicates. # If you are working on the smartset implementation itself, check # 'base-revsets.txt'. # # Please update this file with any revsets you use for benchmarking a change so # that future contributors can easily find and retest it when doing further # modification. Feel free to highlight interesting variants if needed. ## Revset from this section are all extracted from changelog when this file was # created. Feel free to dig and improve documentation. # Used in revision da05fe01170b (20000::) - (20000) # Used in revision 95af98616aa7 parents(20000) # Used in revision 186fd06283b4 (_intlist('20000\x0020001')) and merge() # Used in revision 911f5a6579d1 p1(20000) p2(10000) # Used in revision b6dc3b79bb25 0:: # Used in revision faf4f63533ff bookmark() # Used in revision 22ba2c0825da tip~25 # Used in revision 0cf46b8298fe bisect(range) # Used in revision 5b65429721d5 divergent() # Used in revision 6261b9c549a2 file(COPYING) # Used in revision 44f471102f3a follow(COPYING) # Used in revision 8040a44aab1c origin(tip) # Used in revision bbf4f3dfd700 rev(25) # Used in revision a428db9ab61d p1() # Used in revision c1546d7400ef min(0::) # Used in revision 546fa6576815 author(lmoscovicz) or author("pierre-yves") author("pierre-yves") or author(lmoscovicz) # Used in revision 9bfe68357c01 public() and id("d82e2223f132") # Used in revision ba89f7b542c9 rev(25) # Used in revision eb763217152a rev(210000) # Used in revision 69524a05a7fa 10:100 parents(10):parents(100) # Used in revision 6f1b8b3f12fd 100~5 parents(100)~5 (100~5)~5 # Used in revision 7a42e5d4c418 children(tip~100) # Used in revision 7e8737e6ab08 100^1 parents(100)^1 (100^1)^1 # Used in revision 30e0dcd7c5ff matching(100) matching(parents(100)) # Used in revision aafeaba22826 0|1|2|3|4|5|6|7|8|9 # Used in revision 33c7a94d4dd0 tip:0 # Used in revision 7d369fae098e (0:100000) # Used in revision b333ca94403d 0 + 1 + 2 + ... + 200 0 + 1 + 2 + ... + 1000 sort(0 + 1 + 2 + ... + 200) sort(0 + 1 + 2 + ... + 1000) # Used in revision 7fbef7932af9 first(0 + 1 + 2 + ... + 1000) # Used in revision ceaf04bb14ff 0:1000 # Used in revision 262e6ad93885 not public() (tip~1000::) - public() not public() and branch("default") # Used in revision 15412bba5a68 0::tip ## all the revsets from this section have been taken from the former central file # for revset's benchmarking, they are undocumented for this reason. all() draft() ::tip draft() and ::tip ::tip and draft() author(lmoscovicz) author("pierre-yves") ::p1(p1(tip)):: public() :10000 and public() :10000 and draft() (not public() - obsolete()) # The one below is used by rebase (children(ancestor(tip~5, tip)) and ::(tip~5)):: # those two `roots(...)` inputs are close to what phase movement use. roots((tip~100::) - (tip~100::tip)) roots((0::) - (0::tip)) # more roots testing roots(tip~100:) roots(:42) roots(not public()) roots((0:tip)::) roots(0::tip) 42:68 and roots(42:tip) # Used in revision f140d6207cca roots(0:tip) # test disjoint set with multiple roots roots((:42) + (tip~42:)) # Testing the behavior of "head()" in various situations head() head() - public() draft() and head() head() and author("pierre-yves") # testing the mutable phases set draft() secret() # test finding common ancestors heads(commonancestors(last(head(), 2))) heads(commonancestors(head())) # more heads testing heads(all()) heads(-10000:-1) (-5000:-1000) and heads(-10000:-1) heads(matching(tip, "author")) heads(matching(tip, "author")) and -10000:-1 (-10000:-1) and heads(matching(tip, "author")) # more roots testing roots(all()) roots(-10000:-1) (-5000:-1000) and roots(-10000:-1) roots(matching(tip, "author")) roots(matching(tip, "author")) and -10000:-1 (-10000:-1) and roots(matching(tip, "author")) only(max(head())) only(max(head()), min(head())) only(max(head()), limit(head(), 1, 1)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/asv.conf.json0000664000175000017500000000061515060516737017443 0ustar00alpharealphare{ "version": 1, "project": "mercurial", "project_url": "https://mercurial-scm.org/", "repo": "..", "branches": ["default", "stable"], "environment_type": "virtualenv", "show_commit_url": "https://www.mercurial-scm.org/repo/hg/rev/", "benchmark_dir": "benchmarks", "env_dir": "../.asv/env", "results_dir": "../.asv/results", "html_dir": "../.asv/html" } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1757584919.3046966 mercurial-7.1.1/contrib/automation/0000775000175000017500000000000015060517027017202 5ustar00alpharealphare././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/README.rst0000664000175000017500000002311515060516737020702 0ustar00alpharealphare==================== Mercurial Automation ==================== This directory contains code and utilities for building and testing Mercurial on remote machines. The ``automation.py`` Script ============================ ``automation.py`` is an executable Python script (requires Python 3.5+) that serves as a driver to common automation tasks. When executed, the script will *bootstrap* a virtualenv in ``/build/venv-automation`` then re-execute itself using that virtualenv. So there is no need for the caller to have a virtualenv explicitly activated. This virtualenv will be populated with various dependencies (as defined by the ``requirements.txt`` file). To see what you can do with this script, simply run it:: $ ./automation.py Local State =========== By default, local state required to interact with remote servers is stored in the ``~/.hgautomation`` directory. We attempt to limit persistent state to this directory. Even when performing tasks that may have side-effects, we try to limit those side-effects so they don't impact the local system. e.g. when we SSH into a remote machine, we create a temporary directory for the SSH config so the user's known hosts file isn't updated. Try Server ========== There exists a *Try Server* which allows automation to run against an arbitrary Mercurial changeset and displays results via the web. .. note:: The *Try Server* is still experimental infrastructure. To use the *Try Server*:: $ ./automation.py try With a custom AWS profile:: $ AWS_PROFILE=hg contrib/automation/automation.py try By default, the ``.`` revision is submitted. **Any uncommitted changes are not submitted.** To switch which revision is used:: $ ./automation.py try -r abcdef Access to the *Try Server* requires access to a special AWS account. This account is currently run by Gregory Szorc. Here is the procedure for accessing the *Try Server*: 1. Email Gregory Szorc at gregory.szorc@gmail.com and request a username. This username will be stored in the public domain. 2. Wait for an email reply containing your temporary AWS credentials. 3. Log in at https://gregoryszorc-hg.signin.aws.amazon.com/console and set a new, secure password. 4. Go to https://console.aws.amazon.com/iam/home?region=us-west-2#/security_credentials 5. Under ``Access keys for CLI, SDK, & API access``, click the ``Create access key`` button. 6. See the ``AWS Integration`` section for instructions on configuring your local client to use the generated credentials. AWS Integration =============== Various automation tasks integrate with AWS to provide access to resources such as EC2 instances for generic compute. This obviously requires an AWS account and credentials to work. We use the ``boto3`` library for interacting with AWS APIs. We do not employ any special functionality for telling ``boto3`` where to find AWS credentials. See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html for how ``boto3`` works. Once you have configured your environment such that ``boto3`` can find credentials, interaction with AWS should *just work*. To configure ``boto3``, you can use the ``aws configure`` command to write out configuration files. (The ``aws`` command is typically provided by an ``awscli`` package available in your package manager, including ``pip``.) Alternatively, you can write out files in ``~/.aws/`` directly. e.g.:: # ~/.aws/config [default] region = us-west-2 # ~/.aws/credentials [default] aws_access_key_id = XXXX aws_secret_access_key = YYYY If you have multiple AWS accounts, you can name the profile something different from ``default``. e.g. ``hg``. You can influence which profile is used by ``boto3`` by setting the ``AWS_PROFILE`` environment variable. e.g. ``AWS_PROFILE=hg``. Resource Management ------------------- Depending on the task being performed, various AWS services will be accessed. This of course requires AWS credentials with permissions to access these services. The following AWS services can be accessed by automation tasks: * EC2 * IAM * Simple Systems Manager (SSM) Various resources will also be created as part of performing various tasks. This also requires various permissions. The following AWS resources can be created by automation tasks: * EC2 key pairs * EC2 security groups * EC2 instances * IAM roles and instance profiles * SSM command invocations When possible, we prefix resource names with ``hg-`` so they can easily be identified as belonging to Mercurial. .. important:: We currently assume that AWS accounts utilized by *us* are single tenancy. Attempts to have discrete users of ``automation.py`` (including sharing credentials across machines) using the same AWS account can result in them interfering with each other and things breaking. Cost of Operation ----------------- ``automation.py`` tries to be frugal with regards to utilization of remote resources. Persistent remote resources are minimized in order to keep costs in check. For example, EC2 instances are often ephemeral and only live as long as the operation being performed. Under normal operation, recurring costs are limited to: * Storage costs for AMI / EBS snapshots. This should be just a few pennies per month. When running EC2 instances, you'll be billed accordingly. Default instance types vary by operation. We try to be respectful of your money when choosing defaults. e.g. for Windows instances which are billed per hour, we use e.g. ``t3.medium`` instances, which cost ~$0.07 per hour. For operations that scale well to many CPUs like running Linux tests, we may use a more powerful instance like ``c5.9xlarge``. However, since Linux instances are billed per second and the cost of running an e.g. ``c5.9xlarge`` for half the time of a ``c5.4xlarge`` is roughly the same, the choice is justified. .. note:: When running Windows EC2 instances, AWS bills at the full hourly cost, even if the instance doesn't run for a full hour (per-second billing doesn't apply to Windows AMIs). Managing Remote Resources ------------------------- Occassionally, there may be an error purging a temporary resource. Or you may wish to forcefully purge remote state. Commands can be invoked to manually purge remote resources. To terminate all EC2 instances that we manage:: $ automation.py terminate-ec2-instances To purge all EC2 resources that we manage:: $ automation.py purge-ec2-resources Remote Machine Interfaces ========================= The code that connects to a remote machine and executes things is theoretically machine agnostic as long as the remote machine conforms to an *interface*. In other words, to perform actions like running tests remotely or triggering packaging, it shouldn't matter if the remote machine is an EC2 instance, a virtual machine, etc. This section attempts to document the interface that remote machines need to provide in order to be valid *targets* for remote execution. These interfaces are often not ideal nor the most flexible. Instead, they have often evolved as the requirements of our automation code have evolved. Linux ----- Remote Linux machines expose an SSH server on port 22. The SSH server must allow the ``hg`` user to authenticate using the SSH key generated by the automation code. The ``hg`` user should be part of the ``hg`` group and it should have ``sudo`` access without password prompting. The SSH channel must support SFTP to facilitate transferring files from client to server. ``/bin/bash`` must be executable and point to a bash shell executable. The ``/hgdev`` directory must exist and all its content owned by ``hg::hg``. The ``/hgdev/pyenv`` directory should contain an installation of ``pyenv``. Various Python distributions should be installed. The exact versions shouldn't matter. ``pyenv global`` should have been run so ``/hgdev/pyenv/shims/`` is populated with redirector scripts that point to the appropriate Python executable. The ``/hgdev/venv-bootstrap`` directory must contain a virtualenv with Mercurial installed. The ``/hgdev/venv-bootstrap/bin/hg`` executable is referenced by various scripts and the client. The ``/hgdev/src`` directory MUST contain a clone of the Mercurial source code. The state of the working directory is not important. In order to run tests, the ``/hgwork`` directory will be created. This may require running various ``mkfs.*`` executables and ``mount`` to provision a new filesystem. This will require elevated privileges via ``sudo``. Various dependencies to run the Mercurial test harness are also required. Documenting them is beyond the scope of this document. Various tests also require other optional dependencies and missing dependencies will be printed by the test runner when a test is skipped. Releasing Windows Artifacts =========================== The `automation.py` script can be used to automate the release of Windows artifacts:: $ ./automation.py build-all-windows-packages --revision 5.1.1 $ ./automation.py publish-windows-artifacts 5.1.1 The first command will launch an EC2 instance to build all Windows packages and copy them into the `dist` directory relative to the repository root. The second command will then attempt to upload these files to PyPI (via `twine`) and to `mercurial-scm.org` (via SSH). Uploading to PyPI requires a PyPI account with write access to the `Mercurial` package. You can skip PyPI uploading by passing `--no-pypi`. Uploading to `mercurial-scm.org` requires an SSH account on that server with `windows` group membership and for the SSH key for that account to be the default SSH key (e.g. `~/.ssh/id_rsa`) or in a running SSH agent. You can skip `mercurial-scm.org` uploading by passing `--no-mercurial-scm-org`. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/automation.py0000755000175000017500000000327415060516737021752 0ustar00alpharealphare#!/usr/bin/env python3 # # automation.py - Perform tasks on remote machines # # Copyright 2019 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. import os import pathlib import subprocess import sys import venv HERE = pathlib.Path(os.path.abspath(__file__)).parent REQUIREMENTS_TXT = HERE / 'requirements.txt' SOURCE_DIR = HERE.parent.parent VENV = SOURCE_DIR / 'build' / 'venv-automation' def bootstrap(): venv_created = not VENV.exists() VENV.parent.mkdir(exist_ok=True) venv.create(VENV, with_pip=True) if os.name == 'nt': venv_bin = VENV / 'Scripts' pip = venv_bin / 'pip.exe' python = venv_bin / 'python.exe' else: venv_bin = VENV / 'bin' pip = venv_bin / 'pip' python = venv_bin / 'python' args = [ str(pip), 'install', '-r', str(REQUIREMENTS_TXT), '--disable-pip-version-check', ] if not venv_created: args.append('-q') subprocess.run(args, check=True) os.environ['HGAUTOMATION_BOOTSTRAPPED'] = '1' os.environ['PATH'] = '%s%s%s' % (venv_bin, os.pathsep, os.environ['PATH']) subprocess.run([str(python), __file__] + sys.argv[1:], check=True) def run(): import hgautomation.cli as cli # Need to strip off main Python executable. cli.main() if __name__ == '__main__': try: if 'HGAUTOMATION_BOOTSTRAPPED' not in os.environ: bootstrap() else: run() except subprocess.CalledProcessError as e: sys.exit(e.returncode) except KeyboardInterrupt: sys.exit(1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1757584919.3052642 mercurial-7.1.1/contrib/automation/hgautomation/0000775000175000017500000000000015060517027021701 5ustar00alpharealphare././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/hgautomation/__init__.py0000664000175000017500000000274415060516737024030 0ustar00alpharealphare# __init__.py - High-level automation interfaces # # Copyright 2019 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # no-check-code because Python 3 native. import pathlib import secrets from .aws import AWSConnection class HGAutomation: """High-level interface for Mercurial automation. Holds global state, provides access to other primitives, etc. """ def __init__(self, state_path: pathlib.Path): self.state_path = state_path state_path.mkdir(exist_ok=True) def default_password(self): """Obtain the default password to use for remote machines. A new password will be generated if one is not stored. """ p = self.state_path / 'default-password' try: with p.open('r', encoding='ascii') as fh: data = fh.read().strip() if data: return data except FileNotFoundError: pass password = secrets.token_urlsafe(24) with p.open('w', encoding='ascii') as fh: fh.write(password) fh.write('\n') p.chmod(0o0600) return password def aws_connection(self, region: str, ensure_ec2_state: bool = True): """Obtain an AWSConnection instance bound to a specific region.""" return AWSConnection(self, region, ensure_ec2_state=ensure_ec2_state) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/hgautomation/aws.py0000664000175000017500000012012415060516737023054 0ustar00alpharealphare# aws.py - Automation code for Amazon Web Services # # Copyright 2019 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # no-check-code because Python 3 native. import contextlib import copy import hashlib import json import os import pathlib import subprocess import time import boto3 import botocore.exceptions from .linux import BOOTSTRAP_DEBIAN from .ssh import ( exec_command as ssh_exec_command, wait_for_ssh, ) from .winrm import ( run_powershell, wait_for_winrm, ) SOURCE_ROOT = pathlib.Path( os.path.abspath(__file__) ).parent.parent.parent.parent INSTALL_WINDOWS_DEPENDENCIES = ( SOURCE_ROOT / 'contrib' / 'install-windows-dependencies.ps1' ) INSTANCE_TYPES_WITH_STORAGE = { 'c5d', 'd2', 'h1', 'i3', 'm5ad', 'm5d', 'r5d', 'r5ad', 'x1', 'z1d', } AMAZON_ACCOUNT_ID = '801119661308' DEBIAN_ACCOUNT_ID = '379101102735' DEBIAN_ACCOUNT_ID_2 = '136693071363' UBUNTU_ACCOUNT_ID = '099720109477' WINDOWS_BASE_IMAGE_NAME = 'Windows_Server-2022-English-Full-Base-*' KEY_PAIRS = { 'automation', } SECURITY_GROUPS = { 'linux-dev-1': { 'description': 'Mercurial Linux instances that perform build/test automation', 'ingress': [ { 'FromPort': 22, 'ToPort': 22, 'IpProtocol': 'tcp', 'IpRanges': [ { 'CidrIp': '0.0.0.0/0', 'Description': 'SSH from entire Internet', }, ], }, ], }, 'windows-dev-1': { 'description': 'Mercurial Windows instances that perform build automation', 'ingress': [ { 'FromPort': 22, 'ToPort': 22, 'IpProtocol': 'tcp', 'IpRanges': [ { 'CidrIp': '0.0.0.0/0', 'Description': 'SSH from entire Internet', }, ], }, { 'FromPort': 3389, 'ToPort': 3389, 'IpProtocol': 'tcp', 'IpRanges': [ { 'CidrIp': '0.0.0.0/0', 'Description': 'RDP from entire Internet', }, ], }, { 'FromPort': 5985, 'ToPort': 5986, 'IpProtocol': 'tcp', 'IpRanges': [ { 'CidrIp': '0.0.0.0/0', 'Description': 'PowerShell Remoting (Windows Remote Management)', }, ], }, ], }, } IAM_ROLES = { 'ephemeral-ec2-role-1': { 'description': 'Mercurial temporary EC2 instances', 'policy_arns': [ 'arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM', ], }, } ASSUME_ROLE_POLICY_DOCUMENT = ''' { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } '''.strip() IAM_INSTANCE_PROFILES = { 'ephemeral-ec2-1': { 'roles': [ 'ephemeral-ec2-role-1', ], } } # User Data for Windows EC2 instance. Mainly used to set the password # and configure WinRM. # Inspired by the User Data script used by Packer # (from https://www.packer.io/intro/getting-started/build-image.html). WINDOWS_USER_DATA = r''' # TODO enable this once we figure out what is failing. #$ErrorActionPreference = "stop" # Set administrator password net user Administrator "%s" wmic useraccount where "name='Administrator'" set PasswordExpires=FALSE # And set it via EC2Launch so it persists across reboots. $config = & $env:ProgramFiles\Amazon\EC2Launch\EC2Launch.exe get-agent-config --format json | ConvertFrom-Json $config | ConvertTo-Json -Depth 6 | Out-File -encoding UTF8 $env:ProgramData/Amazon/EC2Launch/config/agent-config.yml $setAdminAccount = @" { "task": "setAdminAccount", "inputs": { "password": { "type": "static", "data": "%s" } } } "@ $config.config | %%{if($_.stage -eq 'preReady'){$_.tasks += (ConvertFrom-Json -InputObject $setAdminAccount)}} $config | ConvertTo-Json -Depth 6 | Out-File -encoding UTF8 $env:ProgramData/Amazon/EC2Launch/config/agent-config.yml # First, make sure WinRM can't be connected to netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=block # Delete any existing WinRM listeners winrm delete winrm/config/listener?Address=*+Transport=HTTP 2>$Null winrm delete winrm/config/listener?Address=*+Transport=HTTPS 2>$Null # Create a new WinRM listener and configure winrm create winrm/config/listener?Address=*+Transport=HTTP winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="0"}' winrm set winrm/config '@{MaxTimeoutms="7200000"}' winrm set winrm/config/service '@{AllowUnencrypted="true"}' winrm set winrm/config/service '@{MaxConcurrentOperationsPerUser="12000"}' winrm set winrm/config/service/auth '@{Basic="true"}' winrm set winrm/config/client/auth '@{Basic="true"}' # Configure UAC to allow privilege elevation in remote shells $Key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' $Setting = 'LocalAccountTokenFilterPolicy' Set-ItemProperty -Path $Key -Name $Setting -Value 1 -Force # Avoid long usernames in the temp directory path because the '~' causes extra quoting in ssh output [System.Environment]::SetEnvironmentVariable('TMP', 'C:\Temp', [System.EnvironmentVariableTarget]::User) [System.Environment]::SetEnvironmentVariable('TEMP', 'C:\Temp', [System.EnvironmentVariableTarget]::User) # Configure and restart the WinRM Service; Enable the required firewall exception Stop-Service -Name WinRM Set-Service -Name WinRM -StartupType Automatic netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new action=allow localip=any remoteip=any Start-Service -Name WinRM # Disable firewall on private network interfaces so prompts don't appear. Set-NetFirewallProfile -Name private -Enabled false '''.lstrip() WINDOWS_BOOTSTRAP_POWERSHELL = ''' Write-Output "installing PowerShell dependencies" Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force Set-PSRepository -Name PSGallery -InstallationPolicy Trusted Install-Module -Name OpenSSHUtils -RequiredVersion 0.0.2.0 Write-Output "installing OpenSSL server" Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 # Various tools will attempt to use older versions of .NET. So we enable # the feature that provides them so it doesn't have to be auto-enabled # later. Write-Output "enabling .NET Framework feature" Install-WindowsFeature -Name Net-Framework-Core ''' class AWSConnection: """Manages the state of a connection with AWS.""" def __init__(self, automation, region: str, ensure_ec2_state: bool = True): self.automation = automation self.local_state_path = automation.state_path self.prefix = 'hg-' self.session = boto3.session.Session(region_name=region) self.ec2client = self.session.client('ec2') self.ec2resource = self.session.resource('ec2') self.iamclient = self.session.client('iam') self.iamresource = self.session.resource('iam') self.security_groups = {} if ensure_ec2_state: ensure_key_pairs(automation.state_path, self.ec2resource) self.security_groups = ensure_security_groups(self.ec2resource) ensure_iam_state(self.iamclient, self.iamresource) def key_pair_path_private(self, name): """Path to a key pair private key file.""" return self.local_state_path / 'keys' / ('keypair-%s' % name) def key_pair_path_public(self, name): return self.local_state_path / 'keys' / ('keypair-%s.pub' % name) def rsa_key_fingerprint(p: pathlib.Path): """Compute the fingerprint of an RSA private key.""" # TODO use rsa package. res = subprocess.run( [ 'openssl', 'pkcs8', '-in', str(p), '-nocrypt', '-topk8', '-outform', 'DER', ], capture_output=True, check=True, ) sha1 = hashlib.sha1(res.stdout).hexdigest() return ':'.join(a + b for a, b in zip(sha1[::2], sha1[1::2])) def ensure_key_pairs(state_path: pathlib.Path, ec2resource, prefix='hg-'): remote_existing = {} for kpi in ec2resource.key_pairs.all(): if kpi.name.startswith(prefix): remote_existing[kpi.name[len(prefix) :]] = kpi.key_fingerprint # Validate that we have these keys locally. key_path = state_path / 'keys' key_path.mkdir(exist_ok=True, mode=0o700) def remove_remote(name): print('deleting key pair %s' % name) key = ec2resource.KeyPair(name) key.delete() def remove_local(name): pub_full = key_path / ('keypair-%s.pub' % name) priv_full = key_path / ('keypair-%s' % name) print('removing %s' % pub_full) pub_full.unlink() print('removing %s' % priv_full) priv_full.unlink() local_existing = {} for f in sorted(os.listdir(key_path)): if not f.startswith('keypair-') or not f.endswith('.pub'): continue name = f[len('keypair-') : -len('.pub')] pub_full = key_path / f priv_full = key_path / ('keypair-%s' % name) with open(pub_full, encoding='ascii') as fh: data = fh.read() if not data.startswith('ssh-rsa '): print( 'unexpected format for key pair file: %s; removing' % pub_full ) pub_full.unlink() priv_full.unlink() continue local_existing[name] = rsa_key_fingerprint(priv_full) for name in sorted(set(remote_existing) | set(local_existing)): if name not in local_existing: actual = '%s%s' % (prefix, name) print('remote key %s does not exist locally' % name) remove_remote(actual) del remote_existing[name] elif name not in remote_existing: print('local key %s does not exist remotely' % name) remove_local(name) del local_existing[name] elif remote_existing[name] != local_existing[name]: print( 'key fingerprint mismatch for %s; ' 'removing from local and remote' % name ) remove_local(name) remove_remote('%s%s' % (prefix, name)) del local_existing[name] del remote_existing[name] missing = KEY_PAIRS - set(remote_existing) for name in sorted(missing): actual = '%s%s' % (prefix, name) print('creating key pair %s' % actual) priv_full = key_path / ('keypair-%s' % name) pub_full = key_path / ('keypair-%s.pub' % name) kp = ec2resource.create_key_pair(KeyName=actual) with priv_full.open('w', encoding='ascii') as fh: fh.write(kp.key_material) fh.write('\n') priv_full.chmod(0o0600) # SSH public key can be extracted via `ssh-keygen`. with pub_full.open('w', encoding='ascii') as fh: subprocess.run( ['ssh-keygen', '-y', '-f', str(priv_full)], stdout=fh, check=True, ) pub_full.chmod(0o0600) def delete_instance_profile(profile): for role in profile.roles: print( 'removing role %s from instance profile %s' % (role.name, profile.name) ) profile.remove_role(RoleName=role.name) print('deleting instance profile %s' % profile.name) profile.delete() def ensure_iam_state(iamclient, iamresource, prefix='hg-'): """Ensure IAM state is in sync with our canonical definition.""" remote_profiles = {} for profile in iamresource.instance_profiles.all(): if profile.name.startswith(prefix): remote_profiles[profile.name[len(prefix) :]] = profile for name in sorted(set(remote_profiles) - set(IAM_INSTANCE_PROFILES)): delete_instance_profile(remote_profiles[name]) del remote_profiles[name] remote_roles = {} for role in iamresource.roles.all(): if role.name.startswith(prefix): remote_roles[role.name[len(prefix) :]] = role for name in sorted(set(remote_roles) - set(IAM_ROLES)): role = remote_roles[name] print('removing role %s' % role.name) role.delete() del remote_roles[name] # We've purged remote state that doesn't belong. Create missing # instance profiles and roles. for name in sorted(set(IAM_INSTANCE_PROFILES) - set(remote_profiles)): actual = '%s%s' % (prefix, name) print('creating IAM instance profile %s' % actual) profile = iamresource.create_instance_profile( InstanceProfileName=actual ) remote_profiles[name] = profile waiter = iamclient.get_waiter('instance_profile_exists') waiter.wait(InstanceProfileName=actual) print('IAM instance profile %s is available' % actual) for name in sorted(set(IAM_ROLES) - set(remote_roles)): entry = IAM_ROLES[name] actual = '%s%s' % (prefix, name) print('creating IAM role %s' % actual) role = iamresource.create_role( RoleName=actual, Description=entry['description'], AssumeRolePolicyDocument=ASSUME_ROLE_POLICY_DOCUMENT, ) waiter = iamclient.get_waiter('role_exists') waiter.wait(RoleName=actual) print('IAM role %s is available' % actual) remote_roles[name] = role for arn in entry['policy_arns']: print('attaching policy %s to %s' % (arn, role.name)) role.attach_policy(PolicyArn=arn) # Now reconcile state of profiles. for name, meta in sorted(IAM_INSTANCE_PROFILES.items()): profile = remote_profiles[name] wanted = {'%s%s' % (prefix, role) for role in meta['roles']} have = {role.name for role in profile.roles} for role in sorted(have - wanted): print('removing role %s from %s' % (role, profile.name)) profile.remove_role(RoleName=role) for role in sorted(wanted - have): print('adding role %s to %s' % (role, profile.name)) profile.add_role(RoleName=role) def find_image(ec2resource, owner_id, name, reverse_sort_field=None): """Find an AMI by its owner ID and name.""" images = ec2resource.images.filter( Filters=[ { 'Name': 'owner-id', 'Values': [owner_id], }, { 'Name': 'state', 'Values': ['available'], }, { 'Name': 'image-type', 'Values': ['machine'], }, { 'Name': 'name', 'Values': [name], }, ] ) if reverse_sort_field: images = sorted( images, key=lambda image: getattr(image, reverse_sort_field), reverse=True, ) for image in images: return image raise Exception('unable to find image for %s' % name) def ensure_security_groups(ec2resource, prefix='hg-'): """Ensure all necessary Mercurial security groups are present. All security groups are prefixed with ``hg-`` by default. Any security groups having this prefix but aren't in our list are deleted. """ existing = {} for group in ec2resource.security_groups.all(): if group.group_name.startswith(prefix): existing[group.group_name[len(prefix) :]] = group purge = set(existing) - set(SECURITY_GROUPS) for name in sorted(purge): group = existing[name] print('removing legacy security group: %s' % group.group_name) group.delete() security_groups = {} for name, group in sorted(SECURITY_GROUPS.items()): if name in existing: security_groups[name] = existing[name] continue actual = '%s%s' % (prefix, name) print('adding security group %s' % actual) group_res = ec2resource.create_security_group( Description=group['description'], GroupName=actual, ) group_res.authorize_ingress( IpPermissions=group['ingress'], ) security_groups[name] = group_res return security_groups def terminate_ec2_instances(ec2resource, prefix='hg-'): """Terminate all EC2 instances managed by us.""" waiting = [] for instance in ec2resource.instances.all(): if instance.state['Name'] == 'terminated': continue for tag in instance.tags or []: if tag['Key'] == 'Name' and tag['Value'].startswith(prefix): print('terminating %s' % instance.id) instance.terminate() waiting.append(instance) for instance in waiting: instance.wait_until_terminated() def remove_resources(c, prefix='hg-'): """Purge all of our resources in this EC2 region.""" ec2resource = c.ec2resource iamresource = c.iamresource terminate_ec2_instances(ec2resource, prefix=prefix) for image in ec2resource.images.filter(Owners=['self']): if image.name.startswith(prefix): remove_ami(ec2resource, image) for group in ec2resource.security_groups.all(): if group.group_name.startswith(prefix): print('removing security group %s' % group.group_name) group.delete() for profile in iamresource.instance_profiles.all(): if profile.name.startswith(prefix): delete_instance_profile(profile) for role in iamresource.roles.all(): if role.name.startswith(prefix): for p in role.attached_policies.all(): print('detaching policy %s from %s' % (p.arn, role.name)) role.detach_policy(PolicyArn=p.arn) print('removing role %s' % role.name) role.delete() def wait_for_ip_addresses(instances): """Wait for the public IP addresses of an iterable of instances.""" for instance in instances: while True: if not instance.public_ip_address: time.sleep(2) instance.reload() continue print( 'public IP address for %s: %s' % (instance.id, instance.public_ip_address) ) break def remove_ami(ec2resource, image): """Remove an AMI and its underlying snapshots.""" snapshots = [] for device in image.block_device_mappings: if 'Ebs' in device: snapshots.append(ec2resource.Snapshot(device['Ebs']['SnapshotId'])) print('deregistering %s' % image.id) image.deregister() for snapshot in snapshots: print('deleting snapshot %s' % snapshot.id) snapshot.delete() def wait_for_ssm(ssmclient, instances): """Wait for SSM to come online for an iterable of instance IDs.""" while True: res = ssmclient.describe_instance_information( Filters=[ { 'Key': 'InstanceIds', 'Values': [i.id for i in instances], }, ], ) available = len(res['InstanceInformationList']) wanted = len(instances) print('%d/%d instances available in SSM' % (available, wanted)) if available == wanted: return time.sleep(2) def run_ssm_command(ssmclient, instances, document_name, parameters): """Run a PowerShell script on an EC2 instance.""" res = ssmclient.send_command( InstanceIds=[i.id for i in instances], DocumentName=document_name, Parameters=parameters, CloudWatchOutputConfig={ 'CloudWatchOutputEnabled': True, }, ) command_id = res['Command']['CommandId'] for instance in instances: while True: try: res = ssmclient.get_command_invocation( CommandId=command_id, InstanceId=instance.id, ) except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == 'InvocationDoesNotExist': print('could not find SSM command invocation; waiting') time.sleep(1) continue else: raise if res['Status'] == 'Success': break elif res['Status'] in ('Pending', 'InProgress', 'Delayed'): time.sleep(2) else: raise Exception( 'command failed on %s: %s' % (instance.id, res['Status']) ) @contextlib.contextmanager def temporary_ec2_instances(ec2resource, config): """Create temporary EC2 instances. This is a proxy to ``ec2client.run_instances(**config)`` that takes care of managing the lifecycle of the instances. When the context manager exits, the instances are terminated. The context manager evaluates to the list of data structures describing each created instance. The instances may not be available for work immediately: it is up to the caller to wait for the instance to start responding. """ ids = None try: res = ec2resource.create_instances(**config) ids = [i.id for i in res] print('started instances: %s' % ' '.join(ids)) yield res finally: if ids: print('terminating instances: %s' % ' '.join(ids)) for instance in res: instance.terminate() print('terminated %d instances' % len(ids)) @contextlib.contextmanager def create_temp_windows_ec2_instances( c: AWSConnection, config, bootstrap: bool = False ): """Create temporary Windows EC2 instances. This is a higher-level wrapper around ``create_temp_ec2_instances()`` that configures the Windows instance for Windows Remote Management. The emitted instances will have a ``winrm_client`` attribute containing a ``pypsrp.client.Client`` instance bound to the instance. """ if 'IamInstanceProfile' in config: raise ValueError('IamInstanceProfile cannot be provided in config') if 'UserData' in config: raise ValueError('UserData cannot be provided in config') password = c.automation.default_password() config = copy.deepcopy(config) config['IamInstanceProfile'] = { 'Name': 'hg-ephemeral-ec2-1', } config.setdefault('TagSpecifications', []).append( { 'ResourceType': 'instance', 'Tags': [{'Key': 'Name', 'Value': 'hg-temp-windows'}], } ) if bootstrap: config['UserData'] = WINDOWS_USER_DATA % (password, password) with temporary_ec2_instances(c.ec2resource, config) as instances: wait_for_ip_addresses(instances) print('waiting for Windows Remote Management service...') for instance in instances: client = wait_for_winrm( instance.public_ip_address, 'Administrator', password ) print('established WinRM connection to %s' % instance.id) instance.winrm_client = client yield instances def resolve_fingerprint(fingerprint): fingerprint = json.dumps(fingerprint, sort_keys=True) return hashlib.sha256(fingerprint.encode('utf-8')).hexdigest() def find_and_reconcile_image(ec2resource, name, fingerprint): """Attempt to find an existing EC2 AMI with a name and fingerprint. If an image with the specified fingerprint is found, it is returned. Otherwise None is returned. Existing images for the specified name that don't have the specified fingerprint or are missing required metadata or deleted. """ # Find existing AMIs with this name and delete the ones that are invalid. # Store a reference to a good image so it can be returned one the # image state is reconciled. images = ec2resource.images.filter( Filters=[{'Name': 'name', 'Values': [name]}] ) existing_image = None for image in images: if image.tags is None: print( 'image %s for %s lacks required tags; removing' % (image.id, image.name) ) remove_ami(ec2resource, image) else: tags = {t['Key']: t['Value'] for t in image.tags} if tags.get('HGIMAGEFINGERPRINT') == fingerprint: existing_image = image else: print( 'image %s for %s has wrong fingerprint; removing' % (image.id, image.name) ) remove_ami(ec2resource, image) return existing_image def create_ami_from_instance( ec2client, instance, name, description, fingerprint ): """Create an AMI from a running instance. Returns the ``ec2resource.Image`` representing the created AMI. """ instance.stop() ec2client.get_waiter('instance_stopped').wait( InstanceIds=[instance.id], WaiterConfig={ 'Delay': 5, }, ) print('%s is stopped' % instance.id) image = instance.create_image( Name=name, Description=description, ) image.create_tags( Tags=[ { 'Key': 'HGIMAGEFINGERPRINT', 'Value': fingerprint, }, ] ) print('waiting for image %s' % image.id) ec2client.get_waiter('image_available').wait( ImageIds=[image.id], ) print('image %s available as %s' % (image.id, image.name)) return image def ensure_linux_dev_ami(c: AWSConnection, distro='debian10', prefix='hg-'): """Ensures a Linux development AMI is available and up-to-date. Returns an ``ec2.Image`` of either an existing AMI or a newly-built one. """ ec2client = c.ec2client ec2resource = c.ec2resource name = '%s%s-%s' % (prefix, 'linux-dev', distro) if distro == 'debian9': image = find_image( ec2resource, DEBIAN_ACCOUNT_ID, 'debian-stretch-hvm-x86_64-gp2-2019-09-08-17994', ) ssh_username = 'admin' elif distro == 'debian10': image = find_image( ec2resource, DEBIAN_ACCOUNT_ID_2, 'debian-10-amd64-20190909-10', ) ssh_username = 'admin' elif distro == 'ubuntu18.04': image = find_image( ec2resource, UBUNTU_ACCOUNT_ID, 'ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-20190918', ) ssh_username = 'ubuntu' elif distro == 'ubuntu19.04': image = find_image( ec2resource, UBUNTU_ACCOUNT_ID, 'ubuntu/images/hvm-ssd/ubuntu-disco-19.04-amd64-server-20190918', ) ssh_username = 'ubuntu' else: raise ValueError('unsupported Linux distro: %s' % distro) config = { 'BlockDeviceMappings': [ { 'DeviceName': image.block_device_mappings[0]['DeviceName'], 'Ebs': { 'DeleteOnTermination': True, 'VolumeSize': 10, 'VolumeType': 'gp3', }, }, ], 'EbsOptimized': True, 'ImageId': image.id, 'InstanceInitiatedShutdownBehavior': 'stop', # 8 VCPUs for compiling Python. 'InstanceType': 't3.2xlarge', 'KeyName': '%sautomation' % prefix, 'MaxCount': 1, 'MinCount': 1, 'SecurityGroupIds': [c.security_groups['linux-dev-1'].id], } requirements3_path = ( pathlib.Path(__file__).parent.parent / 'linux-requirements-py3.txt' ) requirements35_path = ( pathlib.Path(__file__).parent.parent / 'linux-requirements-py3.5.txt' ) with requirements3_path.open('r', encoding='utf-8') as fh: requirements3 = fh.read() with requirements35_path.open('r', encoding='utf-8') as fh: requirements35 = fh.read() # Compute a deterministic fingerprint to determine whether image needs to # be regenerated. fingerprint = resolve_fingerprint( { 'instance_config': config, 'bootstrap_script': BOOTSTRAP_DEBIAN, 'requirements_py3': requirements3, 'requirements_py35': requirements35, } ) existing_image = find_and_reconcile_image(ec2resource, name, fingerprint) if existing_image: return existing_image print('no suitable %s image found; creating one...' % name) with temporary_ec2_instances(ec2resource, config) as instances: wait_for_ip_addresses(instances) instance = instances[0] client = wait_for_ssh( instance.public_ip_address, 22, username=ssh_username, key_filename=str(c.key_pair_path_private('automation')), ) home = '/home/%s' % ssh_username with client: print('connecting to SSH server') sftp = client.open_sftp() print('uploading bootstrap files') with sftp.open('%s/bootstrap' % home, 'wb') as fh: fh.write(BOOTSTRAP_DEBIAN) fh.chmod(0o0700) with sftp.open('%s/requirements-py3.txt' % home, 'wb') as fh: fh.write(requirements3) fh.chmod(0o0700) with sftp.open('%s/requirements-py3.5.txt' % home, 'wb') as fh: fh.write(requirements35) fh.chmod(0o0700) print('executing bootstrap') chan, stdin, stdout = ssh_exec_command( client, '%s/bootstrap' % home ) stdin.close() for line in stdout: print(line, end='') res = chan.recv_exit_status() if res: raise Exception('non-0 exit from bootstrap: %d' % res) print( 'bootstrap completed; stopping %s to create %s' % (instance.id, name) ) return create_ami_from_instance( ec2client, instance, name, 'Mercurial Linux development environment', fingerprint, ) @contextlib.contextmanager def temporary_linux_dev_instances( c: AWSConnection, image, instance_type, prefix='hg-', ensure_extra_volume=False, ): """Create temporary Linux development EC2 instances. Context manager resolves to a list of ``ec2.Instance`` that were created and are running. ``ensure_extra_volume`` can be set to ``True`` to require that instances have a 2nd storage volume available other than the primary AMI volume. For instance types with instance storage, this does nothing special. But for instance types without instance storage, an additional EBS volume will be added to the instance. Instances have an ``ssh_client`` attribute containing a paramiko SSHClient instance bound to the instance. Instances have an ``ssh_private_key_path`` attributing containing the str path to the SSH private key to connect to the instance. """ block_device_mappings = [ { 'DeviceName': image.block_device_mappings[0]['DeviceName'], 'Ebs': { 'DeleteOnTermination': True, 'VolumeSize': 12, 'VolumeType': 'gp3', }, } ] # This is not an exhaustive list of instance types having instance storage. # But if ensure_extra_volume and not instance_type.startswith( tuple(INSTANCE_TYPES_WITH_STORAGE) ): main_device = block_device_mappings[0]['DeviceName'] if main_device == 'xvda': second_device = 'xvdb' elif main_device == '/dev/sda1': second_device = '/dev/sdb' else: raise ValueError( 'unhandled primary EBS device name: %s' % main_device ) block_device_mappings.append( { 'DeviceName': second_device, 'Ebs': { 'DeleteOnTermination': True, 'VolumeSize': 8, 'VolumeType': 'gp3', }, } ) config = { 'BlockDeviceMappings': block_device_mappings, 'EbsOptimized': True, 'ImageId': image.id, 'InstanceInitiatedShutdownBehavior': 'terminate', 'InstanceType': instance_type, 'KeyName': '%sautomation' % prefix, 'MaxCount': 1, 'MinCount': 1, 'SecurityGroupIds': [c.security_groups['linux-dev-1'].id], } with temporary_ec2_instances(c.ec2resource, config) as instances: wait_for_ip_addresses(instances) ssh_private_key_path = str(c.key_pair_path_private('automation')) for instance in instances: client = wait_for_ssh( instance.public_ip_address, 22, username='hg', key_filename=ssh_private_key_path, ) instance.ssh_client = client instance.ssh_private_key_path = ssh_private_key_path try: yield instances finally: for instance in instances: instance.ssh_client.close() def ensure_windows_dev_ami( c: AWSConnection, prefix='hg-', base_image_name=WINDOWS_BASE_IMAGE_NAME, ): """Ensure Windows Development AMI is available and up-to-date. If necessary, a modern AMI will be built by starting a temporary EC2 instance and bootstrapping it. Obsolete AMIs will be deleted so there is only a single AMI having the desired name. Returns an ``ec2.Image`` of either an existing AMI or a newly-built one. """ ec2client = c.ec2client ec2resource = c.ec2resource ssmclient = c.session.client('ssm') name = '%s%s' % (prefix, 'windows-dev') image = find_image( ec2resource, AMAZON_ACCOUNT_ID, base_image_name, reverse_sort_field="name", ) config = { 'BlockDeviceMappings': [ { 'DeviceName': '/dev/sda1', 'Ebs': { 'DeleteOnTermination': True, 'VolumeSize': 32, 'VolumeType': 'gp3', }, } ], 'ImageId': image.id, 'InstanceInitiatedShutdownBehavior': 'stop', 'InstanceType': 'm6i.large', 'KeyName': '%sautomation' % prefix, 'MaxCount': 1, 'MinCount': 1, 'SecurityGroupIds': [c.security_groups['windows-dev-1'].id], } commands = [ # Need to start the service so sshd_config is generated. 'Start-Service sshd', 'Write-Output "modifying sshd_config"', r'$content = Get-Content C:\ProgramData\ssh\sshd_config', '$content = $content -replace "Match Group administrators","" -replace "AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys",""', r'$content | Set-Content C:\ProgramData\ssh\sshd_config', 'Import-Module OpenSSHUtils', r'Repair-SshdConfigPermission C:\ProgramData\ssh\sshd_config -Confirm:$false', 'Restart-Service sshd', 'Write-Output "installing OpenSSL client"', 'Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0', 'Set-Service -Name sshd -StartupType "Automatic"', 'Write-Output "OpenSSH server running"', ] with INSTALL_WINDOWS_DEPENDENCIES.open('r', encoding='utf-8') as fh: commands.extend(l.rstrip() for l in fh) # Disable Windows Defender when bootstrapping because it just slows # things down. commands.insert(0, 'Set-MpPreference -DisableRealtimeMonitoring $true') commands.append('Set-MpPreference -DisableRealtimeMonitoring $false') # Trigger shutdown to prepare for imaging. commands.append( 'Stop-Computer -ComputerName localhost', ) # Compute a deterministic fingerprint to determine whether image needs # to be regenerated. fingerprint = resolve_fingerprint( { 'instance_config': config, 'user_data': WINDOWS_USER_DATA, 'initial_bootstrap': WINDOWS_BOOTSTRAP_POWERSHELL, 'bootstrap_commands': commands, 'base_image_name': base_image_name, } ) existing_image = find_and_reconcile_image(ec2resource, name, fingerprint) if existing_image: return existing_image print('no suitable Windows development image found; creating one...') with create_temp_windows_ec2_instances( c, config, bootstrap=True ) as instances: assert len(instances) == 1 instance = instances[0] wait_for_ssm(ssmclient, [instance]) # On first boot, install various Windows updates. # We would ideally use PowerShell Remoting for this. However, there are # trust issues that make it difficult to invoke Windows Update # remotely. So we use SSM, which has a mechanism for running Windows # Update. print('installing Windows features...') run_ssm_command( ssmclient, [instance], 'AWS-RunPowerShellScript', { 'commands': WINDOWS_BOOTSTRAP_POWERSHELL.split('\n'), }, ) # Reboot so all updates are fully applied. # # We don't use instance.reboot() here because it is asynchronous and # we don't know when exactly the instance has rebooted. It could take # a while to stop and we may start trying to interact with the instance # before it has rebooted. print('rebooting instance %s' % instance.id) instance.stop() ec2client.get_waiter('instance_stopped').wait( InstanceIds=[instance.id], WaiterConfig={ 'Delay': 5, }, ) instance.start() wait_for_ip_addresses([instance]) # There is a race condition here between the User Data PS script running # and us connecting to WinRM. This can manifest as # "AuthorizationManager check failed" failures during run_powershell(). # TODO figure out a workaround. print('waiting for Windows Remote Management to come back...') client = wait_for_winrm( instance.public_ip_address, 'Administrator', c.automation.default_password(), ) print('established WinRM connection to %s' % instance.id) instance.winrm_client = client print('bootstrapping instance...') run_powershell(instance.winrm_client, '\n'.join(commands)) print('bootstrap completed; stopping %s to create image' % instance.id) return create_ami_from_instance( ec2client, instance, name, 'Mercurial Windows development environment', fingerprint, ) @contextlib.contextmanager def temporary_windows_dev_instances( c: AWSConnection, image, instance_type, prefix='hg-', disable_antivirus=False, ): """Create a temporary Windows development EC2 instance. Context manager resolves to the list of ``EC2.Instance`` that were created. """ config = { 'BlockDeviceMappings': [ { 'DeviceName': '/dev/sda1', 'Ebs': { 'DeleteOnTermination': True, 'VolumeSize': 32, 'VolumeType': 'gp3', }, } ], 'ImageId': image.id, 'InstanceInitiatedShutdownBehavior': 'stop', 'InstanceType': instance_type, 'KeyName': '%sautomation' % prefix, 'MaxCount': 1, 'MinCount': 1, 'SecurityGroupIds': [c.security_groups['windows-dev-1'].id], } with create_temp_windows_ec2_instances(c, config) as instances: if disable_antivirus: for instance in instances: run_powershell( instance.winrm_client, 'Set-MpPreference -DisableRealtimeMonitoring $true', ) yield instances ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/hgautomation/cli.py0000664000175000017500000003421615060516737023037 0ustar00alpharealphare# cli.py - Command line interface for automation # # Copyright 2019 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # no-check-code because Python 3 native. import argparse import concurrent.futures as futures import os import pathlib import time from . import ( aws, HGAutomation, linux, try_server, windows, ) SOURCE_ROOT = pathlib.Path( os.path.abspath(__file__) ).parent.parent.parent.parent DIST_PATH = SOURCE_ROOT / 'dist' def bootstrap_linux_dev( hga: HGAutomation, aws_region, distros=None, parallel=False ): c = hga.aws_connection(aws_region) if distros: distros = distros.split(',') else: distros = sorted(linux.DISTROS) # TODO There is a wonky interaction involving KeyboardInterrupt whereby # the context manager that is supposed to terminate the temporary EC2 # instance doesn't run. Until we fix this, make parallel building opt-in # so we don't orphan instances. if parallel: fs = [] with futures.ThreadPoolExecutor(len(distros)) as e: for distro in distros: fs.append(e.submit(aws.ensure_linux_dev_ami, c, distro=distro)) for f in fs: f.result() else: for distro in distros: aws.ensure_linux_dev_ami(c, distro=distro) def bootstrap_windows_dev(hga: HGAutomation, aws_region, base_image_name): c = hga.aws_connection(aws_region) image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name) print('Windows development AMI available as %s' % image.id) def build_inno( hga: HGAutomation, aws_region, arch, revision, version, base_image_name, ): c = hga.aws_connection(aws_region) image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name) DIST_PATH.mkdir(exist_ok=True) with aws.temporary_windows_dev_instances(c, image, 't3.medium') as insts: instance = insts[0] windows.synchronize_hg(SOURCE_ROOT, revision, instance) for a in arch: windows.build_inno_installer( instance.winrm_client, a, DIST_PATH, version=version, ) def build_wix( hga: HGAutomation, aws_region, arch, revision, version, base_image_name, ): c = hga.aws_connection(aws_region) image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name) DIST_PATH.mkdir(exist_ok=True) with aws.temporary_windows_dev_instances(c, image, 't3.medium') as insts: instance = insts[0] windows.synchronize_hg(SOURCE_ROOT, revision, instance) for a in arch: windows.build_wix_installer( instance.winrm_client, a, DIST_PATH, version=version, ) def build_windows_wheel( hga: HGAutomation, aws_region, python_version, arch, revision, base_image_name, ): c = hga.aws_connection(aws_region) image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name) DIST_PATH.mkdir(exist_ok=True) with aws.temporary_windows_dev_instances(c, image, 't3.medium') as insts: instance = insts[0] windows.synchronize_hg(SOURCE_ROOT, revision, instance) for py_version in python_version: for a in arch: windows.build_wheel( instance.winrm_client, py_version, a, DIST_PATH ) def build_all_windows_packages( hga: HGAutomation, aws_region, revision, version, base_image_name ): c = hga.aws_connection(aws_region) image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name) DIST_PATH.mkdir(exist_ok=True) with aws.temporary_windows_dev_instances(c, image, 'm6i.large') as insts: instance = insts[0] winrm_client = instance.winrm_client windows.synchronize_hg(SOURCE_ROOT, revision, instance) for py_version in ("3.7", "3.8", "3.9", "3.10"): for arch in ("x86", "x64"): windows.purge_hg(winrm_client) windows.build_wheel( winrm_client, python_version=py_version, arch=arch, dest_path=DIST_PATH, ) for arch in ('x86', 'x64'): windows.purge_hg(winrm_client) windows.build_inno_installer( winrm_client, arch, DIST_PATH, version=version ) windows.build_wix_installer( winrm_client, arch, DIST_PATH, version=version ) def terminate_ec2_instances(hga: HGAutomation, aws_region): c = hga.aws_connection(aws_region, ensure_ec2_state=False) aws.terminate_ec2_instances(c.ec2resource) def purge_ec2_resources(hga: HGAutomation, aws_region): c = hga.aws_connection(aws_region, ensure_ec2_state=False) aws.remove_resources(c) def run_tests_linux( hga: HGAutomation, aws_region, instance_type, python_version, test_flags, distro, filesystem, ): c = hga.aws_connection(aws_region) image = aws.ensure_linux_dev_ami(c, distro=distro) t_start = time.time() ensure_extra_volume = filesystem not in ('default', 'tmpfs') with aws.temporary_linux_dev_instances( c, image, instance_type, ensure_extra_volume=ensure_extra_volume ) as insts: instance = insts[0] linux.prepare_exec_environment( instance.ssh_client, filesystem=filesystem ) linux.synchronize_hg(SOURCE_ROOT, instance, '.') t_prepared = time.time() linux.run_tests(instance.ssh_client, python_version, test_flags) t_done = time.time() t_setup = t_prepared - t_start t_all = t_done - t_start print( 'total time: %.1fs; setup: %.1fs; tests: %.1fs; setup overhead: %.1f%%' % (t_all, t_setup, t_done - t_prepared, t_setup / t_all * 100.0) ) def run_tests_windows( hga: HGAutomation, aws_region, instance_type, python_version, arch, test_flags, base_image_name, ): c = hga.aws_connection(aws_region) image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name) with aws.temporary_windows_dev_instances( c, image, instance_type, disable_antivirus=True ) as insts: instance = insts[0] windows.synchronize_hg(SOURCE_ROOT, '.', instance) windows.run_tests( instance.winrm_client, python_version, arch, test_flags ) def publish_windows_artifacts( hg: HGAutomation, aws_region, version: str, pypi: bool, mercurial_scm_org: bool, ssh_username: str, ): windows.publish_artifacts( DIST_PATH, version, pypi=pypi, mercurial_scm_org=mercurial_scm_org, ssh_username=ssh_username, ) def run_try(hga: HGAutomation, aws_region: str, rev: str): c = hga.aws_connection(aws_region, ensure_ec2_state=False) try_server.trigger_try(c, rev=rev) def get_parser(): parser = argparse.ArgumentParser() parser.add_argument( '--state-path', default='~/.hgautomation', help='Path for local state files', ) parser.add_argument( '--aws-region', help='AWS region to use', default='us-west-2', ) subparsers = parser.add_subparsers() sp = subparsers.add_parser( 'bootstrap-linux-dev', help='Bootstrap Linux development environments', ) sp.add_argument( '--distros', help='Comma delimited list of distros to bootstrap', ) sp.add_argument( '--parallel', action='store_true', help='Generate AMIs in parallel (not CTRL-c safe)', ) sp.set_defaults(func=bootstrap_linux_dev) sp = subparsers.add_parser( 'bootstrap-windows-dev', help='Bootstrap the Windows development environment', ) sp.add_argument( '--base-image-name', help='AMI name of base image', default=aws.WINDOWS_BASE_IMAGE_NAME, ) sp.set_defaults(func=bootstrap_windows_dev) sp = subparsers.add_parser( 'build-all-windows-packages', help='Build all Windows packages', ) sp.add_argument( '--revision', help='Mercurial revision to build', default='.', ) sp.add_argument( '--version', help='Mercurial version string to use', ) sp.add_argument( '--base-image-name', help='AMI name of base image', default=aws.WINDOWS_BASE_IMAGE_NAME, ) sp.set_defaults(func=build_all_windows_packages) sp = subparsers.add_parser( 'build-inno', help='Build Inno Setup installer(s)', ) sp.add_argument( '--arch', help='Architecture to build for', choices={'x86', 'x64'}, nargs='*', default=['x64'], ) sp.add_argument( '--revision', help='Mercurial revision to build', default='.', ) sp.add_argument( '--version', help='Mercurial version string to use in installer', ) sp.add_argument( '--base-image-name', help='AMI name of base image', default=aws.WINDOWS_BASE_IMAGE_NAME, ) sp.set_defaults(func=build_inno) sp = subparsers.add_parser( 'build-windows-wheel', help='Build Windows wheel(s)', ) sp.add_argument( '--python-version', help='Python version to build for', choices={'3.7', '3.8', '3.9', '3.10'}, nargs='*', default=['3.8'], ) sp.add_argument( '--arch', help='Architecture to build for', choices={'x86', 'x64'}, nargs='*', default=['x64'], ) sp.add_argument( '--revision', help='Mercurial revision to build', default='.', ) sp.add_argument( '--base-image-name', help='AMI name of base image', default=aws.WINDOWS_BASE_IMAGE_NAME, ) sp.set_defaults(func=build_windows_wheel) sp = subparsers.add_parser('build-wix', help='Build WiX installer(s)') sp.add_argument( '--arch', help='Architecture to build for', choices={'x86', 'x64'}, nargs='*', default=['x64'], ) sp.add_argument( '--revision', help='Mercurial revision to build', default='.', ) sp.add_argument( '--version', help='Mercurial version string to use in installer', ) sp.add_argument( '--base-image-name', help='AMI name of base image', default=aws.WINDOWS_BASE_IMAGE_NAME, ) sp.set_defaults(func=build_wix) sp = subparsers.add_parser( 'terminate-ec2-instances', help='Terminate all active EC2 instances managed by us', ) sp.set_defaults(func=terminate_ec2_instances) sp = subparsers.add_parser( 'purge-ec2-resources', help='Purge all EC2 resources managed by us', ) sp.set_defaults(func=purge_ec2_resources) sp = subparsers.add_parser( 'run-tests-linux', help='Run tests on Linux', ) sp.add_argument( '--distro', help='Linux distribution to run tests on', choices=linux.DISTROS, default='debian10', ) sp.add_argument( '--filesystem', help='Filesystem type to use', choices={'btrfs', 'default', 'ext3', 'ext4', 'jfs', 'tmpfs', 'xfs'}, default='default', ) sp.add_argument( '--instance-type', help='EC2 instance type to use', default='c5.9xlarge', ) sp.add_argument( '--python-version', help='Python version to use', choices={ 'system3', '3.8', 'pypy', 'pypy3.5', 'pypy3.6', }, default='system3', ) sp.add_argument( 'test_flags', help='Extra command line flags to pass to run-tests.py', nargs='*', ) sp.set_defaults(func=run_tests_linux) sp = subparsers.add_parser( 'run-tests-windows', help='Run tests on Windows', ) sp.add_argument( '--instance-type', help='EC2 instance type to use', default='m6i.large', ) sp.add_argument( '--python-version', help='Python version to use', choices={'3.8', '3.9', '3.10'}, default='3.9', ) sp.add_argument( '--arch', help='Architecture to test', choices={'x86', 'x64'}, default='x64', ) sp.add_argument( '--test-flags', help='Extra command line flags to pass to run-tests.py', ) sp.add_argument( '--base-image-name', help='AMI name of base image', default=aws.WINDOWS_BASE_IMAGE_NAME, ) sp.set_defaults(func=run_tests_windows) sp = subparsers.add_parser( 'publish-windows-artifacts', help='Publish built Windows artifacts (wheels, installers, etc)', ) sp.add_argument( '--no-pypi', dest='pypi', action='store_false', default=True, help='Skip uploading to PyPI', ) sp.add_argument( '--no-mercurial-scm-org', dest='mercurial_scm_org', action='store_false', default=True, help='Skip uploading to www.mercurial-scm.org', ) sp.add_argument( '--ssh-username', help='SSH username for mercurial-scm.org', ) sp.add_argument( 'version', help='Mercurial version string to locate local packages', ) sp.set_defaults(func=publish_windows_artifacts) sp = subparsers.add_parser( 'try', help='Run CI automation against a custom changeset' ) sp.add_argument('-r', '--rev', default='.', help='Revision to run CI on') sp.set_defaults(func=run_try) return parser def main(): parser = get_parser() args = parser.parse_args() local_state_path = pathlib.Path(os.path.expanduser(args.state_path)) automation = HGAutomation(local_state_path) if not hasattr(args, 'func'): parser.print_help() return kwargs = dict(vars(args)) del kwargs['func'] del kwargs['state_path'] args.func(automation, **kwargs) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/hgautomation/linux.py0000664000175000017500000004317415060516737023432 0ustar00alpharealphare# linux.py - Linux specific automation functionality # # Copyright 2019 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # no-check-code because Python 3 native. import os import pathlib import shlex import subprocess import tempfile from .ssh import exec_command # Linux distributions that are supported. DISTROS = { 'debian9', 'debian10', 'ubuntu18.04', 'ubuntu19.04', } INSTALL_PYTHONS = r''' PYENV3_VERSIONS="3.8.10 3.9.5 pypy3.5-7.0.0 pypy3.6-7.3.3 pypy3.7-7.3.3" git clone https://github.com/pyenv/pyenv.git /hgdev/pyenv pushd /hgdev/pyenv git checkout 328fd42c3a2fbf14ae46dae2021a087fe27ba7e2 popd export PYENV_ROOT="/hgdev/pyenv" export PATH="$PYENV_ROOT/bin:$PATH" # pip 19.2.3. PIP_SHA256=57e3643ff19f018f8a00dfaa6b7e4620e3c1a7a2171fd218425366ec006b3bfe wget -O get-pip.py --progress dot:mega https://github.com/pypa/get-pip/raw/309a56c5fd94bd1134053a541cb4657a4e47e09d/get-pip.py echo "${PIP_SHA256} get-pip.py" | sha256sum --check - VIRTUALENV_SHA256=f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2 VIRTUALENV_TARBALL=virtualenv-16.7.5.tar.gz wget -O ${VIRTUALENV_TARBALL} --progress dot:mega https://files.pythonhosted.org/packages/66/f0/6867af06d2e2f511e4e1d7094ff663acdebc4f15d4a0cb0fed1007395124/${VIRTUALENV_TARBALL} echo "${VIRTUALENV_SHA256} ${VIRTUALENV_TARBALL}" | sha256sum --check - for v in ${PYENV3_VERSIONS}; do pyenv install -v ${v} ${PYENV_ROOT}/versions/${v}/bin/python get-pip.py case ${v} in 3.5.*) REQUIREMENTS=requirements-py3.5.txt ;; pypy3.5*) REQUIREMENTS=requirements-py3.5.txt ;; *) REQUIREMENTS=requirements-py3.txt ;; esac ${PYENV_ROOT}/versions/${v}/bin/pip install -r /hgdev/${REQUIREMENTS} done pyenv global ${PYENV3_VERSIONS} system '''.lstrip().replace( '\r\n', '\n' ) INSTALL_PYOXIDIZER = r''' PYOXIDIZER_VERSION=0.16.0 PYOXIDIZER_SHA256=8875471c270312fbb934007fd30f65f1904cc0f5da6188d61c90ed2129b9f9c1 PYOXIDIZER_URL=https://github.com/indygreg/PyOxidizer/releases/download/pyoxidizer%2F${PYOXIDIZER_VERSION}/pyoxidizer-${PYOXIDIZER_VERSION}-linux_x86_64.zip wget -O pyoxidizer.zip --progress dot:mega ${PYOXIDIZER_URL} echo "${PYOXIDIZER_SHA256} pyoxidizer.zip" | sha256sum --check - unzip pyoxidizer.zip chmod +x pyoxidizer sudo mv pyoxidizer /usr/local/bin/pyoxidizer ''' INSTALL_RUST = r''' RUSTUP_INIT_SHA256=a46fe67199b7bcbbde2dcbc23ae08db6f29883e260e23899a88b9073effc9076 wget -O rustup-init --progress dot:mega https://static.rust-lang.org/rustup/archive/1.18.3/x86_64-unknown-linux-gnu/rustup-init echo "${RUSTUP_INIT_SHA256} rustup-init" | sha256sum --check - chmod +x rustup-init sudo -H -u hg -g hg ./rustup-init -y sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup install 1.41.1 1.52.0 sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup component add clippy ''' BOOTSTRAP_VIRTUALENV = r''' /usr/bin/virtualenv /hgdev/venv-bootstrap HG_SHA256=35fc8ba5e0379c1b3affa2757e83fb0509e8ac314cbd9f1fd133cf265d16e49f HG_TARBALL=mercurial-5.1.1.tar.gz wget -O ${HG_TARBALL} --progress dot:mega https://www.mercurial-scm.org/release/${HG_TARBALL} echo "${HG_SHA256} ${HG_TARBALL}" | sha256sum --check - /hgdev/venv-bootstrap/bin/pip install ${HG_TARBALL} '''.lstrip().replace( '\r\n', '\n' ) BOOTSTRAP_DEBIAN = ( r''' #!/bin/bash set -ex DISTRO=`grep DISTRIB_ID /etc/lsb-release | awk -F= '{{print $2}}'` DEBIAN_VERSION=`cat /etc/debian_version` LSB_RELEASE=`lsb_release -cs` sudo /usr/sbin/groupadd hg sudo /usr/sbin/groupadd docker sudo /usr/sbin/useradd -g hg -G sudo,docker -d /home/hg -m -s /bin/bash hg sudo mkdir /home/hg/.ssh sudo cp ~/.ssh/authorized_keys /home/hg/.ssh/authorized_keys sudo chown -R hg:hg /home/hg/.ssh sudo chmod 700 /home/hg/.ssh sudo chmod 600 /home/hg/.ssh/authorized_keys cat << EOF | sudo tee /etc/sudoers.d/90-hg hg ALL=(ALL) NOPASSWD:ALL EOF sudo apt-get update sudo DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade # Install packages necessary to set up Docker Apt repo. sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install --no-install-recommends \ apt-transport-https \ gnupg cat > docker-apt-key << EOF -----BEGIN PGP PUBLIC KEY BLOCK----- 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 YT90qFF93M3v01BbxP+EIY2/9tiIPbrd =0YYh -----END PGP PUBLIC KEY BLOCK----- EOF sudo apt-key add docker-apt-key if [ "$LSB_RELEASE" = "stretch" ]; then cat << EOF | sudo tee -a /etc/apt/sources.list # Need backports for clang-format-6.0 deb http://deb.debian.org/debian stretch-backports main EOF fi if [ "$LSB_RELEASE" = "stretch" -o "$LSB_RELEASE" = "buster" ]; then cat << EOF | sudo tee -a /etc/apt/sources.list # Sources are useful if we want to compile things locally. deb-src http://deb.debian.org/debian $LSB_RELEASE main deb-src http://security.debian.org/debian-security $LSB_RELEASE/updates main deb-src http://deb.debian.org/debian $LSB_RELEASE-updates main deb-src http://deb.debian.org/debian $LSB_RELEASE-backports main deb [arch=amd64] https://download.docker.com/linux/debian $LSB_RELEASE stable EOF elif [ "$DISTRO" = "Ubuntu" ]; then cat << EOF | sudo tee -a /etc/apt/sources.list deb [arch=amd64] https://download.docker.com/linux/ubuntu $LSB_RELEASE stable EOF fi sudo apt-get update PACKAGES="\ awscli \ btrfs-progs \ build-essential \ bzr \ clang-format-6.0 \ cvs \ darcs \ debhelper \ devscripts \ docker-ce \ dpkg-dev \ dstat \ emacs \ gettext \ git \ htop \ iotop \ jfsutils \ libbz2-dev \ libexpat1-dev \ libffi-dev \ libgdbm-dev \ liblzma-dev \ libncurses5-dev \ libnss3-dev \ libreadline-dev \ libsqlite3-dev \ libssl-dev \ netbase \ ntfs-3g \ nvme-cli \ pyflakes3 \ pylint3 \ python3-boto3 \ python3-dev \ python3-docutils \ python3-fuzzywuzzy \ python3-pygments \ python3-vcr \ python3-venv \ rsync \ sqlite3 \ subversion \ tcl-dev \ tk-dev \ tla \ unzip \ uuid-dev \ vim \ virtualenv \ wget \ xfsprogs \ zip \ zlib1g-dev" if [ "LSB_RELEASE" = "stretch" ]; then PACKAGES="$PACKAGES linux-perf" elif [ "$DISTRO" = "Ubuntu" ]; then PACKAGES="$PACKAGES linux-tools-common" fi # Monotone only available in older releases. if [ "$LSB_RELEASE" = "stretch" -o "$LSB_RELEASE" = "xenial" ]; then PACKAGES="$PACKAGES monotone" fi sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install --no-install-recommends $PACKAGES # Create clang-format symlink so test harness finds it. sudo update-alternatives --install /usr/bin/clang-format clang-format \ /usr/bin/clang-format-6.0 1000 sudo mkdir /hgdev # Will be normalized to hg:hg later. sudo chown `whoami` /hgdev {install_rust} {install_pyoxidizer} cp requirements-*.txt /hgdev/ # Disable the pip version check because it uses the network and can # be annoying. cat << EOF | sudo tee -a /etc/pip.conf [global] disable-pip-version-check = True EOF {install_pythons} {bootstrap_virtualenv} /hgdev/venv-bootstrap/bin/hg clone https://www.mercurial-scm.org/repo/hg /hgdev/src # Mark the repo as non-publishing. cat >> /hgdev/src/.hg/hgrc << EOF [phases] publish = false EOF sudo chown -R hg:hg /hgdev '''.lstrip() .format( install_rust=INSTALL_RUST, install_pyoxidizer=INSTALL_PYOXIDIZER, install_pythons=INSTALL_PYTHONS, bootstrap_virtualenv=BOOTSTRAP_VIRTUALENV, ) .replace('\r\n', '\n') ) # Prepares /hgdev for operations. PREPARE_HGDEV = ''' #!/bin/bash set -e FS=$1 ensure_device() { if [ -z "${DEVICE}" ]; then echo "could not find block device to format" exit 1 fi } # Determine device to partition for extra filesystem. # If only 1 volume is present, it will be the root volume and # should be /dev/nvme0. If multiple volumes are present, the # root volume could be nvme0 or nvme1. Use whichever one doesn't have # a partition. if [ -e /dev/nvme1n1 ]; then if [ -e /dev/nvme0n1p1 ]; then DEVICE=/dev/nvme1n1 else DEVICE=/dev/nvme0n1 fi else DEVICE= fi sudo mkdir /hgwork if [ "${FS}" != "default" -a "${FS}" != "tmpfs" ]; then ensure_device echo "creating ${FS} filesystem on ${DEVICE}" fi if [ "${FS}" = "default" ]; then : elif [ "${FS}" = "btrfs" ]; then sudo mkfs.btrfs ${DEVICE} sudo mount ${DEVICE} /hgwork elif [ "${FS}" = "ext3" ]; then # lazy_journal_init speeds up filesystem creation at the expense of # integrity if things crash. We are an ephemeral instance, so we don't # care about integrity. sudo mkfs.ext3 -E lazy_journal_init=1 ${DEVICE} sudo mount ${DEVICE} /hgwork elif [ "${FS}" = "ext4" ]; then sudo mkfs.ext4 -E lazy_journal_init=1 ${DEVICE} sudo mount ${DEVICE} /hgwork elif [ "${FS}" = "jfs" ]; then sudo mkfs.jfs ${DEVICE} sudo mount ${DEVICE} /hgwork elif [ "${FS}" = "tmpfs" ]; then echo "creating tmpfs volume in /hgwork" sudo mount -t tmpfs -o size=1024M tmpfs /hgwork elif [ "${FS}" = "xfs" ]; then sudo mkfs.xfs ${DEVICE} sudo mount ${DEVICE} /hgwork else echo "unsupported filesystem: ${FS}" exit 1 fi echo "/hgwork ready" sudo chown hg:hg /hgwork mkdir /hgwork/tmp chown hg:hg /hgwork/tmp rsync -a /hgdev/src /hgwork/ '''.lstrip().replace( '\r\n', '\n' ) HG_UPDATE_CLEAN = ''' set -ex HG=/hgdev/venv-bootstrap/bin/hg cd /hgwork/src ${HG} --config extensions.purge= purge --all ${HG} update -C $1 ${HG} log -r . '''.lstrip().replace( '\r\n', '\n' ) def prepare_exec_environment(ssh_client, filesystem='default'): """Prepare an EC2 instance to execute things. The AMI has an ``/hgdev`` bootstrapped with various Python installs and a clone of the Mercurial repo. In EC2, EBS volumes launched from snapshots have wonky performance behavior. Notably, blocks have to be copied on first access, which makes volume I/O extremely slow on fresh volumes. Furthermore, we may want to run operations, tests, etc on alternative filesystems so we examine behavior on different filesystems. This function is used to facilitate executing operations on alternate volumes. """ sftp = ssh_client.open_sftp() with sftp.open('/hgdev/prepare-hgdev', 'wb') as fh: fh.write(PREPARE_HGDEV) fh.chmod(0o0777) command = 'sudo /hgdev/prepare-hgdev %s' % filesystem chan, stdin, stdout = exec_command(ssh_client, command) stdin.close() for line in stdout: print(line, end='') res = chan.recv_exit_status() if res: raise Exception('non-0 exit code updating working directory; %d' % res) def synchronize_hg( source_path: pathlib.Path, ec2_instance, revision: str = None ): """Synchronize a local Mercurial source path to remote EC2 instance.""" with tempfile.TemporaryDirectory() as temp_dir: temp_dir = pathlib.Path(temp_dir) ssh_dir = temp_dir / '.ssh' ssh_dir.mkdir() ssh_dir.chmod(0o0700) public_ip = ec2_instance.public_ip_address ssh_config = ssh_dir / 'config' with ssh_config.open('w', encoding='utf-8') as fh: fh.write('Host %s\n' % public_ip) fh.write(' User hg\n') fh.write(' StrictHostKeyChecking no\n') fh.write(' UserKnownHostsFile %s\n' % (ssh_dir / 'known_hosts')) fh.write(' IdentityFile %s\n' % ec2_instance.ssh_private_key_path) if not (source_path / '.hg').is_dir(): raise Exception( '%s is not a Mercurial repository; synchronization ' 'not yet supported' % source_path ) env = dict(os.environ) env['HGPLAIN'] = '1' env['HGENCODING'] = 'utf-8' hg_bin = source_path / 'hg' res = subprocess.run( ['python3', str(hg_bin), 'log', '-r', revision, '-T', '{node}'], cwd=str(source_path), env=env, check=True, capture_output=True, ) full_revision = res.stdout.decode('ascii') args = [ 'python3', str(hg_bin), '--config', 'ui.ssh=ssh -F %s' % ssh_config, '--config', 'ui.remotecmd=/hgdev/venv-bootstrap/bin/hg', # Also ensure .hgtags changes are present so auto version # calculation works. 'push', '-f', '-r', full_revision, '-r', 'file(.hgtags)', 'ssh://%s//hgwork/src' % public_ip, ] res = subprocess.run(args, cwd=str(source_path), env=env) # Allow 1 (no-op) to not trigger error. if res.returncode not in (0, 1): res.check_returncode() # TODO support synchronizing dirty working directory. sftp = ec2_instance.ssh_client.open_sftp() with sftp.open('/hgdev/hgup', 'wb') as fh: fh.write(HG_UPDATE_CLEAN) fh.chmod(0o0700) chan, stdin, stdout = exec_command( ec2_instance.ssh_client, '/hgdev/hgup %s' % full_revision ) stdin.close() for line in stdout: print(line, end='') res = chan.recv_exit_status() if res: raise Exception( 'non-0 exit code updating working directory; %d' % res ) def run_tests(ssh_client, python_version, test_flags=None): """Run tests on a remote Linux machine via an SSH client.""" test_flags = test_flags or [] print('running tests') if python_version == 'system3': python = '/usr/bin/python3' elif python_version.startswith('pypy'): python = '/hgdev/pyenv/shims/%s' % python_version else: python = '/hgdev/pyenv/shims/python%s' % python_version test_flags = shlex.join(test_flags) command = ( '/bin/sh -c "export TMPDIR=/hgwork/tmp; ' 'cd /hgwork/src/tests && %s run-tests.py %s"' % (python, test_flags) ) chan, stdin, stdout = exec_command(ssh_client, command) stdin.close() for line in stdout: print(line, end='') return chan.recv_exit_status() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/hgautomation/pypi.py0000664000175000017500000000104715060516737023245 0ustar00alpharealphare# pypi.py - Automation around PyPI # # Copyright 2019 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # no-check-code because Python 3 native. from twine.commands.upload import upload as twine_upload from twine.settings import Settings def upload(paths): """Upload files to PyPI. `paths` is an iterable of `pathlib.Path`. """ settings = Settings() twine_upload(settings, [str(p) for p in paths]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/hgautomation/ssh.py0000664000175000017500000000413315060516737023060 0ustar00alpharealphare# ssh.py - Interact with remote SSH servers # # Copyright 2019 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # no-check-code because Python 3 native. import socket import time import warnings from cryptography.utils import CryptographyDeprecationWarning import paramiko def wait_for_ssh(hostname, port, timeout=60, username=None, key_filename=None): """Wait for an SSH server to start on the specified host and port.""" class IgnoreHostKeyPolicy(paramiko.MissingHostKeyPolicy): def missing_host_key(self, client, hostname, key): return end_time = time.time() + timeout # paramiko triggers a CryptographyDeprecationWarning in the cryptography # package. Let's suppress with warnings.catch_warnings(): warnings.filterwarnings( 'ignore', category=CryptographyDeprecationWarning ) while True: client = paramiko.SSHClient() client.set_missing_host_key_policy(IgnoreHostKeyPolicy()) try: client.connect( hostname, port=port, username=username, key_filename=key_filename, timeout=5.0, allow_agent=False, look_for_keys=False, ) return client except OSError: pass except paramiko.AuthenticationException: raise except paramiko.SSHException: pass if time.time() >= end_time: raise Exception('Timeout reached waiting for SSH') time.sleep(1.0) def exec_command(client, command): """exec_command wrapper that combines stderr/stdout and returns channel""" chan = client.get_transport().open_session() chan.exec_command(command) chan.set_combine_stderr(True) stdin = chan.makefile('wb', -1) stdout = chan.makefile('r', -1) return chan, stdin, stdout ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/hgautomation/try_server.py0000664000175000017500000000465215060516737024475 0ustar00alpharealphare# try_server.py - Interact with Try server # # Copyright 2019 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # no-check-code because Python 3 native. import base64 import json import os import subprocess import tempfile from .aws import AWSConnection LAMBDA_FUNCTION = "ci-try-server-upload" def trigger_try(c: AWSConnection, rev="."): """Trigger a new Try run.""" lambda_client = c.session.client("lambda") cset, bundle = generate_bundle(rev=rev) payload = { "bundle": base64.b64encode(bundle).decode("utf-8"), "node": cset["node"], "branch": cset["branch"], "user": cset["user"], "message": cset["desc"], } print("resolved revision:") print("node: %s" % cset["node"]) print("branch: %s" % cset["branch"]) print("user: %s" % cset["user"]) print("desc: %s" % cset["desc"].splitlines()[0]) print() print("sending to Try...") res = lambda_client.invoke( FunctionName=LAMBDA_FUNCTION, InvocationType="RequestResponse", Payload=json.dumps(payload).encode("utf-8"), ) body = json.load(res["Payload"]) for message in body: print("remote: %s" % message) def generate_bundle(rev="."): """Generate a bundle suitable for use by the Try service. Returns a tuple of revision metadata and raw Mercurial bundle data. """ # `hg bundle` doesn't support streaming to stdout. So we use a temporary # file. path = None try: fd, path = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg") os.close(fd) args = [ "hg", "bundle", "--type", "gzip-v2", "--base", "public()", "--rev", rev, path, ] print("generating bundle...") subprocess.run(args, check=True) with open(path, "rb") as fh: bundle_data = fh.read() finally: if path: os.unlink(path) args = [ "hg", "log", "-r", rev, # We have to upload as JSON, so it won't matter if we emit binary # since we need to normalize to UTF-8. "-T", "json", ] res = subprocess.run(args, check=True, capture_output=True) return json.loads(res.stdout)[0], bundle_data ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/hgautomation/windows.py0000664000175000017500000004210015060516737023751 0ustar00alpharealphare# windows.py - Automation specific to Windows # # Copyright 2019 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # no-check-code because Python 3 native. import datetime import os import paramiko import pathlib import re import subprocess import tempfile from .pypi import upload as pypi_upload from .winrm import run_powershell HG_PURGE = r''' $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH" Set-Location C:\hgdev\src hg.exe --config extensions.purge= purge --all if ($LASTEXITCODE -ne 0) { throw "process exited non-0: $LASTEXITCODE" } Write-Output "purged Mercurial repo" ''' HG_UPDATE_CLEAN = r''' $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH" Set-Location C:\hgdev\src hg.exe --config extensions.purge= purge --all if ($LASTEXITCODE -ne 0) {{ throw "process exited non-0: $LASTEXITCODE" }} hg.exe update -C {revision} if ($LASTEXITCODE -ne 0) {{ throw "process exited non-0: $LASTEXITCODE" }} hg.exe log -r . Write-Output "updated Mercurial working directory to {revision}" '''.lstrip() BUILD_INNO_PYTHON3 = r''' $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH" $Env:RUSTUP_HOME = "C:\hgdev\rustup" $Env:CARGO_HOME = "C:\hgdev\cargo" Set-Location C:\hgdev\src C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --pyoxidizer-target {pyoxidizer_target} --version {version} if ($LASTEXITCODE -ne 0) {{ throw "process exited non-0: $LASTEXITCODE" }} ''' BUILD_WHEEL = r''' $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH" Set-Location C:\hgdev\src C:\hgdev\python{python_version}-{arch}\python.exe -m pip wheel --wheel-dir dist . if ($LASTEXITCODE -ne 0) {{ throw "process exited non-0: $LASTEXITCODE" }} ''' BUILD_WIX_PYTHON3 = r''' $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH" $Env:RUSTUP_HOME = "C:\hgdev\rustup" $Env:CARGO_HOME = "C:\hgdev\cargo" Set-Location C:\hgdev\src C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --pyoxidizer-target {pyoxidizer_target} --version {version} if ($LASTEXITCODE -ne 0) {{ throw "process exited non-0: $LASTEXITCODE" }} ''' RUN_TESTS = r''' C:\hgdev\MinGW\msys\1.0\bin\sh.exe --login -c "cd /c/hgdev/src/tests && /c/hgdev/{python_path}/python.exe run-tests.py {test_flags}" if ($LASTEXITCODE -ne 0) {{ throw "process exited non-0: $LASTEXITCODE" }} ''' WHEEL_FILENAME_PYTHON37_X86 = 'mercurial-{version}-cp37-cp37m-win32.whl' WHEEL_FILENAME_PYTHON37_X64 = 'mercurial-{version}-cp37-cp37m-win_amd64.whl' WHEEL_FILENAME_PYTHON38_X86 = 'mercurial-{version}-cp38-cp38-win32.whl' WHEEL_FILENAME_PYTHON38_X64 = 'mercurial-{version}-cp38-cp38-win_amd64.whl' WHEEL_FILENAME_PYTHON39_X86 = 'mercurial-{version}-cp39-cp39-win32.whl' WHEEL_FILENAME_PYTHON39_X64 = 'mercurial-{version}-cp39-cp39-win_amd64.whl' WHEEL_FILENAME_PYTHON310_X86 = 'mercurial-{version}-cp310-cp310-win32.whl' WHEEL_FILENAME_PYTHON310_X64 = 'mercurial-{version}-cp310-cp310-win_amd64.whl' EXE_FILENAME_PYTHON3_X86 = 'Mercurial-{version}-x86.exe' EXE_FILENAME_PYTHON3_X64 = 'Mercurial-{version}-x64.exe' MSI_FILENAME_PYTHON3_X86 = 'mercurial-{version}-x86.msi' MSI_FILENAME_PYTHON3_X64 = 'mercurial-{version}-x64.msi' MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows' X86_USER_AGENT_PATTERN = '.*Windows.*' X64_USER_AGENT_PATTERN = '.*Windows.*(WOW|x)64.*' # TODO remove Python version once Python 2 is dropped. EXE_PYTHON3_X86_DESCRIPTION = ( 'Mercurial {version} Inno Setup installer - x86 Windows (Python 3) ' '- does not require admin rights' ) EXE_PYTHON3_X64_DESCRIPTION = ( 'Mercurial {version} Inno Setup installer - x64 Windows (Python 3) ' '- does not require admin rights' ) MSI_PYTHON3_X86_DESCRIPTION = ( 'Mercurial {version} MSI installer - x86 Windows (Python 3) ' '- requires admin rights' ) MSI_PYTHON3_X64_DESCRIPTION = ( 'Mercurial {version} MSI installer - x64 Windows (Python 3) ' '- requires admin rights' ) def fix_authorized_keys_permissions(winrm_client, path): commands = [ '$ErrorActionPreference = "Stop"', 'Repair-AuthorizedKeyPermission -FilePath %s -Confirm:$false' % path, r'icacls %s /remove:g "NT Service\sshd"' % path, ] run_powershell(winrm_client, '\n'.join(commands)) def synchronize_hg(hg_repo: pathlib.Path, revision: str, ec2_instance): """Synchronize local Mercurial repo to remote EC2 instance.""" winrm_client = ec2_instance.winrm_client with tempfile.TemporaryDirectory() as temp_dir: temp_dir = pathlib.Path(temp_dir) ssh_dir = temp_dir / '.ssh' ssh_dir.mkdir() ssh_dir.chmod(0o0700) # Generate SSH key to use for communication. subprocess.run( [ 'ssh-keygen', '-t', 'rsa', '-b', '4096', '-N', '', '-f', str(ssh_dir / 'id_rsa'), ], check=True, capture_output=True, ) # Add it to ~/.ssh/authorized_keys on remote. # This assumes the file doesn't already exist. authorized_keys = r'c:\Users\Administrator\.ssh\authorized_keys' winrm_client.execute_cmd(r'mkdir c:\Users\Administrator\.ssh') winrm_client.copy(str(ssh_dir / 'id_rsa.pub'), authorized_keys) fix_authorized_keys_permissions(winrm_client, authorized_keys) public_ip = ec2_instance.public_ip_address ssh_config = temp_dir / '.ssh' / 'config' with open(ssh_config, 'w', encoding='utf-8') as fh: fh.write('Host %s\n' % public_ip) fh.write(' User Administrator\n') fh.write(' StrictHostKeyChecking no\n') fh.write(' UserKnownHostsFile %s\n' % (ssh_dir / 'known_hosts')) fh.write(' IdentityFile %s\n' % (ssh_dir / 'id_rsa')) if not (hg_repo / '.hg').is_dir(): raise Exception( '%s is not a Mercurial repository; ' 'synchronization not yet supported' % hg_repo ) env = dict(os.environ) env['HGPLAIN'] = '1' env['HGENCODING'] = 'utf-8' hg_bin = hg_repo / 'hg' res = subprocess.run( ['python3', str(hg_bin), 'log', '-r', revision, '-T', '{node}'], cwd=str(hg_repo), env=env, check=True, capture_output=True, ) full_revision = res.stdout.decode('ascii') args = [ 'python3', hg_bin, '--config', 'ui.ssh=ssh -F %s' % ssh_config, '--config', 'ui.remotecmd=c:/hgdev/venv-bootstrap/Scripts/hg.exe', # Also ensure .hgtags changes are present so auto version # calculation works. 'push', '-f', '-r', full_revision, '-r', 'file(.hgtags)', 'ssh://%s/c:/hgdev/src' % public_ip, ] res = subprocess.run(args, cwd=str(hg_repo), env=env) # Allow 1 (no-op) to not trigger error. if res.returncode not in (0, 1): res.check_returncode() run_powershell( winrm_client, HG_UPDATE_CLEAN.format(revision=full_revision) ) # TODO detect dirty local working directory and synchronize accordingly. def purge_hg(winrm_client): """Purge the Mercurial source repository on an EC2 instance.""" run_powershell(winrm_client, HG_PURGE) def find_latest_dist(winrm_client, pattern): """Find path to newest file in dist/ directory matching a pattern.""" res = winrm_client.execute_ps( r'$v = Get-ChildItem -Path C:\hgdev\src\dist -Filter "%s" ' '| Sort-Object LastWriteTime -Descending ' '| Select-Object -First 1\n' '$v.name' % pattern ) return res[0] def copy_latest_dist(winrm_client, pattern, dest_path): """Copy latest file matching pattern in dist/ directory. Given a WinRM client and a file pattern, find the latest file on the remote matching that pattern and copy it to the ``dest_path`` directory on the local machine. """ latest = find_latest_dist(winrm_client, pattern) source = r'C:\hgdev\src\dist\%s' % latest dest = dest_path / latest print('copying %s to %s' % (source, dest)) winrm_client.fetch(source, str(dest)) def build_inno_installer( winrm_client, arch: str, dest_path: pathlib.Path, version=None, ): """Build the Inno Setup installer on a remote machine. Using a WinRM client, remote commands are executed to build a Mercurial Inno Setup installer. """ print('building Inno Setup installer for %s' % arch) # TODO fix this limitation in packaging code if not version: raise Exception("version string is required when building for Python 3") if arch == "x86": target_triple = "i686-pc-windows-msvc" elif arch == "x64": target_triple = "x86_64-pc-windows-msvc" else: raise Exception("unhandled arch: %s" % arch) ps = BUILD_INNO_PYTHON3.format( pyoxidizer_target=target_triple, version=version, ) run_powershell(winrm_client, ps) copy_latest_dist(winrm_client, '*.exe', dest_path) def build_wheel( winrm_client, python_version: str, arch: str, dest_path: pathlib.Path ): """Build Python wheels on a remote machine. Using a WinRM client, remote commands are executed to build a Python wheel for Mercurial. """ print('Building Windows wheel for Python %s %s' % (python_version, arch)) ps = BUILD_WHEEL.format( python_version=python_version.replace(".", ""), arch=arch ) run_powershell(winrm_client, ps) copy_latest_dist(winrm_client, '*.whl', dest_path) def build_wix_installer( winrm_client, arch: str, dest_path: pathlib.Path, version=None, ): """Build the WiX installer on a remote machine. Using a WinRM client, remote commands are executed to build a WiX installer. """ print('Building WiX installer for %s' % arch) # TODO fix this limitation in packaging code if not version: raise Exception("version string is required when building for Python 3") if arch == "x86": target_triple = "i686-pc-windows-msvc" elif arch == "x64": target_triple = "x86_64-pc-windows-msvc" else: raise Exception("unhandled arch: %s" % arch) ps = BUILD_WIX_PYTHON3.format( pyoxidizer_target=target_triple, version=version, ) run_powershell(winrm_client, ps) copy_latest_dist(winrm_client, '*.msi', dest_path) def run_tests(winrm_client, python_version, arch, test_flags=''): """Run tests on a remote Windows machine. ``python_version`` is a ``X.Y`` string like ``2.7`` or ``3.7``. ``arch`` is ``x86`` or ``x64``. ``test_flags`` is a str representing extra arguments to pass to ``run-tests.py``. """ if not re.match(r'\d\.\d', python_version): raise ValueError( r'python_version must be \d.\d; got %s' % python_version ) if arch not in ('x86', 'x64'): raise ValueError('arch must be x86 or x64; got %s' % arch) python_path = 'python%s-%s' % (python_version.replace('.', ''), arch) ps = RUN_TESTS.format( python_path=python_path, test_flags=test_flags or '', ) run_powershell(winrm_client, ps) def resolve_wheel_artifacts(dist_path: pathlib.Path, version: str): return ( dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version), dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version), dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version), dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version), dist_path / WHEEL_FILENAME_PYTHON39_X86.format(version=version), dist_path / WHEEL_FILENAME_PYTHON39_X64.format(version=version), dist_path / WHEEL_FILENAME_PYTHON310_X86.format(version=version), dist_path / WHEEL_FILENAME_PYTHON310_X64.format(version=version), ) def resolve_all_artifacts(dist_path: pathlib.Path, version: str): return ( dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version), dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version), dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version), dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version), dist_path / WHEEL_FILENAME_PYTHON39_X86.format(version=version), dist_path / WHEEL_FILENAME_PYTHON39_X64.format(version=version), dist_path / WHEEL_FILENAME_PYTHON310_X86.format(version=version), dist_path / WHEEL_FILENAME_PYTHON310_X64.format(version=version), dist_path / EXE_FILENAME_PYTHON3_X86.format(version=version), dist_path / EXE_FILENAME_PYTHON3_X64.format(version=version), dist_path / MSI_FILENAME_PYTHON3_X86.format(version=version), dist_path / MSI_FILENAME_PYTHON3_X64.format(version=version), ) def generate_latest_dat(version: str): python3_x86_exe_filename = EXE_FILENAME_PYTHON3_X86.format(version=version) python3_x64_exe_filename = EXE_FILENAME_PYTHON3_X64.format(version=version) python3_x86_msi_filename = MSI_FILENAME_PYTHON3_X86.format(version=version) python3_x64_msi_filename = MSI_FILENAME_PYTHON3_X64.format(version=version) entries = ( ( '10', version, X86_USER_AGENT_PATTERN, '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_exe_filename), EXE_PYTHON3_X86_DESCRIPTION.format(version=version), ), ( '10', version, X64_USER_AGENT_PATTERN, '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_exe_filename), EXE_PYTHON3_X64_DESCRIPTION.format(version=version), ), ( '10', version, X86_USER_AGENT_PATTERN, '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_msi_filename), MSI_PYTHON3_X86_DESCRIPTION.format(version=version), ), ( '10', version, X64_USER_AGENT_PATTERN, '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_msi_filename), MSI_PYTHON3_X64_DESCRIPTION.format(version=version), ), ) lines = ['\t'.join(e) for e in entries] return '\n'.join(lines) + '\n' def publish_artifacts_pypi(dist_path: pathlib.Path, version: str): """Publish Windows release artifacts to PyPI.""" wheel_paths = resolve_wheel_artifacts(dist_path, version) for p in wheel_paths: if not p.exists(): raise Exception('%s not found' % p) print('uploading wheels to PyPI (you may be prompted for credentials)') pypi_upload(wheel_paths) def publish_artifacts_mercurial_scm_org( dist_path: pathlib.Path, version: str, ssh_username=None ): """Publish Windows release artifacts to mercurial-scm.org.""" all_paths = resolve_all_artifacts(dist_path, version) for p in all_paths: if not p.exists(): raise Exception('%s not found' % p) client = paramiko.SSHClient() client.load_system_host_keys() # We assume the system SSH configuration knows how to connect. print('connecting to mercurial-scm.org via ssh...') try: client.connect('mercurial-scm.org', username=ssh_username) except paramiko.AuthenticationException: print('error authenticating; is an SSH key available in an SSH agent?') raise print('SSH connection established') print('opening SFTP client...') sftp = client.open_sftp() print('SFTP client obtained') for p in all_paths: dest_path = '/var/www/release/windows/%s' % p.name print('uploading %s to %s' % (p, dest_path)) with p.open('rb') as fh: data = fh.read() with sftp.open(dest_path, 'wb') as fh: fh.write(data) fh.chmod(0o0664) latest_dat_path = '/var/www/release/windows/latest.dat' now = datetime.datetime.utcnow() backup_path = dist_path / ( 'latest-windows-%s.dat' % now.strftime('%Y%m%dT%H%M%S') ) print('backing up %s to %s' % (latest_dat_path, backup_path)) with sftp.open(latest_dat_path, 'rb') as fh: latest_dat_old = fh.read() with backup_path.open('wb') as fh: fh.write(latest_dat_old) print('writing %s with content:' % latest_dat_path) latest_dat_content = generate_latest_dat(version) print(latest_dat_content) with sftp.open(latest_dat_path, 'wb') as fh: fh.write(latest_dat_content.encode('ascii')) def publish_artifacts( dist_path: pathlib.Path, version: str, pypi=True, mercurial_scm_org=True, ssh_username=None, ): """Publish Windows release artifacts. Files are found in `dist_path`. We will look for files with version string `version`. `pypi` controls whether we upload to PyPI. `mercurial_scm_org` controls whether we upload to mercurial-scm.org. """ if pypi: publish_artifacts_pypi(dist_path, version) if mercurial_scm_org: publish_artifacts_mercurial_scm_org( dist_path, version, ssh_username=ssh_username ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/hgautomation/winrm.py0000664000175000017500000000404115060516737023415 0ustar00alpharealphare# winrm.py - Interact with Windows Remote Management (WinRM) # # Copyright 2019 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # no-check-code because Python 3 native. import logging import pprint import time from pypsrp.client import Client from pypsrp.powershell import ( PowerShell, PSInvocationState, RunspacePool, ) import requests.exceptions logger = logging.getLogger(__name__) def wait_for_winrm(host, username, password, timeout=180, ssl=False): """Wait for the Windows Remoting (WinRM) service to become available. Returns a ``psrpclient.Client`` instance. """ end_time = time.time() + timeout while True: try: client = Client( host, username=username, password=password, ssl=ssl, connection_timeout=5, ) client.execute_ps("Write-Host 'Hello, World!'") return client except requests.exceptions.ConnectionError: if time.time() >= end_time: raise time.sleep(1) def format_object(o): if isinstance(o, str): return o try: o = str(o) except (AttributeError, TypeError): o = pprint.pformat(o.extended_properties) return o def run_powershell(client, script): with RunspacePool(client.wsman) as pool: ps = PowerShell(pool) ps.add_script(script) ps.begin_invoke() while ps.state == PSInvocationState.RUNNING: ps.poll_invoke() for o in ps.output: print(format_object(o)) ps.output[:] = [] ps.end_invoke() for o in ps.output: print(format_object(o)) if ps.state == PSInvocationState.FAILED: raise Exception( 'PowerShell execution failed: %s' % ' '.join(map(format_object, ps.streams.error)) ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/linux-requirements-py3.txt0000664000175000017500000005256015060516737024353 0ustar00alpharealphare# # This file is autogenerated by pip-compile # To update, run: # # pip-compile --generate-hashes --output-file=contrib/automation/linux-requirements-py3.txt contrib/automation/linux-requirements.txt.in # appdirs==1.4.4 \ --hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41 \ --hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128 # via black astroid==2.5.6 \ --hash=sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e \ --hash=sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975 # via pylint attrs==21.1.0 \ --hash=sha256:3901be1cb7c2a780f14668691474d9252c070a756be0a9ead98cfeabfa11aeb8 \ --hash=sha256:8ee1e5f5a1afc5b19bdfae4fdf0c35ed324074bdce3500c939842c8f818645d9 # via black black==19.10b0 ; python_version >= "3.8" and platform_python_implementation != "PyPy" \ --hash=sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b \ --hash=sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539 # via -r contrib/automation/linux-requirements.txt.in click==7.1.2 \ --hash=sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a \ --hash=sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc # via black docutils==0.17.1 \ --hash=sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125 \ --hash=sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61 # via -r contrib/automation/linux-requirements.txt.in fuzzywuzzy==0.18.0 \ --hash=sha256:45016e92264780e58972dca1b3d939ac864b78437422beecebb3095f8efd00e8 \ --hash=sha256:928244b28db720d1e0ee7587acf660ea49d7e4c632569cad4f1cd7e68a5f0993 # via -r contrib/automation/linux-requirements.txt.in idna==3.1 \ --hash=sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16 \ --hash=sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1 # via yarl isort==4.3.21 \ --hash=sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1 \ --hash=sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd # via # -r contrib/automation/linux-requirements.txt.in # pylint lazy-object-proxy==1.6.0 \ --hash=sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653 \ --hash=sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61 \ --hash=sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2 \ --hash=sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837 \ --hash=sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3 \ --hash=sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43 \ --hash=sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726 \ --hash=sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3 \ --hash=sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587 \ --hash=sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8 \ --hash=sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a \ --hash=sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd \ --hash=sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f \ --hash=sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad \ --hash=sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4 \ --hash=sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b \ --hash=sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf \ --hash=sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981 \ --hash=sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741 \ --hash=sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e \ --hash=sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93 \ --hash=sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b # via astroid mccabe==0.6.1 \ --hash=sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42 \ --hash=sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f # via pylint multidict==5.1.0 \ --hash=sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a \ --hash=sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93 \ --hash=sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632 \ --hash=sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656 \ --hash=sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79 \ --hash=sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7 \ --hash=sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d \ --hash=sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5 \ --hash=sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224 \ --hash=sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26 \ --hash=sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea \ --hash=sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348 \ --hash=sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6 \ --hash=sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76 \ --hash=sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1 \ --hash=sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f \ --hash=sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952 \ --hash=sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a \ --hash=sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37 \ --hash=sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9 \ --hash=sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359 \ --hash=sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8 \ --hash=sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da \ --hash=sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3 \ --hash=sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d \ --hash=sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf \ --hash=sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841 \ --hash=sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d \ --hash=sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93 \ --hash=sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f \ --hash=sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647 \ --hash=sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635 \ --hash=sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456 \ --hash=sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda \ --hash=sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5 \ --hash=sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281 \ --hash=sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80 # via yarl pathspec==0.8.1 \ --hash=sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd \ --hash=sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d # via black pyflakes==2.3.1 \ --hash=sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3 \ --hash=sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db # via -r contrib/automation/linux-requirements.txt.in pygments==2.9.0 \ --hash=sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f \ --hash=sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e # via -r contrib/automation/linux-requirements.txt.in pylint==2.8.2 \ --hash=sha256:586d8fa9b1891f4b725f587ef267abe2a1bad89d6b184520c7f07a253dd6e217 \ --hash=sha256:f7e2072654a6b6afdf5e2fb38147d3e2d2d43c89f648637baab63e026481279b # via -r contrib/automation/linux-requirements.txt.in python-levenshtein==0.12.2 \ --hash=sha256:dc2395fbd148a1ab31090dd113c366695934b9e85fe5a4b2a032745efd0346f6 # via -r contrib/automation/linux-requirements.txt.in pyyaml==5.4.1 \ --hash=sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf \ --hash=sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696 \ --hash=sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393 \ --hash=sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77 \ --hash=sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922 \ --hash=sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5 \ --hash=sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8 \ --hash=sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10 \ --hash=sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc \ --hash=sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018 \ --hash=sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e \ --hash=sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253 \ --hash=sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347 \ --hash=sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183 \ --hash=sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541 \ --hash=sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb \ --hash=sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185 \ --hash=sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc \ --hash=sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db \ --hash=sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa \ --hash=sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46 \ --hash=sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122 \ --hash=sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b \ --hash=sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63 \ --hash=sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df \ --hash=sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc \ --hash=sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247 \ --hash=sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6 \ --hash=sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0 # via vcrpy regex==2021.4.4 \ --hash=sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5 \ --hash=sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79 \ --hash=sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31 \ --hash=sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500 \ --hash=sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11 \ --hash=sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14 \ --hash=sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3 \ --hash=sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439 \ --hash=sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c \ --hash=sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82 \ --hash=sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711 \ --hash=sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093 \ --hash=sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a \ --hash=sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb \ --hash=sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8 \ --hash=sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17 \ --hash=sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000 \ --hash=sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d \ --hash=sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480 \ --hash=sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc \ --hash=sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0 \ --hash=sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9 \ --hash=sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765 \ --hash=sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e \ --hash=sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a \ --hash=sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07 \ --hash=sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f \ --hash=sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac \ --hash=sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7 \ --hash=sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed \ --hash=sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968 \ --hash=sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7 \ --hash=sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2 \ --hash=sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4 \ --hash=sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87 \ --hash=sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8 \ --hash=sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10 \ --hash=sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29 \ --hash=sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605 \ --hash=sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6 \ --hash=sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042 # via black six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # via vcrpy toml==0.10.2 \ --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f # via # black # pylint typed-ast==1.4.3 ; python_version >= "3.0" and platform_python_implementation != "PyPy" \ --hash=sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace \ --hash=sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff \ --hash=sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266 \ --hash=sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528 \ --hash=sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6 \ --hash=sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808 \ --hash=sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4 \ --hash=sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363 \ --hash=sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341 \ --hash=sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04 \ --hash=sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41 \ --hash=sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e \ --hash=sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3 \ --hash=sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899 \ --hash=sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805 \ --hash=sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c \ --hash=sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c \ --hash=sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39 \ --hash=sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a \ --hash=sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3 \ --hash=sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7 \ --hash=sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f \ --hash=sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075 \ --hash=sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0 \ --hash=sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40 \ --hash=sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428 \ --hash=sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927 \ --hash=sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3 \ --hash=sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f \ --hash=sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65 # via # -r contrib/automation/linux-requirements.txt.in # astroid # black typing-extensions==3.10.0.0 \ --hash=sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497 \ --hash=sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342 \ --hash=sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84 # via yarl vcrpy==4.1.1 \ --hash=sha256:12c3fcdae7b88ecf11fc0d3e6d77586549d4575a2ceee18e82eee75c1f626162 \ --hash=sha256:57095bf22fc0a2d99ee9674cdafebed0f3ba763018582450706f7d3a74fff599 # via -r contrib/automation/linux-requirements.txt.in wrapt==1.12.1 \ --hash=sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7 # via # astroid # vcrpy yarl==1.6.3 \ --hash=sha256:00d7ad91b6583602eb9c1d085a2cf281ada267e9a197e8b7cae487dadbfa293e \ --hash=sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434 \ --hash=sha256:15263c3b0b47968c1d90daa89f21fcc889bb4b1aac5555580d74565de6836366 \ --hash=sha256:2ce4c621d21326a4a5500c25031e102af589edb50c09b321049e388b3934eec3 \ --hash=sha256:31ede6e8c4329fb81c86706ba8f6bf661a924b53ba191b27aa5fcee5714d18ec \ --hash=sha256:324ba3d3c6fee56e2e0b0d09bf5c73824b9f08234339d2b788af65e60040c959 \ --hash=sha256:329412812ecfc94a57cd37c9d547579510a9e83c516bc069470db5f75684629e \ --hash=sha256:4736eaee5626db8d9cda9eb5282028cc834e2aeb194e0d8b50217d707e98bb5c \ --hash=sha256:4953fb0b4fdb7e08b2f3b3be80a00d28c5c8a2056bb066169de00e6501b986b6 \ --hash=sha256:4c5bcfc3ed226bf6419f7a33982fb4b8ec2e45785a0561eb99274ebbf09fdd6a \ --hash=sha256:547f7665ad50fa8563150ed079f8e805e63dd85def6674c97efd78eed6c224a6 \ --hash=sha256:5b883e458058f8d6099e4420f0cc2567989032b5f34b271c0827de9f1079a424 \ --hash=sha256:63f90b20ca654b3ecc7a8d62c03ffa46999595f0167d6450fa8383bab252987e \ --hash=sha256:68dc568889b1c13f1e4745c96b931cc94fdd0defe92a72c2b8ce01091b22e35f \ --hash=sha256:69ee97c71fee1f63d04c945f56d5d726483c4762845400a6795a3b75d56b6c50 \ --hash=sha256:6d6283d8e0631b617edf0fd726353cb76630b83a089a40933043894e7f6721e2 \ --hash=sha256:72a660bdd24497e3e84f5519e57a9ee9220b6f3ac4d45056961bf22838ce20cc \ --hash=sha256:73494d5b71099ae8cb8754f1df131c11d433b387efab7b51849e7e1e851f07a4 \ --hash=sha256:7356644cbed76119d0b6bd32ffba704d30d747e0c217109d7979a7bc36c4d970 \ --hash=sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10 \ --hash=sha256:8aa3decd5e0e852dc68335abf5478a518b41bf2ab2f330fe44916399efedfae0 \ --hash=sha256:97b5bdc450d63c3ba30a127d018b866ea94e65655efaf889ebeabc20f7d12406 \ --hash=sha256:9ede61b0854e267fd565e7527e2f2eb3ef8858b301319be0604177690e1a3896 \ --hash=sha256:b2e9a456c121e26d13c29251f8267541bd75e6a1ccf9e859179701c36a078643 \ --hash=sha256:b5dfc9a40c198334f4f3f55880ecf910adebdcb2a0b9a9c23c9345faa9185721 \ --hash=sha256:bafb450deef6861815ed579c7a6113a879a6ef58aed4c3a4be54400ae8871478 \ --hash=sha256:c49ff66d479d38ab863c50f7bb27dee97c6627c5fe60697de15529da9c3de724 \ --hash=sha256:ce3beb46a72d9f2190f9e1027886bfc513702d748047b548b05dab7dfb584d2e \ --hash=sha256:d26608cf178efb8faa5ff0f2d2e77c208f471c5a3709e577a7b3fd0445703ac8 \ --hash=sha256:d597767fcd2c3dc49d6eea360c458b65643d1e4dbed91361cf5e36e53c1f8c96 \ --hash=sha256:d5c32c82990e4ac4d8150fd7652b972216b204de4e83a122546dce571c1bdf25 \ --hash=sha256:d8d07d102f17b68966e2de0e07bfd6e139c7c02ef06d3a0f8d2f0f055e13bb76 \ --hash=sha256:e46fba844f4895b36f4c398c5af062a9808d1f26b2999c58909517384d5deda2 \ --hash=sha256:e6b5460dc5ad42ad2b36cca524491dfcaffbfd9c8df50508bddc354e787b8dc2 \ --hash=sha256:f040bcc6725c821a4c0665f3aa96a4d0805a7aaf2caf266d256b8ed71b9f041c \ --hash=sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a \ --hash=sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71 # via vcrpy # WARNING: The following packages were not pinned, but pip requires them to be # pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag. # setuptools ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/linux-requirements.txt.in0000664000175000017500000000115615060516737024242 0ustar00alpharealphare# black pulls in typed-ast, which doesn't install on PyPy. black==19.10b0 ; python_version >= '3.8' and platform_python_implementation != 'PyPy' # Bazaar doesn't work with Python 3 nor PyPy. bzr ; python_version <= '2.7' and platform_python_implementation == 'CPython' docutils fuzzywuzzy # isort 5.0 drops support for Python 3.5. We can remove this line when we # drop support for 3.5. isort < 5.0 pyflakes pygments pylint # Needed to avoid warnings from fuzzywuzzy. python-Levenshtein # typed-ast dependency doesn't install on PyPy. typed-ast ; python_version >= '3.8' and platform_python_implementation != 'PyPy' vcrpy ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/requirements.txt0000664000175000017500000003714715060516737022511 0ustar00alpharealphare# # This file is autogenerated by pip-compile with python 3.10 # To update, run: # # pip-compile --generate-hashes --output-file=contrib/automation/requirements.txt contrib/automation/requirements.txt.in # bcrypt==3.2.2 \ --hash=sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521 \ --hash=sha256:433c410c2177057705da2a9f2cd01dd157493b2a7ac14c8593a16b3dab6b6bfb \ --hash=sha256:4e029cef560967fb0cf4a802bcf4d562d3d6b4b1bf81de5ec1abbe0f1adb027e \ --hash=sha256:61bae49580dce88095d669226d5076d0b9d927754cedbdf76c6c9f5099ad6f26 \ --hash=sha256:6d2cb9d969bfca5bc08e45864137276e4c3d3d7de2b162171def3d188bf9d34a \ --hash=sha256:7180d98a96f00b1050e93f5b0f556e658605dd9f524d0b0e68ae7944673f525e \ --hash=sha256:7d9ba2e41e330d2af4af6b1b6ec9e6128e91343d0b4afb9282e54e5508f31baa \ --hash=sha256:7ff2069240c6bbe49109fe84ca80508773a904f5a8cb960e02a977f7f519b129 \ --hash=sha256:88273d806ab3a50d06bc6a2fc7c87d737dd669b76ad955f449c43095389bc8fb \ --hash=sha256:a2c46100e315c3a5b90fdc53e429c006c5f962529bc27e1dfd656292c20ccc40 \ --hash=sha256:cd43303d6b8a165c29ec6756afd169faba9396a9472cdff753fe9f19b96ce2fa # via paramiko bleach==5.0.0 \ --hash=sha256:08a1fe86d253b5c88c92cc3d810fd8048a16d15762e1e5b74d502256e5926aa1 \ --hash=sha256:c6d6cc054bdc9c83b48b8083e236e5f00f238428666d2ce2e083eaa5fd568565 # via readme-renderer boto3==1.22.7 \ --hash=sha256:4dc0df36c3465ff0d586017da68b0152123695f38f30ad98fed7185e59298d2c \ --hash=sha256:de4fa49ca1cbc93313144e93e6d0997cbb61c8cca91f3418b4e3646dc215f441 # via -r contrib/automation/requirements.txt.in botocore==1.25.7 \ --hash=sha256:190361776d96323ff401b976175f76172acf7ebbe3efbb19c4c6f9800a9ad6b6 \ --hash=sha256:83da857c12fff5cf4c1a64afaa72a28ff5bef929a2834ec4ed5b0b674f88fd0e # via # boto3 # s3transfer certifi==2021.10.8 \ --hash=sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872 \ --hash=sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569 # via requests cffi==1.15.0 \ --hash=sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3 \ --hash=sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2 \ --hash=sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636 \ --hash=sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20 \ --hash=sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728 \ --hash=sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27 \ --hash=sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66 \ --hash=sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443 \ --hash=sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0 \ --hash=sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7 \ --hash=sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39 \ --hash=sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605 \ --hash=sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a \ --hash=sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37 \ --hash=sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029 \ --hash=sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139 \ --hash=sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc \ --hash=sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df \ --hash=sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14 \ --hash=sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880 \ --hash=sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2 \ --hash=sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a \ --hash=sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e \ --hash=sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474 \ --hash=sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024 \ --hash=sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8 \ --hash=sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0 \ --hash=sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e \ --hash=sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a \ --hash=sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e \ --hash=sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032 \ --hash=sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6 \ --hash=sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e \ --hash=sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b \ --hash=sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e \ --hash=sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954 \ --hash=sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962 \ --hash=sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c \ --hash=sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4 \ --hash=sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55 \ --hash=sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962 \ --hash=sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023 \ --hash=sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c \ --hash=sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6 \ --hash=sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8 \ --hash=sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382 \ --hash=sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7 \ --hash=sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc \ --hash=sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997 \ --hash=sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796 # via # bcrypt # cryptography # pynacl charset-normalizer==2.0.12 \ --hash=sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597 \ --hash=sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df # via requests commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 # via rich cryptography==37.0.2 \ --hash=sha256:093cb351031656d3ee2f4fa1be579a8c69c754cf874206be1d4cf3b542042804 \ --hash=sha256:0cc20f655157d4cfc7bada909dc5cc228211b075ba8407c46467f63597c78178 \ --hash=sha256:1b9362d34363f2c71b7853f6251219298124aa4cc2075ae2932e64c91a3e2717 \ --hash=sha256:1f3bfbd611db5cb58ca82f3deb35e83af34bb8cf06043fa61500157d50a70982 \ --hash=sha256:2bd1096476aaac820426239ab534b636c77d71af66c547b9ddcd76eb9c79e004 \ --hash=sha256:31fe38d14d2e5f787e0aecef831457da6cec68e0bb09a35835b0b44ae8b988fe \ --hash=sha256:3b8398b3d0efc420e777c40c16764d6870bcef2eb383df9c6dbb9ffe12c64452 \ --hash=sha256:3c81599befb4d4f3d7648ed3217e00d21a9341a9a688ecdd615ff72ffbed7336 \ --hash=sha256:419c57d7b63f5ec38b1199a9521d77d7d1754eb97827bbb773162073ccd8c8d4 \ --hash=sha256:46f4c544f6557a2fefa7ac8ac7d1b17bf9b647bd20b16decc8fbcab7117fbc15 \ --hash=sha256:471e0d70201c069f74c837983189949aa0d24bb2d751b57e26e3761f2f782b8d \ --hash=sha256:59b281eab51e1b6b6afa525af2bd93c16d49358404f814fe2c2410058623928c \ --hash=sha256:731c8abd27693323b348518ed0e0705713a36d79fdbd969ad968fbef0979a7e0 \ --hash=sha256:95e590dd70642eb2079d280420a888190aa040ad20f19ec8c6e097e38aa29e06 \ --hash=sha256:a68254dd88021f24a68b613d8c51d5c5e74d735878b9e32cc0adf19d1f10aaf9 \ --hash=sha256:a7d5137e556cc0ea418dca6186deabe9129cee318618eb1ffecbd35bee55ddc1 \ --hash=sha256:aeaba7b5e756ea52c8861c133c596afe93dd716cbcacae23b80bc238202dc023 \ --hash=sha256:dc26bb134452081859aa21d4990474ddb7e863aa39e60d1592800a8865a702de \ --hash=sha256:e53258e69874a306fcecb88b7534d61820db8a98655662a3dd2ec7f1afd9132f \ --hash=sha256:ef15c2df7656763b4ff20a9bc4381d8352e6640cfeb95c2972c38ef508e75181 \ --hash=sha256:f224ad253cc9cea7568f49077007d2263efa57396a2f2f78114066fd54b5c68e \ --hash=sha256:f8ec91983e638a9bcd75b39f1396e5c0dc2330cbd9ce4accefe68717e6779e0a # via # paramiko # pypsrp # pyspnego # secretstorage docutils==0.18.1 \ --hash=sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c \ --hash=sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06 # via readme-renderer idna==3.3 \ --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d # via requests importlib-metadata==4.11.3 \ --hash=sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6 \ --hash=sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539 # via # keyring # twine jeepney==0.8.0 \ --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 # via # keyring # secretstorage jmespath==1.0.0 \ --hash=sha256:a490e280edd1f57d6de88636992d05b71e97d69a26a19f058ecf7d304474bf5e \ --hash=sha256:e8dcd576ed616f14ec02eed0005c85973b5890083313860136657e24784e4c04 # via # boto3 # botocore keyring==23.5.0 \ --hash=sha256:9012508e141a80bd1c0b6778d5c610dd9f8c464d75ac6774248500503f972fb9 \ --hash=sha256:b0d28928ac3ec8e42ef4cc227822647a19f1d544f21f96457965dc01cf555261 # via twine paramiko==2.10.4 \ --hash=sha256:3c9ed6084f4b671ab66dc3c729092d32d96c3258f1426071301cb33654b09027 \ --hash=sha256:3d2e650b6812ce6d160abff701d6ef4434ec97934b13e95cf1ad3da70ffb5c58 # via -r contrib/automation/requirements.txt.in pkginfo==1.8.2 \ --hash=sha256:542e0d0b6750e2e21c20179803e40ab50598d8066d51097a0e382cba9eb02bff \ --hash=sha256:c24c487c6a7f72c66e816ab1796b96ac6c3d14d49338293d2141664330b55ffc # via twine pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 # via cffi pygments==2.12.0 \ --hash=sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb \ --hash=sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519 # via # readme-renderer # rich pynacl==1.5.0 \ --hash=sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858 \ --hash=sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d \ --hash=sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93 \ --hash=sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1 \ --hash=sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92 \ --hash=sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff \ --hash=sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba \ --hash=sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394 \ --hash=sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b \ --hash=sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543 # via paramiko pypsrp==0.8.1 \ --hash=sha256:0101345ceb415896fed9b056e7b77d65312089ddc73c4286247ccf1859d4bc4d \ --hash=sha256:f5500acd11dfe742d51b7fbb61321ba721038a300d67763dc52babe709db65e7 # via -r contrib/automation/requirements.txt.in pyspnego==0.5.2 \ --hash=sha256:1fed228edc4b1730844da8237b90489be28c55681cf3934cd04fceb2253e55bf \ --hash=sha256:25fbc90fc6bd16881480316739bab820cc91364765e46340da17f861f89691f1 \ --hash=sha256:274b3a2d37e45ad4567bc5754be04b5fefad3f7cdea7d205f739d8a26b5a9189 \ --hash=sha256:36db7ec38023a23a545114dfd23825639571f135c72fb4b13a1ed559a0a4d93c \ --hash=sha256:3b1ff3c1d5588b66f8e4ebafa3079a7bf0bdcc6fb144b944c5a101e688a5a280 \ --hash=sha256:4b9bda51bd964f40322aa1b33dcfc5d68f23b0680b4b5158175f2e9a04119aa9 \ --hash=sha256:5d6d91e35ee63a5de30eb70716bf25274bf16c2c472b046dd21fad60fe63b0b6 \ --hash=sha256:7562bc640bf402bb2849f325b0bb41260bd2c0cb06e38b9a8c6f7021b452c873 \ --hash=sha256:9c5bdb9f0207e2ce9e5410ee2205bf016755712018534c711ae6c1daff7fa7db \ --hash=sha256:a5c135d20819db3c48f65054d648317f369a61b7b22dc17b9e5ec9c0169541a0 \ --hash=sha256:bd95633e7dce69e267579bdbe992fc081a14310236b4e84c3d179b1cf6439ca5 \ --hash=sha256:eb41b970dbda0dfe07b1da6fc83fe9f534a66d8dea38c06c0155377697407d9a # via pypsrp python-dateutil==2.8.2 \ --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 # via botocore readme-renderer==35.0 \ --hash=sha256:73b84905d091c31f36e50b4ae05ae2acead661f6a09a9abb4df7d2ddcdb6a698 \ --hash=sha256:a727999acfc222fc21d82a12ed48c957c4989785e5865807c65a487d21677497 # via twine requests==2.27.1 \ --hash=sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61 \ --hash=sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d # via # pypsrp # requests-toolbelt # twine requests-toolbelt==0.9.1 \ --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \ --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0 # via twine rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c # via twine rich==12.3.0 \ --hash=sha256:0eb63013630c6ee1237e0e395d51cb23513de6b5531235e33889e8842bdf3a6f \ --hash=sha256:7e8700cda776337036a712ff0495b04052fb5f957c7dfb8df997f88350044b64 # via twine s3transfer==0.5.2 \ --hash=sha256:7a6f4c4d1fdb9a2b640244008e142cbc2cd3ae34b386584ef044dd0f27101971 \ --hash=sha256:95c58c194ce657a5f4fb0b9e60a84968c808888aed628cd98ab8771fe1db98ed # via boto3 secretstorage==3.3.2 \ --hash=sha256:0a8eb9645b320881c222e827c26f4cfcf55363e8b374a021981ef886657a912f \ --hash=sha256:755dc845b6ad76dcbcbc07ea3da75ae54bb1ea529eb72d15f83d26499a5df319 # via keyring six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # via # bleach # paramiko # python-dateutil twine==4.0.0 \ --hash=sha256:6f7496cf14a3a8903474552d5271c79c71916519edb42554f23f42a8563498a9 \ --hash=sha256:817aa0c0bdc02a5ebe32051e168e23c71a0608334e624c793011f120dbbc05b7 # via -r contrib/automation/requirements.txt.in urllib3==1.26.9 \ --hash=sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14 \ --hash=sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e # via # botocore # requests # twine webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 # via bleach zipp==3.8.0 \ --hash=sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad \ --hash=sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099 # via importlib-metadata ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/automation/requirements.txt.in0000664000175000017500000000003415060516737023077 0ustar00alpharealphareboto3 paramiko pypsrp twine ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/base-revsets.txt0000664000175000017500000000330415060516737020175 0ustar00alpharealphare# Base Revsets to be used with revsetbenchmarks.py script # # The goal of this file is to gather a limited amount of revsets that allow a # good coverage of the internal revsets mechanisms. Revsets included should not # be selected for their individual implementation, but for what they reveal of # the internal implementation of smartsets classes (and their interactions). # # Use and update this file when you change internal implementation of these # smartsets classes. Please include a comment explaining what each of your # addition is testing. Also check if your changes to the smartset class makes # some of the tests inadequate and replace them with a new one testing the same # behavior. # # If you want to benchmark revsets predicate itself, check 'all-revsets.txt'. # # The current content of this file is currently likely not reaching this goal # entirely, feel free, to audit its content and comment on each revset to # highlight what internal mechanisms they test. all() draft() ::tip draft() and ::tip ::tip and draft() 0::tip roots(0::tip) author(lmoscovicz) author("pierre-yves") author(lmoscovicz) or author("pierre-yves") author("pierre-yves") or author(lmoscovicz) tip:0 0:: # those two `roots(...)` inputs are close to what phase movement use. roots((tip~100::) - (tip~100::tip)) roots((0::) - (0::tip)) 42:68 and roots(42:tip) ::p1(p1(tip)):: public() :10000 and public() draft() :10000 and draft() roots((0:tip)::) (not public() - obsolete()) (_intlist('20000\x0020001')) and merge() parents(20000) (20000::) - (20000) # The one below is used by rebase (children(ancestor(tip~5, tip)) and ::(tip~5)):: heads(commonancestors(last(head(), 2))) heads(-10000:-1) roots(-10000:-1) only(max(head()), min(head())) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/bash_completion0000664000175000017500000003560315060516737020131 0ustar00alpharealphare# bash completion for the Mercurial distributed SCM -*- sh -*- # Docs: # # If you source this file from your .bashrc, bash should be able to # complete a command line that uses hg with all the available commands # and options and sometimes even arguments. # # Mercurial allows you to define additional commands through extensions. # Bash should be able to automatically figure out the name of these new # commands and their options. See below for how to define _hg_opt_foo # and _hg_cmd_foo functions to fine-tune the completion for option and # non-option arguments, respectively. # # # Notes about completion for specific commands: # # - the completion function for the email command from the patchbomb # extension will try to call _hg_emails to get a list of e-mail # addresses. It's up to the user to define this function. For # example, put the addresses of the lists that you usually patchbomb # in ~/.patchbomb-to and the addresses that you usually use to send # the patchbombs in ~/.patchbomb-from and use something like this: # # _hg_emails() # { # if [ -r ~/.patchbomb-$1 ]; then # cat ~/.patchbomb-$1 # fi # } # # # Writing completion functions for additional commands: # # If it exists, the function _hg_cmd_foo will be called without # arguments to generate the completion candidates for the hg command # "foo". If the command receives some arguments that aren't options # even though they start with a "-", you can define a function called # _hg_opt_foo to generate the completion candidates. If _hg_opt_foo # doesn't return 0, regular completion for options is attempted. # # In addition to the regular completion variables provided by bash, # the following variables are also set: # - $hg - the hg program being used (e.g. /usr/bin/hg) # - $cmd - the name of the hg command being completed # - $cmd_index - the index of $cmd in $COMP_WORDS # - $cur - the current argument being completed # - $prev - the argument before $cur # - $global_args - "|"-separated list of global options that accept # an argument (e.g. '--cwd|-R|--repository') # - $canonical - 1 if we canonicalized $cmd before calling the function # 0 otherwise # shopt -s extglob _hg_cmd() { HGPLAIN=1 "$hg" "$@" 2>/dev/null } _hg_commands() { local commands commands="$(HGPLAINEXCEPT=alias _hg_cmd debugcomplete "$cur")" || commands="" COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$commands' -- "$cur")) } _hg_paths() { local paths="$(_hg_cmd paths -q)" COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$paths' -- "$cur")) } _hg_repos() { local i for i in $(compgen -d -- "$cur"); do test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i") done } _hg_debugpathcomplete() { local files="$(_hg_cmd debugpathcomplete $1 "$cur")" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) } _hg_status() { if [ -z "$HGCOMPLETE_NOSTATUS" ]; then local files="$(_hg_cmd status -n$1 "glob:$cur**")" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) fi } _hg_branches() { local branches="$(_hg_cmd branches -q)" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$branches' -- "$cur")) } _hg_bookmarks() { local bookmarks="$(_hg_cmd bookmarks -q)" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$bookmarks' -- "$cur")) } _hg_labels() { local labels="$(_hg_cmd debugnamecomplete "$cur")" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$labels' -- "$cur")) } # this is "kind of" ugly... _hg_count_non_option() { local i count=0 local filters="$1" for ((i=1; $i<=$COMP_CWORD; i++)); do if [[ "${COMP_WORDS[i]}" != -* ]]; then if [[ ${COMP_WORDS[i-1]} == @($filters|$global_args) ]]; then continue fi count=$(($count + 1)) fi done echo $(($count - 1)) } _hg_fix_wordlist() { local LASTCHAR=' ' if [ ${#COMPREPLY[@]} = 1 ]; then [ -d "$COMPREPLY" ] && LASTCHAR=/ COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR") else for ((i=0; i < ${#COMPREPLY[@]}; i++)); do [ -d "${COMPREPLY[$i]}" ] && COMPREPLY[$i]=${COMPREPLY[$i]}/ done fi } _hg() { local cur prev cmd cmd_index opts i aliashg # global options that receive an argument local global_args='--cwd|-R|--repository|--color|--config|--encoding|--encodingmode|--pager' local hg="$1" local canonical=0 aliashg=$(alias $hg 2>/dev/null) if [[ -n "$aliashg" ]]; then aliashg=${aliashg#"alias $hg='"} aliashg=${aliashg%"'"} # `source`d aliases break completion, so ignore them if [[ "${aliashg:0:7}" != "source " ]]; then hg=$aliashg fi fi COMPREPLY=() cur="$2" prev="$3" # searching for the command # (first non-option argument that doesn't follow a global option that # receives an argument) for ((i=1; $i<=$COMP_CWORD; i++)); do if [[ ${COMP_WORDS[i]} != -* ]]; then if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then cmd="${COMP_WORDS[i]}" cmd_index=$i break fi fi done if [[ "$cur" == -* ]]; then if [ "$(type -t "_hg_opt_$cmd")" = function ] && "_hg_opt_$cmd"; then _hg_fix_wordlist return fi opts=$(HGPLAINEXCEPT=alias _hg_cmd debugcomplete --options "$cmd") COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur")) _hg_fix_wordlist return fi # global options case "$prev" in -R|--repository) _hg_paths _hg_repos _hg_fix_wordlist return ;; --cwd) # Stick with default bash completion _hg_fix_wordlist return ;; --color) local choices='true false yes no always auto never debug' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$choices' -- "$cur")) _hg_fix_wordlist return ;; --pager) local choices='true false yes no always auto never' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$choices' -- "$cur")) _hg_fix_wordlist return ;; esac if [ -z "$cmd" ] || [ $COMP_CWORD -eq $i ]; then _hg_commands _hg_fix_wordlist return fi # try to generate completion candidates for whatever command the user typed local help if _hg_command_specific; then _hg_fix_wordlist return fi # canonicalize the command name and try again help=$(_hg_cmd help "$cmd") if [ $? -ne 0 ]; then # Probably either the command doesn't exist or it's ambiguous return fi cmd=${help#hg } cmd=${cmd%%[$' \n']*} canonical=1 _hg_command_specific _hg_fix_wordlist } _hg_command_specific() { if [ "$(type -t "_hg_cmd_$cmd")" = function ]; then "_hg_cmd_$cmd" return 0 fi if [ "$cmd" != status ]; then case "$prev" in -r|--rev) if [[ $canonical = 1 || status != "$cmd"* ]]; then _hg_labels return 0 fi return 1 ;; -B|--bookmark) if [[ $canonical = 1 || status != "$cmd"* ]]; then _hg_bookmarks return 0 fi return 1 ;; -b|--branch) if [[ $canonical = 1 || status != "$cmd"* ]]; then _hg_branches return 0 fi return 1 ;; esac fi local aliascmd=$(_hg_cmd showconfig alias.$cmd | awk '{print $1}') [ -n "$aliascmd" ] && cmd=$aliascmd case "$cmd" in help) _hg_commands ;; export) if _hg_ext_mq_patchlist qapplied && [ "${COMPREPLY[*]}" ]; then return 0 fi _hg_labels ;; manifest|update|up|checkout|co) _hg_labels ;; pull|push|outgoing|incoming) _hg_paths _hg_repos ;; paths) _hg_paths ;; add) _hg_status "u" ;; merge) _hg_labels ;; commit|ci|record|amend) _hg_status "mar" ;; remove|rm) _hg_debugpathcomplete -n ;; forget) _hg_debugpathcomplete -fa ;; diff) _hg_status "mar" ;; revert) _hg_status "mard" ;; clone) local count=$(_hg_count_non_option) if [ $count = 1 ]; then _hg_paths fi _hg_repos ;; debugindex|debugindexdot) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.i" -- "$cur")) ;; debugdata) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.d" -- "$cur")) ;; *) return 1 ;; esac return 0 } complete -o bashdefault -o default -o nospace -F _hg hg \ || complete -o default -o nospace -F _hg hg # Completion for commands provided by extensions # bookmarks _hg_cmd_bookmarks() { _hg_bookmarks return } # mq _hg_ext_mq_patchlist() { local patches patches=$(_hg_cmd $1) if [ $? -eq 0 ] && [ "$patches" ]; then COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$patches' -- "$cur")) return 0 fi return 1 } _hg_ext_mq_queues() { local root=$(_hg_cmd root) local n for n in $(cd "$root"/.hg && compgen -d -- "$cur"); do # I think we're usually not interested in the regular "patches" queue # so just filter it. if [ "$n" != patches ] && [ -e "$root/.hg/$n/series" ]; then COMPREPLY=(${COMPREPLY[@]:-} "$n") fi done } _hg_cmd_qpop() { if [[ "$prev" = @(-n|--name) ]]; then _hg_ext_mq_queues return fi _hg_ext_mq_patchlist qapplied } _hg_cmd_qpush() { if [[ "$prev" = @(-n|--name) ]]; then _hg_ext_mq_queues return fi _hg_ext_mq_patchlist qunapplied } _hg_cmd_qgoto() { if [[ "$prev" = @(-n|--name) ]]; then _hg_ext_mq_queues return fi _hg_ext_mq_patchlist qseries } _hg_cmd_qdelete() { local qcmd=qunapplied if [[ "$prev" = @(-r|--rev) ]]; then qcmd=qapplied fi _hg_ext_mq_patchlist $qcmd } _hg_cmd_qfinish() { if [[ "$prev" = @(-a|--applied) ]]; then return fi _hg_ext_mq_patchlist qapplied } _hg_cmd_qsave() { if [[ "$prev" = @(-n|--name) ]]; then _hg_ext_mq_queues return fi } _hg_cmd_rebase() { if [[ "$prev" = @(-s|--source|-d|--dest|-b|--base|-r|--rev) ]]; then _hg_labels return fi } _hg_cmd_strip() { if [[ "$prev" = @(-B|--bookmark) ]]; then _hg_bookmarks return fi _hg_labels } _hg_cmd_qcommit() { local root=$(_hg_cmd root) # this is run in a sub-shell, so we can't use _hg_status local files=$(cd "$root/.hg/patches" && _hg_cmd status -nmar) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) } _hg_cmd_qfold() { _hg_ext_mq_patchlist qunapplied } _hg_cmd_qrename() { _hg_ext_mq_patchlist qseries } _hg_cmd_qheader() { _hg_ext_mq_patchlist qseries } _hg_cmd_qclone() { local count=$(_hg_count_non_option) if [ $count = 1 ]; then _hg_paths fi _hg_repos } _hg_ext_mq_guards() { _hg_cmd qselect --series | sed -e 's/^.//' } _hg_cmd_qselect() { local guards=$(_hg_ext_mq_guards) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$guards' -- "$cur")) } _hg_cmd_qguard() { local prefix='' if [[ "$cur" == +* ]]; then prefix=+ elif [[ "$cur" == -* ]]; then prefix=- fi local ncur=${cur#[-+]} if ! [ "$prefix" ]; then _hg_ext_mq_patchlist qseries return fi local guards=$(_hg_ext_mq_guards) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -P $prefix -W '$guards' -- "$ncur")) } _hg_opt_qguard() { local i for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do if [[ ${COMP_WORDS[i]} != -* ]]; then if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then _hg_cmd_qguard return 0 fi elif [ "${COMP_WORDS[i]}" = -- ]; then _hg_cmd_qguard return 0 fi done return 1 } _hg_cmd_qqueue() { local q local queues local opts="--list --create --rename --delete --purge" queues=$( _hg_cmd qqueue --quiet ) COMPREPLY=( $( compgen -W "${opts} ${queues}" "${cur}" ) ) } # hbisect _hg_cmd_bisect() { local i subcmd # find the sub-command for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do if [[ ${COMP_WORDS[i]} != -* ]]; then if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then subcmd="${COMP_WORDS[i]}" break fi fi done if [ -z "$subcmd" ] || [ $COMP_CWORD -eq $i ] || [ "$subcmd" = help ]; then COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W 'bad good help init next reset' -- "$cur")) return fi case "$subcmd" in good|bad) _hg_labels ;; esac return } # patchbomb _hg_cmd_email() { case "$prev" in -c|--cc|-t|--to|-f|--from|--bcc) # we need an e-mail address. let the user provide a function # to get them if [ "$(type -t _hg_emails)" = function ]; then local arg=to if [[ "$prev" == @(-f|--from) ]]; then arg=from fi local addresses=$(_hg_emails $arg) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$addresses' -- "$cur")) fi return ;; -m|--mbox) # fallback to standard filename completion return ;; -s|--subject) # free form string return ;; esac _hg_labels return } # gpg _hg_cmd_sign() { _hg_labels } # transplant _hg_cmd_transplant() { case "$prev" in -s|--source) _hg_paths _hg_repos return ;; --filter) # standard filename completion return ;; esac # all other transplant options values and command parameters are revisions _hg_labels return } # shelve _hg_shelves() { local shelves="$(_hg_cmd shelve -ql)" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$shelves' -- "$cur")) } _hg_cmd_shelve() { if [[ "$prev" = @(-d|--delete|-l|--list|-p|--patch|--stat) ]]; then _hg_shelves else _hg_status "mard" fi } _hg_cmd_unshelve() { _hg_shelves } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/bdiff-torture.py0000664000175000017500000000413615060516737020163 0ustar00alpharealphare# Randomized torture test generation for bdiff import random import sys from mercurial import ( mdiff, pycompat, ) def reducetest(a, b): tries = 0 reductions = 0 print("reducing...") while tries < 1000: a2 = ( "\n".join(l for l in a.splitlines() if random.randint(0, 100) > 0) + "\n" ) b2 = ( "\n".join(l for l in b.splitlines() if random.randint(0, 100) > 0) + "\n" ) if a2 == a and b2 == b: continue if a2 == b2: continue tries += 1 try: test1(a, b) except Exception: reductions += 1 tries = 0 a = a2 b = b2 print("reduced:", reductions, len(a) + len(b), repr(a), repr(b)) try: test1(a, b) except Exception as inst: print("failed:", inst) sys.exit(0) def test1(a, b): d = mdiff.textdiff(a, b) if not d: raise ValueError("empty") c = mdiff.patches(a, [d]) if c != b: raise ValueError("bad") def testwrap(a, b): try: test1(a, b) return except Exception as inst: print("exception:", inst) reducetest(a, b) def test(a, b): testwrap(a, b) testwrap(b, a) def rndtest(size, noise): a = [] src = " aaaaaaaabbbbccd" for x in pycompat.xrange(size): a.append(src[random.randint(0, len(src) - 1)]) while True: b = [c for c in a if random.randint(0, 99) > noise] b2 = [] for c in b: b2.append(c) while random.randint(0, 99) < noise: b2.append(src[random.randint(0, len(src) - 1)]) if b2 != a: break a = "\n".join(a) + "\n" b = "\n".join(b2) + "\n" test(a, b) maxvol = 10000 startsize = 2 while True: size = startsize count = 0 while size < maxvol: print(size) volume = 0 while volume < maxvol: rndtest(size, 2) volume += size count += 2 size *= 2 maxvol *= 4 startsize *= 4 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1757584919.3054512 mercurial-7.1.1/contrib/benchmarks/0000775000175000017500000000000015060517027017137 5ustar00alpharealphare././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/benchmarks/__init__.py0000664000175000017500000000750115060516737021262 0ustar00alpharealphare# __init__.py - asv benchmark suite # # Copyright 2016 Logilab SA # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # "historical portability" policy of contrib/benchmarks: # # We have to make this code work correctly with current mercurial stable branch # and if possible with reasonable cost with early Mercurial versions. '''ASV (https://asv.readthedocs.io) benchmark suite Benchmark are parameterized against reference repositories found in the directory pointed by the REPOS_DIR environment variable. Invocation example: $ export REPOS_DIR=~/hgperf/repos # run suite on given revision $ asv --config contrib/asv.conf.json run REV # run suite on new changesets found in stable and default branch $ asv --config contrib/asv.conf.json run NEW # display a comparative result table of benchmark results between two given # revisions $ asv --config contrib/asv.conf.json compare REV1 REV2 # compute regression detection and generate ASV static website $ asv --config contrib/asv.conf.json publish # serve the static website $ asv --config contrib/asv.conf.json preview ''' import functools import os import re from mercurial import ( extensions, hg, ui as uimod, ) basedir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir) ) reposdir = os.environ['REPOS_DIR'] reposnames = [ name for name in os.listdir(reposdir) if os.path.isdir(os.path.join(reposdir, name, ".hg")) ] if not reposnames: raise ValueError("No repositories found in $REPO_DIR") outputre = re.compile( r'! wall (\d+.\d+) comb \d+.\d+ user \d+.\d+ sys ' r'\d+.\d+ \(best of \d+\)' ) def runperfcommand(reponame, command, *args, **kwargs): os.environ["HGRCPATH"] = os.environ.get("ASVHGRCPATH", "") # for "historical portability" # ui.load() has been available since d83ca85 if hasattr(uimod.ui, "load"): ui = uimod.ui.load() else: ui = uimod.ui() repo = hg.repository(ui, os.path.join(reposdir, reponame)) perfext = extensions.load( ui, 'perfext', os.path.join(basedir, 'contrib', 'perf.py') ) cmd = getattr(perfext, command) ui.pushbuffer() cmd(ui, repo, *args, **kwargs) output = ui.popbuffer() match = outputre.search(output) if not match: raise ValueError(f"Invalid output {output}") return float(match.group(1)) def perfbench(repos=reposnames, name=None, params=None): """decorator to declare ASV benchmark based on contrib/perf.py extension An ASV benchmark is a python function with the given attributes: __name__: should start with track_, time_ or mem_ to be collected by ASV params and param_name: parameter matrix to display multiple graphs on the same page. pretty_name: If defined it's displayed in web-ui instead of __name__ (useful for revsets) the module name is prepended to the benchmark name and displayed as "category" in webui. Benchmarks are automatically parameterized with repositories found in the REPOS_DIR environment variable. `params` is the param matrix in the form of a list of tuple (param_name, [value0, value1]) For example [(x, [a, b]), (y, [c, d])] declare benchmarks for (a, c), (a, d), (b, c) and (b, d). """ params = list(params or []) params.insert(0, ("repo", repos)) def decorator(func): @functools.wraps(func) def wrapped(repo, *args): def perf(command, *a, **kw): return runperfcommand(repo, command, *a, **kw) return func(perf, *args) wrapped.params = [p[1] for p in params] wrapped.param_names = [p[0] for p in params] wrapped.pretty_name = name return wrapped return decorator ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/benchmarks/perf.py0000664000175000017500000000114615060516737020456 0ustar00alpharealphare# perf.py - asv benchmarks using contrib/perf.py extension # # Copyright 2016 Logilab SA # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. from . import perfbench @perfbench() def track_tags(perf): return perf("perftags") @perfbench() def track_status(perf): return perf("perfstatus", unknown=False) @perfbench(params=[('rev', ['1000', '10000', 'tip'])]) def track_manifest(perf, rev): return perf("perfmanifest", rev) @perfbench() def track_heads(perf): return perf("perfheads") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/benchmarks/revset.py0000664000175000017500000000307715060516737021037 0ustar00alpharealphare# revset.py - asv revset benchmarks # # Copyright 2016 Logilab SA # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. '''ASV revset benchmarks generated from contrib/base-revsets.txt Each revset benchmark is parameterized with variants (first, last, sort, ...) ''' import os import string import sys from . import basedir, perfbench def createrevsetbenchmark(baseset, variants=None): if variants is None: # Default variants variants = ["plain", "first", "last", "sort", "sort+first", "sort+last"] fname = "track_" + "_".join( "".join( [c if c in string.digits + string.letters else " " for c in baseset] ).split() ) def wrap(fname, baseset): @perfbench(name=baseset, params=[("variant", variants)]) def f(perf, variant): revset = baseset if variant != "plain": for var in variant.split("+"): revset = "%s(%s)" % (var, revset) return perf("perfrevset", revset) f.__name__ = fname return f return wrap(fname, baseset) def initializerevsetbenchmarks(): mod = sys.modules[__name__] with open(os.path.join(basedir, 'contrib', 'base-revsets.txt'), 'rb') as fh: for line in fh: baseset = line.strip() if baseset and not baseset.startswith('#'): func = createrevsetbenchmark(baseset) setattr(mod, func.__name__, func) initializerevsetbenchmarks() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/build-one-linux-wheel.sh0000755000175000017500000000144015060516737021502 0ustar00alpharealphare#!/bin/bash # build a single linux wheel within a prepared imaged based on manylinux images # # # set -eu if [ $# -lt 2 ]; then echo "usage $0 PYTHONTAG DEST_DIR [FLAVOR]" >&2 echo "" >&2 echo 'PYTHONTAG should be of the form "cp310-cp310"' >&2 exit 64 fi py_tag=$1 destination_directory=$2 flavor=${3:-c} flavor_arg="" if [[ "${flavor}" == "c" ]]; then : elif [[ "$flavor" == "rust" ]]; then flavor_arg="--config-setting=--global-option=--rust" else echo "unknown flavor: \"$flavor\"" exit 96 fi tmp_wheel_dir=./tmp-wheelhouse if [ -e $tmp_wheel_dir ]; then rm -rf $tmp_wheel_dir fi /opt/python/$py_tag/bin/python -m build --outdir $tmp_wheel_dir $flavor_arg # adjust it to make it universal auditwheel repair $tmp_wheel_dir/*.whl -w $destination_directory ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/byteify-strings.py0000755000175000017500000002603315060516737020552 0ustar00alpharealphare#!/usr/bin/env python3 # # byteify-strings.py - transform string literals to be Python 3 safe # # Copyright 2015 Gregory Szorc # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. import argparse import contextlib import errno import os import sys import tempfile import token import tokenize def adjusttokenpos(t, ofs): """Adjust start/end column of the given token""" return t._replace( start=(t.start[0], t.start[1] + ofs), end=(t.end[0], t.end[1] + ofs) ) def replacetokens(tokens, opts): """Transform a stream of tokens from raw to Python 3. Returns a generator of possibly rewritten tokens. The input token list may be mutated as part of processing. However, its changes do not necessarily match the output token stream. """ sysstrtokens = set() # The following utility functions access the tokens list and i index of # the for i, t enumerate(tokens) loop below def _isop(j, *o): """Assert that tokens[j] is an OP with one of the given values""" try: return tokens[j].type == token.OP and tokens[j].string in o except IndexError: return False def _findargnofcall(n): """Find arg n of a call expression (start at 0) Returns index of the first token of that argument, or None if there is not that many arguments. Assumes that token[i + 1] is '('. """ nested = 0 for j in range(i + 2, len(tokens)): if _isop(j, ')', ']', '}'): # end of call, tuple, subscription or dict / set nested -= 1 if nested < 0: return None elif n == 0: # this is the starting position of arg return j elif _isop(j, '(', '[', '{'): nested += 1 elif _isop(j, ',') and nested == 0: n -= 1 return None def _ensuresysstr(j): """Make sure the token at j is a system string Remember the given token so the string transformer won't add the byte prefix. Ignores tokens that are not strings. Assumes bounds checking has already been done. """ k = j currtoken = tokens[k] while currtoken.type in (token.STRING, token.NEWLINE, tokenize.NL): k += 1 if currtoken.type == token.STRING and currtoken.string.startswith( ("'", '"') ): sysstrtokens.add(currtoken) try: currtoken = tokens[k] except IndexError: break def _isitemaccess(j): """Assert the next tokens form an item access on `tokens[j]` and that `tokens[j]` is a name. """ try: return ( tokens[j].type == token.NAME and _isop(j + 1, '[') and tokens[j + 2].type == token.STRING and _isop(j + 3, ']') ) except IndexError: return False def _ismethodcall(j, *methodnames): """Assert the next tokens form a call to `methodname` with a string as first argument on `tokens[j]` and that `tokens[j]` is a name. """ try: return ( tokens[j].type == token.NAME and _isop(j + 1, '.') and tokens[j + 2].type == token.NAME and tokens[j + 2].string in methodnames and _isop(j + 3, '(') and tokens[j + 4].type == token.STRING ) except IndexError: return False coldelta = 0 # column increment for new opening parens coloffset = -1 # column offset for the current line (-1: TBD) parens = [(0, 0, 0, -1)] # stack of (line, end-column, column-offset, type) ignorenextline = False # don't transform the next line insideignoreblock = False # don't transform until turned off for i, t in enumerate(tokens): # Compute the column offset for the current line, such that # the current line will be aligned to the last opening paren # as before. if coloffset < 0: lastparen = parens[-1] if t.start[1] == lastparen[1]: coloffset = lastparen[2] elif t.start[1] + 1 == lastparen[1] and lastparen[3] not in ( token.NEWLINE, tokenize.NL, ): # fix misaligned indent of s/util.Abort/error.Abort/ coloffset = lastparen[2] + (lastparen[1] - t.start[1]) else: coloffset = 0 # Reset per-line attributes at EOL. if t.type in (token.NEWLINE, tokenize.NL): yield adjusttokenpos(t, coloffset) coldelta = 0 coloffset = -1 if not insideignoreblock: ignorenextline = ( tokens[i - 1].type == token.COMMENT and tokens[i - 1].string == "# no-py3-transform" ) continue if t.type == token.COMMENT: if t.string == "# py3-transform: off": insideignoreblock = True if t.string == "# py3-transform: on": insideignoreblock = False if ignorenextline or insideignoreblock: yield adjusttokenpos(t, coloffset) continue # Remember the last paren position. if _isop(i, '(', '[', '{'): parens.append(t.end + (coloffset + coldelta, tokens[i + 1].type)) elif _isop(i, ')', ']', '}'): parens.pop() # Convert most string literals to byte literals. String literals # in Python 2 are bytes. String literals in Python 3 are unicode. # Most strings in Mercurial are bytes and unicode strings are rare. # Rather than rewrite all string literals to use ``b''`` to indicate # byte strings, we apply this token transformer to insert the ``b`` # prefix nearly everywhere. if t.type == token.STRING and t not in sysstrtokens: s = t.string # Preserve docstrings as string literals. This is inconsistent # with regular unprefixed strings. However, the # "from __future__" parsing (which allows a module docstring to # exist before it) doesn't properly handle the docstring if it # is b''' prefixed, leading to a SyntaxError. We leave all # docstrings as unprefixed to avoid this. This means Mercurial # components touching docstrings need to handle unicode, # unfortunately. if s[0:3] in ("'''", '"""'): # If it's assigned to something, it's not a docstring if not _isop(i - 1, '='): yield adjusttokenpos(t, coloffset) continue # If the first character isn't a quote, it is likely a string # prefixing character (such as 'b', 'u', or 'r'. Ignore. if s[0] not in ("'", '"'): yield adjusttokenpos(t, coloffset) continue # String literal. Prefix to make a b'' string. yield adjusttokenpos(t._replace(string='b%s' % t.string), coloffset) coldelta += 1 continue # This looks like a function call. if t.type == token.NAME and _isop(i + 1, '('): fn = t.string # *attr() builtins don't accept byte strings to 2nd argument. if fn in ( 'getattr', 'setattr', 'hasattr', 'safehasattr', 'wrapfunction', 'wrapclass', 'addattr', ): arg1idx = _findargnofcall(1) if arg1idx is not None: _ensuresysstr(arg1idx) # .encode() and .decode() on str/bytes/unicode don't accept # byte strings on Python 3. elif fn in ('encode', 'decode') and _isop(i - 1, '.'): for argn in range(2): argidx = _findargnofcall(argn) if argidx is not None: _ensuresysstr(argidx) # It changes iteritems/values to items/values as they are not # present in Python 3 world. elif opts['dictiter'] and fn in ('iteritems', 'itervalues'): yield adjusttokenpos(t._replace(string=fn[4:]), coloffset) continue if t.type == token.NAME and t.string in opts['treat-as-kwargs']: if _isitemaccess(i): _ensuresysstr(i + 2) if _ismethodcall(i, 'get', 'pop', 'setdefault', 'popitem'): _ensuresysstr(i + 4) # Looks like "if __name__ == '__main__'". if ( t.type == token.NAME and t.string == '__name__' and _isop(i + 1, '==') ): _ensuresysstr(i + 2) # Emit unmodified token. yield adjusttokenpos(t, coloffset) def process(fin, fout, opts): tokens = tokenize.tokenize(fin.readline) tokens = replacetokens(list(tokens), opts) fout.write(tokenize.untokenize(tokens)) def tryunlink(fname): try: os.unlink(fname) except OSError as err: if err.errno != errno.ENOENT: raise @contextlib.contextmanager def editinplace(fname): n = os.path.basename(fname) d = os.path.dirname(fname) fp = tempfile.NamedTemporaryFile( prefix='.%s-' % n, suffix='~', dir=d, delete=False ) try: yield fp fp.close() if os.name == 'nt': tryunlink(fname) os.rename(fp.name, fname) finally: fp.close() tryunlink(fp.name) def main(): ap = argparse.ArgumentParser() ap.add_argument( '--version', action='version', version='Byteify strings 1.0' ) ap.add_argument( '-i', '--inplace', action='store_true', default=False, help='edit files in place', ) ap.add_argument( '--dictiter', action='store_true', default=False, help='rewrite iteritems() and itervalues()', ), ap.add_argument( '--treat-as-kwargs', nargs="+", default=[], help="ignore kwargs-like objects", ), ap.add_argument('files', metavar='FILE', nargs='+', help='source file') args = ap.parse_args() opts = { 'dictiter': args.dictiter, 'treat-as-kwargs': set(args.treat_as_kwargs), } for fname in args.files: fname = os.path.realpath(fname) if args.inplace: with editinplace(fname) as fout: with open(fname, 'rb') as fin: process(fin, fout, opts) else: with open(fname, 'rb') as fin: fout = sys.stdout.buffer process(fin, fout, opts) if __name__ == '__main__': if sys.version_info[0:2] < (3, 7): print('This script must be run under Python 3.7+') sys.exit(3) main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/casesmash.py0000664000175000017500000000157715060516737017364 0ustar00alpharealphareimport __builtin__ import os from mercurial import util def lowerwrap(scope, funcname): f = getattr(scope, funcname) def wrap(fname, *args, **kwargs): d, base = os.path.split(fname) try: files = os.listdir(d or '.') except OSError: files = [] if base in files: return f(fname, *args, **kwargs) for fn in files: if fn.lower() == base.lower(): return f(os.path.join(d, fn), *args, **kwargs) return f(fname, *args, **kwargs) scope.__dict__[funcname] = wrap def normcase(path): return path.lower() os.path.normcase = normcase for f in 'file open'.split(): lowerwrap(__builtin__, f) for f in "chmod chown open lstat stat remove unlink".split(): lowerwrap(os, f) for f in "exists lexists".split(): lowerwrap(os.path, f) lowerwrap(util, 'posixfile') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/catapipe.py0000755000175000017500000000705315060516737017177 0ustar00alpharealphare#!/usr/bin/env python3 # # Copyright 2018 Google LLC. # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. """Tool read primitive events from a pipe to produce a catapult trace. Usage: Terminal 1: $ catapipe.py /tmp/mypipe /tmp/trace.json Terminal 2: $ HGCATAPULTSERVERPIPE=/tmp/mypipe hg root $ catapult/tracing/bin/trace2html /tmp/trace.json # produce /tmp/trace.html (catapult is located at https://github.com/catapult-project/catapult) For now the event stream supports START $SESSIONID ... and END $SESSIONID ... events. Everything after the SESSIONID (which must not contain spaces) is used as a label for the event. Events are timestamped as of when they arrive in this process and are then used to produce catapult traces that can be loaded in Chrome's about:tracing utility. It's important that the event stream *into* this process stay simple, because we have to emit it from the shell scripts produced by run-tests.py. Typically you'll want to place the path to the named pipe in the HGCATAPULTSERVERPIPE environment variable, which both run-tests and hg understand. To trace *only* run-tests, use HGTESTCATAPULTSERVERPIPE instead. """ import argparse import json import os import timeit _TYPEMAP = { 'START': 'B', 'END': 'E', 'COUNTER': 'C', } _threadmap = {} # Timeit already contains the whole logic about which timer to use based on # Python version and OS timer = timeit.default_timer def main(): parser = argparse.ArgumentParser() parser.add_argument( 'pipe', type=str, nargs=1, help='Path of named pipe to create and listen on.', ) parser.add_argument( 'output', default='trace.json', type=str, nargs='?', help='Path of json file to create where the traces ' 'will be stored.', ) parser.add_argument( '--debug', default=False, action='store_true', help='Print useful debug messages', ) args = parser.parse_args() fn = args.pipe[0] os.mkfifo(fn) try: with open(fn) as f, open(args.output, 'w') as out: out.write('[\n') start = timer() while True: ev = f.readline().strip() if not ev: continue now = timer() if args.debug: print(ev) verb, session, label = ev.split(' ', 2) if session not in _threadmap: _threadmap[session] = len(_threadmap) if verb == 'COUNTER': amount, label = label.split(' ', 1) payload_args = {'value': int(amount)} else: payload_args = {} pid = _threadmap[session] ts_micros = (now - start) * 1000000 out.write( json.dumps( { "name": label, "cat": "misc", "ph": _TYPEMAP[verb], "ts": ts_micros, "pid": pid, "tid": 1, "args": payload_args, } ) ) out.write(',\n') finally: os.unlink(fn) if __name__ == '__main__': main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/check-code.py0000755000175000017500000010433015060516737017372 0ustar00alpharealphare#!/usr/bin/env python3 # # check-code - a style and portability checker for Mercurial # # Copyright 2010 Olivia Mackall # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. """style and portability checker for Mercurial when a rule triggers wrong, do one of the following (prefer one from top): * do the work-around the rule suggests * doublecheck that it is a false match * improve the rule pattern * add an ignore pattern to the rule (3rd arg) which matches your good line (you can append a short comment and match this, like: #re-raises) * change the pattern to a warning and list the exception in test-check-code-hg * ONLY use no--check-code for skipping entire files from external sources """ import glob import keyword import optparse import os import re import sys if sys.version_info[0] < 3: opentext = open else: def opentext(f): return open(f, encoding='latin1') try: xrange except NameError: xrange = range try: import re2 except ImportError: re2 = None import testparseutil def compilere(pat, multiline=False): if multiline: pat = '(?m)' + pat if re2: try: return re2.compile(pat) except re2.error: pass return re.compile(pat) # check "rules depending on implementation of repquote()" in each # patterns (especially pypats), before changing around repquote() _repquotefixedmap = { ' ': ' ', '\n': '\n', '.': 'p', ':': 'q', '%': '%', '\\': 'b', '*': 'A', '+': 'P', '-': 'M', } def _repquoteencodechr(i): if i > 255: return 'u' c = chr(i) if c in _repquotefixedmap: return _repquotefixedmap[c] if c.isalpha(): return 'x' if c.isdigit(): return 'n' return 'o' _repquotett = ''.join(_repquoteencodechr(i) for i in xrange(256)) def repquote(m): t = m.group('text') t = t.translate(_repquotett) return m.group('quote') + t + m.group('quote') def reppython(m): comment = m.group('comment') if comment: l = len(comment.rstrip()) return "#" * l + comment[l:] return repquote(m) def repcomment(m): return m.group(1) + "#" * len(m.group(2)) def repccomment(m): t = re.sub(r"((?<=\n) )|\S", "x", m.group(2)) return m.group(1) + t + "*/" def repcallspaces(m): t = re.sub(r"\n\s+", "\n", m.group(2)) return m.group(1) + t def repinclude(m): return m.group(1) + "" def rephere(m): t = re.sub(r"\S", "x", m.group(2)) return m.group(1) + t testpats = [ [ (r'\b(push|pop)d\b', "don't use 'pushd' or 'popd', use 'cd'"), (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"), (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"), (r'(?'"), (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"), (r'\bls\b.*-\w*R', "don't use 'ls -R', use 'find'"), (r'printf.*[^\\]\\([1-9]|0\d)', r"don't use 'printf \NNN', use Python"), (r'printf.*[^\\]\\x', "don't use printf \\x, use Python"), (r'rm -rf \*', "don't use naked rm -rf, target a directory"), ( r'\[[^\]]+==', '[ foo == bar ] is a bashism, use [ foo = bar ] instead', ), (r'(^|\|\s*)egrep', "use grep -E for extended grep syntax"), (r'(^|\|\s*)fgrep', "use grep -F for fixed string grepping"), (r'(^|\|\s*)e?grep .*\\S', "don't use \\S in regular expression"), (r'(?\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"), (r'^stop\(\)', "don't use 'stop' as a shell function name"), (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"), (r'\[\[\s+[^\]]*\]\]', "don't use '[[ ]]', use '[ ]'"), (r'^alias\b.*=', "don't use alias, use a function"), # Solaris sh can not negate exit status with '!' ( r'if\s*!', "don't use '!' to negate exit status (use `||` or if/else)", ), (r'/dev/u?random', "don't use entropy, use /dev/zero"), (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"), ( r'sed (-e )?\'(\d+|/[^/]*/)i(?!\\\n)', "put a backslash-escaped newline after sed 'i' command", ), (r'^diff *-\w*[uU].*$\n(^ \$ |^$)', "prefix diff -u/-U with cmp"), (r'^\s+(if)? diff *-\w*[uU]', "prefix diff -u/-U with cmp"), (r'[\s="`\']python\s(?!bindings)', "don't use 'python', use '$PYTHON'"), (r'seq ', "don't use 'seq', use $TESTDIR/seq.py"), (r'\butil\.Abort\b', "directly use error.Abort"), (r'\|&', "don't use |&, use 2>&1"), (r'\w = +\w', "only one space after = allowed"), ( r'\bsed\b.*[^\\]\\n', "don't use 'sed ... \\n', use a \\ and a newline", ), (r'env.*-u', "don't use 'env -u VAR', use 'unset VAR'"), (r'cp.* -r ', "don't use 'cp -r', use 'cp -R'"), (r'grep.* -[ABC]', "don't use grep's context flags"), ( r'find.*-printf', "don't use 'find -printf', it doesn't exist on BSD find(1)", ), (r'\$RANDOM ', "don't use bash-only $RANDOM to generate random values"), ], # warnings [ (r'^function', "don't use 'function', use old style"), (r'^diff.*-\w*N', "don't use 'diff -N'"), (r'\$PWD|\${PWD}', "don't use $PWD, use `pwd`", "no-pwd-check"), (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"), (r'kill (`|\$\()', "don't use kill, use killdaemons.py"), ], ] testfilters = [ (r"( *)(#([^!][^\n]*\S)?)", repcomment), (r"<<(\S+)((.|\n)*?\n\1)", rephere), ] uprefix = r"^ \$ " utestpats = [ [ (r'^(\S.*|| [$>] \S.*)[ \t]\n', "trailing whitespace on non-output"), ( uprefix + r'.*\|\s*sed[^|>\n]*\n', "use regex test output patterns instead of sed", ), (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"), ( uprefix + r'.*\|\| echo.*(fail|error)', "explicit exit code checks unnecessary", ), (uprefix + r'set -e', "don't use set -e"), (uprefix + r'(\s|fi\b|done\b)', "use > for continued lines"), ( uprefix + r'.*:\.\S*/', "x:.y in a path does not work on msys, rewrite " "as x://.y, or see `hg log -k msys` for alternatives", r'-\S+:\.|' '# no-msys', # -Rxxx ), # in test-pull.t which is skipped on windows ( r'^ [^$>].*27\.0\.0\.1', 'use $LOCALIP not an explicit loopback address', ), ( r'^ (?![>$] ).*\$LOCALIP.*[^)]$', 'mark $LOCALIP output lines with (glob) to help tests in BSD jails', ), ( r'^ (cat|find): .*: \$ENOENT\$', 'use test -f to test for file existence', ), ( r'^ diff -[^ -]*p', "don't use (external) diff with -p for portability", ), (r' readlink ', 'use readlink.py instead of readlink'), ( r'^ [-+][-+][-+] .* [-+]0000 \(glob\)', "glob timezone field in diff output for portability", ), ( r'^ @@ -[0-9]+ [+][0-9]+,[0-9]+ @@', "use '@@ -N* +N,n @@ (glob)' style chunk header for portability", ), ( r'^ @@ -[0-9]+,[0-9]+ [+][0-9]+ @@', "use '@@ -N,n +N* @@ (glob)' style chunk header for portability", ), ( r'^ @@ -[0-9]+ [+][0-9]+ @@', "use '@@ -N* +N* @@ (glob)' style chunk header for portability", ), ( uprefix + r'hg( +-[^ ]+( +[^ ]+)?)* +extdiff' r'( +(-[^ po-]+|--(?!program|option)[^ ]+|[^-][^ ]*))*$', "use $RUNTESTDIR/pdiff via extdiff (or -o/-p for false-positives)", ), ], # warnings [ ( r'^ (?!.*\$LOCALIP)[^*?/\n]* \(glob\)$', "glob match with no glob string (?, *, /, and $LOCALIP)", ), ], ] # transform plain test rules to unified test's for i in [0, 1]: for tp in testpats[i]: p = tp[0] m = tp[1] if p.startswith('^'): p = "^ [$>] (%s)" % p[1:] else: p = "^ [$>] .*(%s)" % p utestpats[i].append((p, m) + tp[2:]) # don't transform the following rules: # " > \t" and " \t" should be allowed in unified tests testpats[0].append((r'^( *)\t', "don't use tabs to indent")) utestpats[0].append((r'^( ?)\t', "don't use tabs to indent")) utestfilters = [ (r"<<(\S+)((.|\n)*?\n > \1)", rephere), (r"( +)(#([^!][^\n]*\S)?)", repcomment), ] # common patterns to check *.py commonpypats = [ [ (r'\\$', 'Use () to wrap long lines in Python, not \\'), ( r'^\s*def\s*\w+\s*\(.*,\s*\(', "tuple parameter unpacking not available in Python 3+", ), ( r'lambda\s*\(.*,.*\)', "tuple parameter unpacking not available in Python 3+", ), (r'(?\s', '<> operator is not available in Python 3+, use !='), (r'^\s*\t', "don't use tabs"), (r'\S;\s*\n', "semicolon"), (r'[^_]_\([ \t\n]*(?:"[^"]+"[ \t\n+]*)+%', "don't use % inside _()"), (r"[^_]_\([ \t\n]*(?:'[^']+'[ \t\n+]*)+%", "don't use % inside _()"), (r'(\w|\)),\w', "missing whitespace after ,"), (r'(\w|\))[+/*\-<>]\w', "missing whitespace in expression"), (r'\w\s=\s\s+\w', "gratuitous whitespace after ="), ( ( # a line ending with a colon, potentially with trailing comments r':([ \t]*#[^\n]*)?\n' # one that is not a pass and not only a comment r'(?P[ \t]+)[^#][^\n]+\n' # more lines at the same indent level r'((?P=indent)[^\n]+\n)*' # a pass at the same indent level, which is bogus r'(?P=indent)pass[ \t\n#]' ), 'omit superfluous pass', ), (r'[^\n]\Z', "no trailing newline"), (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"), ( r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+', "linebreak after :", ), ( r'\b(%s)\(' % '|'.join(k for k in keyword.kwlist if k not in ('print', 'exec')), "Python keyword is not a function", ), # (r'class\s[A-Z][^\(]*\((?!Exception)', # "don't capitalize non-exception classes"), # (r'in range\(', "use xrange"), # (r'^\s*print\s+', "avoid using print in core and extensions"), (r'[\x80-\xff]', "non-ASCII character literal"), (r'("\')\.format\(', "str.format() has no bytes counterpart, use %"), ( r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []", ), # (r'\s\s=', "gratuitous whitespace before ="), ( r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S', "missing whitespace around operator", ), ( r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\s', "missing whitespace around operator", ), ( r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S', "missing whitespace around operator", ), (r'[^^+=*/!<>&| %-:](\s=|=\s)[^= ]', "wrong whitespace around ="), ( r'raise [^,(]+, (\([^\)]+\)|[^,\(\)]+)$', "don't use old-style two-argument raise, use Exception(message)", ), (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"), ( r' [=!]=\s+(True|False|None)', "comparison with singleton, use 'is' or 'is not' instead", ), ( r'^\s*(while|if) [01]:', "use True/False for constant Boolean expression", ), (r'^\s*if False(:| +and)', 'Remove code instead of using `if False`'), (r'opener\([^)]*\).read\(', "use opener.read() instead"), (r'opener\([^)]*\).write\(', "use opener.write() instead"), (r'(?i)descend[e]nt', "the proper spelling is descendAnt"), (r'\.debug\(\_', "don't mark debug messages for translation"), (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"), (r'^\s*except\s*:', "naked except clause", r'#.*re-raises'), ( r'^\s*except\s([^\(,]+|\([^\)]+\))\s*,', 'legacy exception syntax; use "as" instead of ","', ), (r'release\(.*wlock, .*lock\)', "wrong lock release order"), (r'\bdef\s+__bool__\b', "__bool__ should be __nonzero__ in Python 2"), ( r'os\.path\.join\(.*, *(""|\'\')\)', "use pathutil.normasprefix(path) instead of os.path.join(path, '')", ), (r'\s0[0-7]+\b', 'legacy octal syntax; use "0o" prefix instead of "0"'), # XXX only catch mutable arguments on the first line of the definition (r'def.*[( ]\w+=\{\}', "don't use mutable default arguments"), (r'\butil\.Abort\b', "directly use error.Abort"), ( r'^@(\w*\.)?cachefunc', "module-level @cachefunc is risky, please avoid", ), ( r'^(from|import) mercurial\.(cext|pure|cffi)', "use mercurial.policy.importmod instead", ), (r'\.next\(\)', "don't use .next(), use next(...)"), ( r'([a-z]*).revision\(\1\.node\(', "don't convert rev to node before passing to revision(nodeorrev)", ), (r'platform\.system\(\)', "don't use platform.system(), use pycompat"), ], # warnings [], ] # patterns to check normal *.py files pypats = [ [ # Ideally, these should be placed in "commonpypats" for # consistency of coding rules in Mercurial source tree. # But on the other hand, these are not so seriously required for # python code fragments embedded in test scripts. Fixing test # scripts for these patterns requires many changes, and has less # profit than effort. (r'raise Exception', "don't raise generic exceptions"), (r'[\s\(](open|file)\([^)]*\)\.read\(', "use util.readfile() instead"), ( r'[\s\(](open|file)\([^)]*\)\.write\(', "use util.writefile() instead", ), ( r'^[\s\(]*(open(er)?|file)\([^)]*\)(?!\.close\(\))', "always assign an opened file to a variable, and close it afterwards", ), ( r'[\s\(](open|file)\([^)]*\)\.(?!close\(\))', "always assign an opened file to a variable, and close it afterwards", ), (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"), (r'^import atexit', "don't use atexit, use ui.atexit"), # rules depending on implementation of repquote() ( r' x+[xpqo%APM][\'"]\n\s+[\'"]x', 'string join across lines with no space', ), ( r'''(?x)ui\.(status|progress|write|note|warn)\( [ \t\n#]* (?# any strings/comments might precede a string, which # contains translatable message) b?((['"]|\'\'\'|""")[ \npq%bAPMxno]*(['"]|\'\'\'|""")[ \t\n#]+)* (?# sequence consisting of below might precede translatable message # - formatting string: "% 10s", "%05d", "% -3.2f", "%*s", "%%" ... # - escaped character: "\\", "\n", "\0" ... # - character other than '%', 'b' as '\', and 'x' as alphabet) (['"]|\'\'\'|""") ((%([ n]?[PM]?([np]+|A))?x)|%%|b[bnx]|[ \nnpqAPMo])*x (?# this regexp can't use [^...] style, # because _preparepats forcibly adds "\n" into [^...], # even though this regexp wants match it against "\n")''', "missing _() in ui message (use `noi18n` method to hide false-positives)", ), ] + commonpypats[0], # warnings [ # rules depending on implementation of repquote() (r'(^| )pp +xxxxqq[ \n][^\n]', "add two newlines after '.. note::'"), ] + commonpypats[1], ] # patterns to check *.py for embedded ones in test script embeddedpypats = [ [] + commonpypats[0], # warnings [] + commonpypats[1], ] # common filters to convert *.py commonpyfilters = [ ( r"""(?msx)(?P\#.*?$)| ((?P('''|\"\"\"|(?(([^\\]|\\.)*?)) (?P=quote))""", reppython, ), ] # pattern only for mercurial and extensions core_py_pats = [ [ # Windows tend to get confused about capitalization of the drive letter # # see mercurial.windows.abspath for details ( r'os\.path\.abspath', "use util.abspath instead (windows)", r'#.*re-exports', ), ], # warnings [], ] # filters to convert normal *.py files pyfilters = [] + commonpyfilters # non-filter patterns pynfpats = [ [ (r'pycompat\.osname\s*[=!]=\s*[\'"]nt[\'"]', "use pycompat.iswindows"), (r'pycompat\.osname\s*[=!]=\s*[\'"]posix[\'"]', "use pycompat.isposix"), ( r'pycompat\.sysplatform\s*[!=]=\s*[\'"]darwin[\'"]', "use pycompat.isdarwin", ), ], # warnings [], ] # filters to convert *.py for embedded ones in test script embeddedpyfilters = [] + commonpyfilters # extension non-filter patterns pyextnfpats = [ [(r'^"""\n?[A-Z]', "don't capitalize docstring title")], # warnings [], ] txtfilters = [] txtpats = [ [ (r'\s$', 'trailing whitespace'), ('.. note::[ \n][^\n]', 'add two newlines after note::'), ], [], ] cpats = [ [ (r'//', "don't use //-style comments"), (r'\S\t', "don't use tabs except for indent"), (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"), (r'(while|if|do|for)\(', "use space after while/if/do/for"), (r'return\(', "return is not a function"), (r' ;', "no space before ;"), (r'[^;] \)', "no space before )"), (r'[)][{]', "space between ) and {"), (r'\w+\* \w+', "use int *foo, not int* foo"), (r'\W\([^\)]+\) \w+', "use (int)foo, not (int) foo"), (r'\w+ (\+\+|--)', "use foo++, not foo ++"), (r'\w,\w', "missing whitespace after ,"), (r'^[^#]\w[+/*]\w', "missing whitespace in expression"), (r'\w\s=\s\s+\w', "gratuitous whitespace after ="), (r'^#\s+\w', "use #foo, not # foo"), (r'[^\n]\Z', "no trailing newline"), (r'^\s*#import\b', "use only #include in standard C code"), (r'strcpy\(', "don't use strcpy, use strlcpy or memcpy"), (r'strcat\(', "don't use strcat"), # rules depending on implementation of repquote() ], # warnings [ # rules depending on implementation of repquote() ], ] cfilters = [ (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment), (r'''(?P(?([^"]|\\")+)"(?!")''', repquote), (r'''(#\s*include\s+<)([^>]+)>''', repinclude), (r'(\()([^)]+\))', repcallspaces), ] inutilpats = [ [ (r'\bui\.', "don't use ui in util"), ], # warnings [], ] inrevlogpats = [ [ (r'\brepo\.', "don't use repo in revlog"), ], # warnings [], ] webtemplatefilters = [] webtemplatepats = [ [], [ ( r'{desc(\|(?!websub|firstline)[^\|]*)+}', 'follow desc keyword with either firstline or websub', ), ], ] allfilesfilters = [] allfilespats = [ [ ( r'(http|https)://[a-zA-Z0-9./]*selenic.com/', 'use mercurial-scm.org domain URL', ), ( r'mercurial@selenic\.com', 'use mercurial-scm.org domain for mercurial ML address', ), ( r'mercurial-devel@selenic\.com', 'use mercurial-scm.org domain for mercurial-devel ML address', ), ], # warnings [], ] py3pats = [ [ ( r'os\.environ', "use encoding.environ instead (py3)", r'#.*re-exports', ), (r'os\.name', "use pycompat.osname instead (py3)"), (r'os\.getcwd', "use encoding.getcwd instead (py3)", r'#.*re-exports'), (r'os\.sep', "use pycompat.ossep instead (py3)"), (r'os\.pathsep', "use pycompat.ospathsep instead (py3)"), (r'os\.altsep', "use pycompat.osaltsep instead (py3)"), (r'sys\.platform', "use pycompat.sysplatform instead (py3)"), (r'getopt\.getopt', "use pycompat.getoptb instead (py3)"), (r'os\.getenv', "use encoding.environ.get instead"), (r'(? %s" % line) self._lastseen = msgid print(" " + msg) _defaultlogger = norepeatlogger() def getblame(f): lines = [] for l in os.popen('hg annotate -un %s' % f): start, line = l.split(':', 1) user, rev = start.split() lines.append((line[1:-1], user, rev)) return lines def checkfile( f, logfunc=_defaultlogger.log, maxerr=None, warnings=False, blame=False, debug=False, lineno=True, ): """checks style and portability of a given file :f: filepath :logfunc: function used to report error logfunc(filename, linenumber, linecontent, errormessage) :maxerr: number of error to display before aborting. Set to false (default) to report all errors return True if no error is found, False otherwise. """ result = True try: with opentext(f) as fp: try: pre = fp.read() except UnicodeDecodeError as e: print("%s while reading %s" % (e, f)) return result except OSError as e: print("Skipping %s, %s" % (f, str(e).split(':', 1)[0])) return result # context information shared while single checkfile() invocation context = {'blamecache': None} for name, match, magic, filters, pats in checks: if debug: print(name, f) if not (re.match(match, f) or (magic and re.search(magic, pre))): if debug: print( "Skipping %s for %s it doesn't match %s" % (name, match, f) ) continue if "no-" "check-code" in pre: # If you're looking at this line, it's because a file has: # no- check- code # but the reason to output skipping is to make life for # tests easier. So, instead of writing it with a normal # spelling, we write it with the expected spelling from # tests/test-check-code.t print("Skipping %s it has no-che?k-code (glob)" % f) return "Skip" # skip checking this file fc = _checkfiledata( name, f, pre, filters, pats, context, logfunc, maxerr, warnings, blame, debug, lineno, ) if fc: result = False if f.endswith('.t') and "no-" "check-code" not in pre: if debug: print("Checking embedded code in %s" % f) prelines = pre.splitlines() embeddederros = [] for name, embedded, filters, pats in embeddedchecks: # "reset curmax at each repetition" treats maxerr as "max # nubmer of errors in an actual file per entry of # (embedded)checks" curmaxerr = maxerr for found in embedded(f, prelines, embeddederros): filename, starts, ends, code = found fc = _checkfiledata( name, f, code, filters, pats, context, logfunc, curmaxerr, warnings, blame, debug, lineno, offset=starts - 1, ) if fc: result = False if curmaxerr: if fc >= curmaxerr: break curmaxerr -= fc return result def _checkfiledata( name, f, filedata, filters, pats, context, logfunc, maxerr, warnings, blame, debug, lineno, offset=None, ): """Execute actual error check for file data :name: of the checking category :f: filepath :filedata: content of a file :filters: to be applied before checking :pats: to detect errors :context: a dict of information shared while single checkfile() invocation Valid keys: 'blamecache'. :logfunc: function used to report error logfunc(filename, linenumber, linecontent, errormessage) :maxerr: number of error to display before aborting, or False to report all errors :warnings: whether warning level checks should be applied :blame: whether blame information should be displayed at error reporting :debug: whether debug information should be displayed :lineno: whether lineno should be displayed at error reporting :offset: line number offset of 'filedata' in 'f' for checking an embedded code fragment, or None (offset=0 is different from offset=None) returns number of detected errors. """ blamecache = context['blamecache'] if offset is None: lineoffset = 0 else: lineoffset = offset fc = 0 pre = post = filedata if True: # TODO: get rid of this redundant 'if' block for p, r in filters: post = re.sub(p, r, post) nerrs = len(pats[0]) # nerr elements are errors if warnings: pats = pats[0] + pats[1] else: pats = pats[0] # print post # uncomment to show filtered version if debug: print("Checking %s for %s" % (name, f)) prelines = None errors = [] for i, pat in enumerate(pats): if len(pat) == 3: p, msg, ignore = pat else: p, msg = pat ignore = None if i >= nerrs: msg = "warning: " + msg pos = 0 n = 0 for m in p.finditer(post): if prelines is None: prelines = pre.splitlines() postlines = post.splitlines(True) start = m.start() while n < len(postlines): step = len(postlines[n]) if pos + step > start: break pos += step n += 1 l = prelines[n] if ignore and re.search(ignore, l, re.MULTILINE): if debug: print( "Skipping %s for %s:%s (ignore pattern)" % (name, f, (n + lineoffset)) ) continue bd = "" if blame: bd = 'working directory' if blamecache is None: blamecache = getblame(f) context['blamecache'] = blamecache if (n + lineoffset) < len(blamecache): bl, bu, br = blamecache[(n + lineoffset)] if offset is None and bl == l: bd = '%s@%s' % (bu, br) elif offset is not None and bl.endswith(l): # "offset is not None" means "checking # embedded code fragment". In this case, # "l" does not have information about the # beginning of an *original* line in the # file (e.g. ' > '). # Therefore, use "str.endswith()", and # show "maybe" for a little loose # examination. bd = '%s@%s, maybe' % (bu, br) errors.append((f, lineno and (n + lineoffset + 1), l, msg, bd)) errors.sort() for e in errors: logfunc(*e) fc += 1 if maxerr and fc >= maxerr: print(" (too many errors, giving up)") break return fc def main(): parser = optparse.OptionParser("%prog [options] [files | -]") parser.add_option( "-w", "--warnings", action="store_true", help="include warning-level checks", ) parser.add_option( "-p", "--per-file", type="int", help="max warnings per file" ) parser.add_option( "-b", "--blame", action="store_true", help="use annotate to generate blame info", ) parser.add_option( "", "--debug", action="store_true", help="show debug information" ) parser.add_option( "", "--nolineno", action="store_false", dest='lineno', help="don't show line numbers", ) parser.set_defaults( per_file=15, warnings=False, blame=False, debug=False, lineno=True ) (options, args) = parser.parse_args() if len(args) == 0: check = glob.glob("*") elif args == ['-']: # read file list from stdin check = sys.stdin.read().splitlines() else: check = args _preparepats() ret = 0 for f in check: if not checkfile( f, maxerr=options.per_file, warnings=options.warnings, blame=options.blame, debug=options.debug, lineno=options.lineno, ): ret = 1 return ret if __name__ == "__main__": sys.exit(main()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/check-commit0000755000175000017500000000622115060516737017321 0ustar00alpharealphare#!/usr/bin/env python3 # # Copyright 2014 Olivia Mackall # # A tool/hook to run basic sanity checks on commits/patches for # submission to Mercurial. Install by adding the following to your # .hg/hgrc: # # [hooks] # pretxncommit = contrib/check-commit # # The hook can be temporarily bypassed with: # # $ BYPASS= hg commit # # See also: https://mercurial-scm.org/wiki/ContributingChanges import os import re import sys commitheader = r"^(?:# [^\n]*\n)*" afterheader = commitheader + r"(?!#)" beforepatch = afterheader + r"(?!\n(?!@@))" errors = [ (beforepatch + r".*[(]bc[)]", "(BC) needs to be uppercase"), ( beforepatch + r".*[(]issue \d\d\d", "no space allowed between issue and number", ), (beforepatch + r".*[(]bug(\d|\s)", "use (issueDDDD) instead of bug"), (commitheader + r"# User [^@\n]+\n", "username is not an email address"), ( commitheader + r"(?!merge with )[^#]\S+[^:] ", "summary line doesn't start with 'topic: '", ), (afterheader + r"[A-Z][a-z]\S+", "don't capitalize summary lines"), (afterheader + r"^\S+: *[A-Z][a-z]\S+", "don't capitalize summary lines"), ( afterheader + r"\S*[^A-Za-z0-9-_]\S*: ", "summary keyword should be most user-relevant one-word command or topic", ), (afterheader + r".*\.\s*\n", "don't add trailing period on summary line"), (afterheader + r".{79,}", "summary line too long (limit is 78)"), ] word = re.compile(r'\S') def nonempty(first, second): if word.search(first): return first return second def checkcommit(commit, node=None): exitcode = 0 printed = node is None hits = [] signtag = ( afterheader + r'Added (tag [^ ]+|signature) for changeset [a-f0-9]{12}' ) if re.search(signtag, commit): return 0 for exp, msg in errors: for m in re.finditer(exp, commit): end = m.end() trailing = re.search(r'(\\n)+$', exp) if trailing: end -= len(trailing.group()) / 2 hits.append((end, exp, msg)) if hits: hits.sort() pos = 0 last = '' for n, l in enumerate(commit.splitlines(True)): pos += len(l) while len(hits): end, exp, msg = hits[0] if pos < end: break if not printed: printed = True print("node: %s" % node) print("%d: %s" % (n, msg)) print(" %s" % nonempty(l, last)[:-1]) if "BYPASS" not in os.environ: exitcode = 1 del hits[0] last = nonempty(l, last) return exitcode def readcommit(node): return os.popen("hg export %s" % node).read() if __name__ == "__main__": exitcode = 0 node = os.environ.get("HG_NODE") if node: commit = readcommit(node) exitcode = checkcommit(commit) elif sys.argv[1:]: for node in sys.argv[1:]: exitcode |= checkcommit(readcommit(node), node) else: commit = sys.stdin.read() exitcode = checkcommit(commit) sys.exit(exitcode) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757584863.0 mercurial-7.1.1/contrib/check-config.py0000755000175000017500000001275415060516737017735 0ustar00alpharealphare#!/usr/bin/env python3 # # check-config - a config flag documentation checker for Mercurial # # Copyright 2015 Olivia Mackall # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. import re import sys foundopts = {} documented = {} allowinconsistent = set() configre = re.compile( br''' # Function call ui\.config(?P|int|bool|list)\( # First argument. ['"](?P
\S+)['"],\s* # Second argument ['"](?P