##// END OF EJS Templates
linelog: add a Python implementation of the linelog datastructure...
Augie Fackler -
r38819:752d858a default draft obsolete
parent child Browse files
Show More

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

@@ -0,0 +1,6 b''
1 {
2 "conduit_uri": "https://phab.mercurial-scm.org/api",
3 "repository.callsign": "HG",
4 "arc.land.onto.default": "@",
5 "base": "hg:.^"
6 }
@@ -0,0 +1,13 b''
1 BasedOnStyle: LLVM
2 IndentWidth: 8
3 UseTab: ForIndentation
4 BreakBeforeBraces: Linux
5 AllowShortIfStatementsOnASingleLine: false
6 IndentCaseLabels: false
7 AllowShortBlocksOnASingleLine: false
8 AllowShortFunctionsOnASingleLine: false
9 IncludeCategories:
10 - Regex: '^<'
11 Priority: 1
12 - Regex: '^"'
13 Priority: 2
@@ -0,0 +1,18 b''
1 # See http://EditorConfig.org for the specification
2
3 root = true
4
5 [*.py]
6 indent_size = 4
7 indent_style = space
8 trim_trailing_whitespace = true
9
10 [*.{c,h}]
11 indent_size = 8
12 indent_style = tab
13 trim_trailing_whitespace = true
14
15 [*.t]
16 indent_size = 2
17 indent_style = space
18 trim_trailing_whitespace = false
@@ -0,0 +1,68 b''
1 syntax: glob
2
3 *.elc
4 *.tmp
5 *.orig
6 *.rej
7 *~
8 *.mergebackup
9 *.o
10 *.so
11 *.dll
12 *.exe
13 *.pyd
14 *.pyc
15 *.pyo
16 *$py.class
17 *.swp
18 *.prof
19 *.zip
20 \#*\#
21 .\#*
22 tests/.coverage*
23 tests/.testtimes*
24 tests/.hypothesis
25 tests/hypothesis-generated
26 tests/annotated
27 tests/exceptions
28 tests/*.err
29 tests/htmlcov
30 build
31 contrib/chg/chg
32 contrib/hgsh/hgsh
33 contrib/vagrant/.vagrant
34 dist
35 packages
36 doc/common.txt
37 doc/*.[0-9]
38 doc/*.[0-9].txt
39 doc/*.[0-9].gendoc.txt
40 doc/*.[0-9].{x,ht}ml
41 MANIFEST
42 MANIFEST.in
43 patches
44 mercurial/__modulepolicy__.py
45 mercurial/__version__.py
46 mercurial/hgpythonlib.h
47 mercurial.egg-info
48 .DS_Store
49 tags
50 cscope.*
51 .idea/*
52 .asv/*
53 i18n/hg.pot
54 locale/*/LC_MESSAGES/hg.mo
55 hgext/__index__.py
56
57 rust/target/
58
59 # Generated wheels
60 wheelhouse/
61
62 syntax: regexp
63 ^\.pc/
64 ^\.(pydev)?project
65
66 # hackable windows distribution additions
67 ^hg-python
68 ^hg.py$
@@ -0,0 +1,170 b''
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
79 335a558f81dc73afeab4d7be63617392b130117f 0 iQIVAwUAUiZrIyBXgaxoKi1yAQK2iw//cquNqqSkc8Re5/TZT9I6NH+lh6DbOKjJP0Xl1Wqq0K+KSIUgZG4G32ovaEb2l5X0uY+3unRPiZ0ebl0YSw4Fb2ZiPIADXLBTOYRrY2Wwd3tpJeGI6wEgZt3SfcITV/g7NJrCjT3FlYoSOIayrExM80InSdcEM0Q3Rx6HKzY2acyxzgZeAtAW5ohFvHilSvY6p5Gcm4+QptMxvw45GPdreUmjeXZxNXNXZ8P+MjMz/QJbai/N7PjmK8lqnhkBsT48Ng/KhhmOkGntNJ2/ImBWLFGcWngSvJ7sfWwnyhndvGhe0Hq1NcCf7I8TjNDxU5TR+m+uW7xjXdLoDbUjBdX4sKXnh8ZjbYiODKBOrrDq25cf8nA/tnpKyE/qsVy60kOk6loY4XKiYmn1V49Ta0emmDx0hqo3HgxHHsHX0NDnGdWGol7cPRET0RzVobKq1A0jnrhPooWidvLh9bPzLonrWDo+ib+DuySoRkuYUK4pgZJ2mbg6daFOBEZygkSyRB8bo1UQUP7EgQDrWe4khb/5GHEfDkrQz3qu/sXvc0Ir1mOUWBFPHC2DjjCn/oMJuUkG1SwM8l2Bfv7h67ssES6YQ2+RjOix4yid7EXS/Ogl45PzCIPSI5+BbNs10JhE0w5uErBHlF53EDTe/TSLc+GU6DB6PP6dH912Njdr3jpNSUQ=
80 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
@@ -0,0 +1,183 b''
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
@@ -0,0 +1,11 b''
1 {
2 // Enforcing
3 "eqeqeq" : true, // true: Require triple equals (===) for comparison
4 "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
5 "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc.
6 "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters.
7 "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
8
9 // Environments
10 "browser" : true // Web Browser (window, document, etc)
11 }
@@ -0,0 +1,13 b''
1 Our full contribution guidelines are in our wiki, please see:
2
3 https://www.mercurial-scm.org/wiki/ContributingChanges
4
5 If you just want a checklist to follow, you can go straight to
6
7 https://www.mercurial-scm.org/wiki/ContributingChanges#Submission_checklist
8
9 If you can't run the entire testsuite for some reason (it can be
10 difficult on Windows), please at least run `contrib/check-code.py` on
11 any files you've modified and run `python contrib/check-commit` on any
12 commits you've made (for example, `python contrib/check-commit
13 273ce12ad8f1` will report some style violations on a very old commit).
@@ -0,0 +1,41 b''
1 [This file is here for historical purposes, all recent contributors
2 should appear in the changelog directly]
3
4 Andrea Arcangeli <andrea at suse.de>
5 Thomas Arendsen Hein <thomas at intevation.de>
6 Goffredo Baroncelli <kreijack at libero.it>
7 Muli Ben-Yehuda <mulix at mulix.org>
8 Mikael Berthe <mikael at lilotux.net>
9 Benoit Boissinot <bboissin at gmail.com>
10 Brendan Cully <brendan at kublai.com>
11 Vincent Danjean <vdanjean.ml at free.fr>
12 Jake Edge <jake at edge2.net>
13 Michael Fetterman <michael.fetterman at intel.com>
14 Edouard Gomez <ed.gomez at free.fr>
15 Eric Hopper <hopper at omnifarious.org>
16 Alecs King <alecsk at gmail.com>
17 Volker Kleinfeld <Volker.Kleinfeld at gmx.de>
18 Vadim Lebedev <vadim at mbdsys.com>
19 Christopher Li <hg at chrisli.org>
20 Chris Mason <mason at suse.com>
21 Colin McMillen <mcmillen at cs.cmu.edu>
22 Wojciech Milkowski <wmilkowski at interia.pl>
23 Chad Netzer <chad.netzer at gmail.com>
24 Bryan O'Sullivan <bos at serpentine.com>
25 Vicent Seguí Pascual <vseguip at gmail.com>
26 Sean Perry <shaleh at speakeasy.net>
27 Nguyen Anh Quynh <aquynh at gmail.com>
28 Ollivier Robert <roberto at keltia.freenix.fr>
29 Alexander Schremmer <alex at alexanderweb.de>
30 Arun Sharma <arun at sharma-home.net>
31 Josef "Jeff" Sipek <jeffpc at optonline.net>
32 Kevin Smith <yarcs at qualitycode.com>
33 TK Soh <teekaysoh at yahoo.com>
34 Radoslaw Szkodzinski <astralstorm at gorzow.mm.pl>
35 Samuel Tardieu <sam at rfc1149.net>
36 K Thananchayan <thananck at yahoo.com>
37 Andrew Thompson <andrewkt at aktzero.com>
38 Michael S. Tsirkin <mst at mellanox.co.il>
39 Rafael Villar Burke <pachi at mmn-arquitectos.com>
40 Tristan Wibberley <tristan at wibberley.org>
41 Mark Williamson <mark.williamson at cl.cam.ac.uk>
@@ -0,0 +1,339 b''
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12 freedom to share and change it. By contrast, the GNU General Public
13 License is intended to guarantee your freedom to share and change free
14 software--to make sure the software is free for all its users. This
15 General Public License applies to most of the Free Software
16 Foundation's software and to any other program whose authors commit to
17 using it. (Some other Free Software Foundation software is covered by
18 the GNU Lesser General Public License instead.) You can apply it to
19 your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22 price. Our General Public Licenses are designed to make sure that you
23 have the freedom to distribute copies of free software (and charge for
24 this service if you wish), that you receive source code or can get it
25 if you want it, that you can change the software or use pieces of it
26 in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29 anyone to deny you these rights or to ask you to surrender the rights.
30 These restrictions translate to certain responsibilities for you if you
31 distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34 gratis or for a fee, you must give the recipients all the rights that
35 you have. You must make sure that they, too, receive or can get the
36 source code. And you must show them these terms so they know their
37 rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40 (2) offer you this license which gives you legal permission to copy,
41 distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44 that everyone understands that there is no warranty for this free
45 software. If the software is modified by someone else and passed on, we
46 want its recipients to know that what they have is not the original, so
47 that any problems introduced by others will not reflect on the original
48 authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51 patents. We wish to avoid the danger that redistributors of a free
52 program will individually obtain patent licenses, in effect making the
53 program proprietary. To prevent this, we have made it clear that any
54 patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57 modification follow.
58
59 GNU GENERAL PUBLIC LICENSE
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
62 0. This License applies to any program or other work which contains
63 a notice placed by the copyright holder saying it may be distributed
64 under the terms of this General Public License. The "Program", below,
65 refers to any such program or work, and a "work based on the Program"
66 means either the Program or any derivative work under copyright law:
67 that is to say, a work containing the Program or a portion of it,
68 either verbatim or with modifications and/or translated into another
69 language. (Hereinafter, translation is included without limitation in
70 the term "modification".) Each licensee is addressed as "you".
71
72 Activities other than copying, distribution and modification are not
73 covered by this License; they are outside its scope. The act of
74 running the Program is not restricted, and the output from the Program
75 is covered only if its contents constitute a work based on the
76 Program (independent of having been made by running the Program).
77 Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80 source code as you receive it, in any medium, provided that you
81 conspicuously and appropriately publish on each copy an appropriate
82 copyright notice and disclaimer of warranty; keep intact all the
83 notices that refer to this License and to the absence of any warranty;
84 and give any other recipients of the Program a copy of this License
85 along with the Program.
86
87 You may charge a fee for the physical act of transferring a copy, and
88 you may at your option offer warranty protection in exchange for a fee.
89
90 2. You may modify your copy or copies of the Program or any portion
91 of it, thus forming a work based on the Program, and copy and
92 distribute such modifications or work under the terms of Section 1
93 above, provided that you also meet all of these conditions:
94
95 a) You must cause the modified files to carry prominent notices
96 stating that you changed the files and the date of any change.
97
98 b) You must cause any work that you distribute or publish, that in
99 whole or in part contains or is derived from the Program or any
100 part thereof, to be licensed as a whole at no charge to all third
101 parties under the terms of this License.
102
103 c) If the modified program normally reads commands interactively
104 when run, you must cause it, when started running for such
105 interactive use in the most ordinary way, to print or display an
106 announcement including an appropriate copyright notice and a
107 notice that there is no warranty (or else, saying that you provide
108 a warranty) and that users may redistribute the program under
109 these conditions, and telling the user how to view a copy of this
110 License. (Exception: if the Program itself is interactive but
111 does not normally print such an announcement, your work based on
112 the Program is not required to print an announcement.)
113
114 These requirements apply to the modified work as a whole. If
115 identifiable sections of that work are not derived from the Program,
116 and can be reasonably considered independent and separate works in
117 themselves, then this License, and its terms, do not apply to those
118 sections when you distribute them as separate works. But when you
119 distribute the same sections as part of a whole which is a work based
120 on the Program, the distribution of the whole must be on the terms of
121 this License, whose permissions for other licensees extend to the
122 entire whole, and thus to each and every part regardless of who wrote it.
123
124 Thus, it is not the intent of this section to claim rights or contest
125 your rights to work written entirely by you; rather, the intent is to
126 exercise the right to control the distribution of derivative or
127 collective works based on the Program.
128
129 In addition, mere aggregation of another work not based on the Program
130 with the Program (or with a work based on the Program) on a volume of
131 a storage or distribution medium does not bring the other work under
132 the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135 under Section 2) in object code or executable form under the terms of
136 Sections 1 and 2 above provided that you also do one of the following:
137
138 a) Accompany it with the complete corresponding machine-readable
139 source code, which must be distributed under the terms of Sections
140 1 and 2 above on a medium customarily used for software interchange; or,
141
142 b) Accompany it with a written offer, valid for at least three
143 years, to give any third party, for a charge no more than your
144 cost of physically performing source distribution, a complete
145 machine-readable copy of the corresponding source code, to be
146 distributed under the terms of Sections 1 and 2 above on a medium
147 customarily used for software interchange; or,
148
149 c) Accompany it with the information you received as to the offer
150 to distribute corresponding source code. (This alternative is
151 allowed only for noncommercial distribution and only if you
152 received the program in object code or executable form with such
153 an offer, in accord with Subsection b above.)
154
155 The source code for a work means the preferred form of the work for
156 making modifications to it. For an executable work, complete source
157 code means all the source code for all modules it contains, plus any
158 associated interface definition files, plus the scripts used to
159 control compilation and installation of the executable. However, as a
160 special exception, the source code distributed need not include
161 anything that is normally distributed (in either source or binary
162 form) with the major components (compiler, kernel, and so on) of the
163 operating system on which the executable runs, unless that component
164 itself accompanies the executable.
165
166 If distribution of executable or object code is made by offering
167 access to copy from a designated place, then offering equivalent
168 access to copy the source code from the same place counts as
169 distribution of the source code, even though third parties are not
170 compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173 except as expressly provided under this License. Any attempt
174 otherwise to copy, modify, sublicense or distribute the Program is
175 void, and will automatically terminate your rights under this License.
176 However, parties who have received copies, or rights, from you under
177 this License will not have their licenses terminated so long as such
178 parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181 signed it. However, nothing else grants you permission to modify or
182 distribute the Program or its derivative works. These actions are
183 prohibited by law if you do not accept this License. Therefore, by
184 modifying or distributing the Program (or any work based on the
185 Program), you indicate your acceptance of this License to do so, and
186 all its terms and conditions for copying, distributing or modifying
187 the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190 Program), the recipient automatically receives a license from the
191 original licensor to copy, distribute or modify the Program subject to
192 these terms and conditions. You may not impose any further
193 restrictions on the recipients' exercise of the rights granted herein.
194 You are not responsible for enforcing compliance by third parties to
195 this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198 infringement or for any other reason (not limited to patent issues),
199 conditions are imposed on you (whether by court order, agreement or
200 otherwise) that contradict the conditions of this License, they do not
201 excuse you from the conditions of this License. If you cannot
202 distribute so as to satisfy simultaneously your obligations under this
203 License and any other pertinent obligations, then as a consequence you
204 may not distribute the Program at all. For example, if a patent
205 license would not permit royalty-free redistribution of the Program by
206 all those who receive copies directly or indirectly through you, then
207 the only way you could satisfy both it and this License would be to
208 refrain entirely from distribution of the Program.
209
210 If any portion of this section is held invalid or unenforceable under
211 any particular circumstance, the balance of the section is intended to
212 apply and the section as a whole is intended to apply in other
213 circumstances.
214
215 It is not the purpose of this section to induce you to infringe any
216 patents or other property right claims or to contest validity of any
217 such claims; this section has the sole purpose of protecting the
218 integrity of the free software distribution system, which is
219 implemented by public license practices. Many people have made
220 generous contributions to the wide range of software distributed
221 through that system in reliance on consistent application of that
222 system; it is up to the author/donor to decide if he or she is willing
223 to distribute software through any other system and a licensee cannot
224 impose that choice.
225
226 This section is intended to make thoroughly clear what is believed to
227 be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230 certain countries either by patents or by copyrighted interfaces, the
231 original copyright holder who places the Program under this License
232 may add an explicit geographical distribution limitation excluding
233 those countries, so that distribution is permitted only in or among
234 countries not thus excluded. In such case, this License incorporates
235 the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238 of the General Public License from time to time. Such new versions will
239 be similar in spirit to the present version, but may differ in detail to
240 address new problems or concerns.
241
242 Each version is given a distinguishing version number. If the Program
243 specifies a version number of this License which applies to it and "any
244 later version", you have the option of following the terms and conditions
245 either of that version or of any later version published by the Free
246 Software Foundation. If the Program does not specify a version number of
247 this License, you may choose any version ever published by the Free Software
248 Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251 programs whose distribution conditions are different, write to the author
252 to ask for permission. For software which is copyrighted by the Free
253 Software Foundation, write to the Free Software Foundation; we sometimes
254 make exceptions for this. Our decision will be guided by the two goals
255 of preserving the free status of all derivatives of our free software and
256 of promoting the sharing and reuse of software generally.
257
258 NO WARRANTY
259
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 POSSIBILITY OF SUCH DAMAGES.
279
280 END OF TERMS AND CONDITIONS
281
282 How to Apply These Terms to Your New Programs
283
284 If you develop a new program, and you want it to be of the greatest
285 possible use to the public, the best way to achieve this is to make it
286 free software which everyone can redistribute and change under these terms.
287
288 To do so, attach the following notices to the program. It is safest
289 to attach them to the start of each source file to most effectively
290 convey the exclusion of warranty; and each file should have at least
291 the "copyright" line and a pointer to where the full notice is found.
292
293 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) <year> <name of author>
295
296 This program is free software; you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or
299 (at your option) any later version.
300
301 This program is distributed in the hope that it will be useful,
302 but WITHOUT ANY WARRANTY; without even the implied warranty of
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details.
305
306 You should have received a copy of the GNU General Public License along
307 with this program; if not, write to the Free Software Foundation, Inc.,
308 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
310 Also add information on how to contact you by electronic and paper mail.
311
312 If the program is interactive, make it output a short notice like this
313 when it starts in an interactive mode:
314
315 Gnomovision version 69, Copyright (C) year name of author
316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 This is free software, and you are welcome to redistribute it
318 under certain conditions; type `show c' for details.
319
320 The hypothetical commands `show w' and `show c' should show the appropriate
321 parts of the General Public License. Of course, the commands you use may
322 be called something other than `show w' and `show c'; they could even be
323 mouse-clicks or menu items--whatever suits your program.
324
325 You should also get your employer (if you work as a programmer) or your
326 school, if any, to sign a "copyright disclaimer" for the program, if
327 necessary. Here is a sample; alter the names:
328
329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
332 <signature of Ty Coon>, 1 April 1989
333 Ty Coon, President of Vice
334
335 This General Public License does not permit incorporating your program into
336 proprietary programs. If your program is a subroutine library, you may
337 consider it more useful to permit linking proprietary applications with the
338 library. If this is what you want to do, use the GNU Lesser General
339 Public License instead of this License.
@@ -0,0 +1,243 b''
1 # If you want to change PREFIX, do not just edit it below. The changed
2 # value wont get passed on to recursive make calls. You should instead
3 # override the variable on the command like:
4 #
5 # % make PREFIX=/opt/ install
6
7 export PREFIX=/usr/local
8 PYTHON=python
9 $(eval HGROOT := $(shell pwd))
10 HGPYTHONS ?= $(HGROOT)/build/pythons
11 PURE=
12 PYFILES:=$(shell find mercurial hgext doc -name '*.py')
13 DOCFILES=mercurial/help/*.txt
14 export LANGUAGE=C
15 export LC_ALL=C
16 TESTFLAGS ?= $(shell echo $$HGTESTFLAGS)
17 OSXVERSIONFLAGS ?= $(shell echo $$OSXVERSIONFLAGS)
18
19 # Set this to e.g. "mingw32" to use a non-default compiler.
20 COMPILER=
21
22 COMPILERFLAG_tmp_ =
23 COMPILERFLAG_tmp_${COMPILER} ?= -c $(COMPILER)
24 COMPILERFLAG=${COMPILERFLAG_tmp_${COMPILER}}
25
26 help:
27 @echo 'Commonly used make targets:'
28 @echo ' all - build program and documentation'
29 @echo ' install - install program and man pages to $$PREFIX ($(PREFIX))'
30 @echo ' install-home - install with setup.py install --home=$$HOME ($(HOME))'
31 @echo ' local - build for inplace usage'
32 @echo ' tests - run all tests in the automatic test suite'
33 @echo ' test-foo - run only specified tests (e.g. test-merge1.t)'
34 @echo ' dist - run all tests and create a source tarball in dist/'
35 @echo ' clean - remove files created by other targets'
36 @echo ' (except installed files or dist source tarball)'
37 @echo ' update-pot - update i18n/hg.pot'
38 @echo
39 @echo 'Example for a system-wide installation under /usr/local:'
40 @echo ' make all && su -c "make install" && hg version'
41 @echo
42 @echo 'Example for a local installation (usable in this directory):'
43 @echo ' make local && ./hg version'
44
45 all: build doc
46
47 local:
48 $(PYTHON) setup.py $(PURE) \
49 build_py -c -d . \
50 build_ext $(COMPILERFLAG) -i \
51 build_hgexe $(COMPILERFLAG) -i \
52 build_mo
53 env HGRCPATH= $(PYTHON) hg version
54
55 build:
56 $(PYTHON) setup.py $(PURE) build $(COMPILERFLAG)
57
58 wheel:
59 FORCE_SETUPTOOLS=1 $(PYTHON) setup.py $(PURE) bdist_wheel $(COMPILERFLAG)
60
61 doc:
62 $(MAKE) -C doc
63
64 cleanbutpackages:
65 -$(PYTHON) setup.py clean --all # ignore errors from this command
66 find contrib doc hgext hgext3rd i18n mercurial tests hgdemandimport \
67 \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';'
68 rm -f MANIFEST MANIFEST.in hgext/__index__.py tests/*.err
69 rm -f mercurial/__modulepolicy__.py
70 if test -d .hg; then rm -f mercurial/__version__.py; fi
71 rm -rf build mercurial/locale
72 $(MAKE) -C doc clean
73 $(MAKE) -C contrib/chg distclean
74
75 clean: cleanbutpackages
76 rm -rf packages
77
78 install: install-bin install-doc
79
80 install-bin: build
81 $(PYTHON) setup.py $(PURE) install --root="$(DESTDIR)/" --prefix="$(PREFIX)" --force
82
83 install-doc: doc
84 cd doc && $(MAKE) $(MFLAGS) install
85
86 install-home: install-home-bin install-home-doc
87
88 install-home-bin: build
89 $(PYTHON) setup.py $(PURE) install --home="$(HOME)" --prefix="" --force
90
91 install-home-doc: doc
92 cd doc && $(MAKE) $(MFLAGS) PREFIX="$(HOME)" install
93
94 MANIFEST-doc:
95 $(MAKE) -C doc MANIFEST
96
97 MANIFEST.in: MANIFEST-doc
98 hg manifest | sed -e 's/^/include /' > MANIFEST.in
99 echo include mercurial/__version__.py >> MANIFEST.in
100 sed -e 's/^/include /' < doc/MANIFEST >> MANIFEST.in
101
102 dist: tests dist-notests
103
104 dist-notests: doc MANIFEST.in
105 TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist
106
107 check: tests
108
109 tests:
110 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS)
111
112 test-%:
113 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@
114
115 testpy-%:
116 @echo Looking for Python $* in $(HGPYTHONS)
117 [ -e $(HGPYTHONS)/$*/bin/python ] || ( \
118 cd $$(mktemp --directory --tmpdir) && \
119 $(MAKE) -f $(HGROOT)/contrib/Makefile.python PYTHONVER=$* PREFIX=$(HGPYTHONS)/$* python )
120 cd tests && $(HGPYTHONS)/$*/bin/python run-tests.py $(TESTFLAGS)
121
122 check-code:
123 hg manifest | xargs python contrib/check-code.py
124
125 format-c:
126 clang-format --style file -i \
127 `hg files 'set:(**.c or **.cc or **.h) and not "listfile:contrib/clang-format-ignorelist"'`
128
129 update-pot: i18n/hg.pot
130
131 i18n/hg.pot: $(PYFILES) $(DOCFILES) i18n/posplit i18n/hggettext
132 $(PYTHON) i18n/hggettext mercurial/commands.py \
133 hgext/*.py hgext/*/__init__.py \
134 mercurial/fileset.py mercurial/revset.py \
135 mercurial/templatefilters.py \
136 mercurial/templatefuncs.py \
137 mercurial/templatekw.py \
138 mercurial/filemerge.py \
139 mercurial/hgweb/webcommands.py \
140 mercurial/util.py \
141 $(DOCFILES) > i18n/hg.pot.tmp
142 # All strings marked for translation in Mercurial contain
143 # ASCII characters only. But some files contain string
144 # literals like this '\037\213'. xgettext thinks it has to
145 # parse them even though they are not marked for translation.
146 # Extracting with an explicit encoding of ISO-8859-1 will make
147 # xgettext "parse" and ignore them.
148 echo $(PYFILES) | xargs \
149 xgettext --package-name "Mercurial" \
150 --msgid-bugs-address "<mercurial-devel@mercurial-scm.org>" \
151 --copyright-holder "Matt Mackall <mpm@selenic.com> and others" \
152 --from-code ISO-8859-1 --join --sort-by-file --add-comments=i18n: \
153 -d hg -p i18n -o hg.pot.tmp
154 $(PYTHON) i18n/posplit i18n/hg.pot.tmp
155 # The target file is not created before the last step. So it never is in
156 # an intermediate state.
157 mv -f i18n/hg.pot.tmp i18n/hg.pot
158
159 %.po: i18n/hg.pot
160 # work on a temporary copy for never having a half completed target
161 cp $@ $@.tmp
162 msgmerge --no-location --update $@.tmp $^
163 mv -f $@.tmp $@
164
165 # Packaging targets
166
167 packaging_targets := \
168 centos5 \
169 centos6 \
170 centos7 \
171 deb \
172 docker-centos5 \
173 docker-centos6 \
174 docker-centos7 \
175 docker-debian-jessie \
176 docker-debian-stretch \
177 docker-fedora20 \
178 docker-fedora21 \
179 docker-fedora28 \
180 docker-ubuntu-trusty \
181 docker-ubuntu-trusty-ppa \
182 docker-ubuntu-xenial \
183 docker-ubuntu-xenial-ppa \
184 docker-ubuntu-artful \
185 docker-ubuntu-artful-ppa \
186 docker-ubuntu-bionic \
187 docker-ubuntu-bionic-ppa \
188 fedora20 \
189 fedora21 \
190 fedora28 \
191 linux-wheels \
192 linux-wheels-x86_64 \
193 linux-wheels-i686 \
194 ppa
195
196 # Forward packaging targets for convenience.
197 $(packaging_targets):
198 $(MAKE) -C contrib/packaging $@
199
200 osx:
201 rm -rf build/mercurial
202 /usr/bin/python2.7 setup.py install --optimize=1 \
203 --root=build/mercurial/ --prefix=/usr/local/ \
204 --install-lib=/Library/Python/2.7/site-packages/
205 make -C doc all install DESTDIR="$(PWD)/build/mercurial/"
206 # Place a bogon .DS_Store file in the target dir so we can be
207 # sure it doesn't get included in the final package.
208 touch build/mercurial/.DS_Store
209 # install zsh completions - this location appears to be
210 # searched by default as of macOS Sierra.
211 install -d build/mercurial/usr/local/share/zsh/site-functions/
212 install -m 0644 contrib/zsh_completion build/mercurial/usr/local/share/zsh/site-functions/_hg
213 # install bash completions - there doesn't appear to be a
214 # place that's searched by default for bash, so we'll follow
215 # the lead of Apple's git install and just put it in a
216 # location of our own.
217 install -d build/mercurial/usr/local/hg/contrib/
218 install -m 0644 contrib/bash_completion build/mercurial/usr/local/hg/contrib/hg-completion.bash
219 make -C contrib/chg \
220 HGPATH=/usr/local/bin/hg \
221 PYTHON=/usr/bin/python2.7 \
222 HGEXTDIR=/Library/Python/2.7/site-packages/hgext \
223 DESTDIR=../../build/mercurial \
224 PREFIX=/usr/local \
225 clean install
226 mkdir -p $${OUTPUTDIR:-dist}
227 HGVER=$$(python contrib/genosxversion.py $(OSXVERSIONFLAGS) build/mercurial/Library/Python/2.7/site-packages/mercurial/__version__.py) && \
228 OSXVER=$$(sw_vers -productVersion | cut -d. -f1,2) && \
229 pkgbuild --filter \\.DS_Store --root build/mercurial/ \
230 --identifier org.mercurial-scm.mercurial \
231 --version "$${HGVER}" \
232 build/mercurial.pkg && \
233 productbuild --distribution contrib/packaging/macosx/distribution.xml \
234 --package-path build/ \
235 --version "$${HGVER}" \
236 --resources contrib/packaging/macosx/ \
237 "$${OUTPUTDIR:-dist/}"/Mercurial-"$${HGVER}"-macosx"$${OSXVER}".pkg
238
239 .PHONY: help all local build doc cleanbutpackages clean install install-bin \
240 install-doc install-home install-home-bin install-home-doc \
241 dist dist-notests check tests check-code format-c update-pot \
242 $(packaging_targets) \
243 osx
@@ -0,0 +1,20 b''
1 Mercurial
2 =========
3
4 Mercurial is a fast, easy to use, distributed revision control tool
5 for software developers.
6
7 Basic install::
8
9 $ make # see install targets
10 $ make install # do a system-wide install
11 $ hg debuginstall # sanity-check setup
12 $ hg # see help
13
14 Running without installing::
15
16 $ make local # build for inplace usage
17 $ ./hg --version # should show the latest version
18
19 See https://mercurial-scm.org/ for detailed installation
20 instructions, platform-specific notes, and Mercurial user information.
@@ -0,0 +1,76 b''
1 PYTHONVER=2.7.14
2 PYTHONNAME=python-
3 PREFIX=$(HOME)/bin/prefix-$(PYTHONNAME)$(PYTHONVER)
4 SYMLINKDIR=$(HOME)/bin
5
6 help:
7 @echo
8 @echo 'Make a custom installation of a Python version'
9 @echo
10 @echo 'Common make parameters:'
11 @echo ' PYTHONVER=... [$(PYTHONVER)]'
12 @echo ' PREFIX=... [$(PREFIX)]'
13 @echo ' SYMLINKDIR=... [$(SYMLINKDIR) creating $(PYTHONNAME)$(PYTHONVER)]'
14 @echo
15 @echo 'Common make targets:'
16 @echo ' python - install Python $$PYTHONVER in $$PREFIX'
17 @echo ' symlink - create a $$SYMLINKDIR/$(PYTHONNAME)$$PYTHONVER symlink'
18 @echo
19 @echo 'Example: create a temporary Python installation:'
20 @echo ' $$ make -f Makefile.python python PYTHONVER=${PYTHONVER} PREFIX=/tmp/p27'
21 @echo ' $$ /tmp/p27/bin/python -V'
22 @echo ' Python 2.7'
23 @echo
24 @echo 'Some external libraries are required for building Python: zlib bzip2 openssl.'
25 @echo 'Make sure their development packages are installed systemwide.'
26 # fedora: yum install zlib-devel bzip2-devel openssl-devel
27 # debian: apt-get install zlib1g-dev libbz2-dev libssl-dev
28 @echo
29 @echo 'To build a nice collection of interesting Python versions:'
30 @echo ' $$ for v in 2.{6{,.1,.2,.9},7{,.8,.10}}; do'
31 @echo ' make -f Makefile.python symlink PYTHONVER=$$v || break; done'
32 @echo 'To run a Mercurial test on all these Python versions:'
33 @echo ' $$ for py in `cd ~/bin && ls $(PYTHONNAME)2.*`; do'
34 @echo ' echo $$py; $$py run-tests.py test-http.t; echo; done'
35 @echo
36
37 export LANGUAGE=C
38 export LC_ALL=C
39
40 python: $(PREFIX)/bin/python docutils
41 printf 'import sys, zlib, bz2, docutils, ssl' | $(PREFIX)/bin/python
42
43 PYTHON_SRCDIR=Python-$(PYTHONVER)
44 PYTHON_SRCFILE=$(PYTHON_SRCDIR).tgz
45
46 $(PREFIX)/bin/python:
47 [ -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) ]
48 rm -rf $(PYTHON_SRCDIR)
49 tar xf $(PYTHON_SRCFILE)
50 # Debian/Ubuntu disables SSLv2,3 the hard way, disable it on old Pythons too
51 -sed -i 's,self.*SSLv[23]_method(),0;//\0,g' $(PYTHON_SRCDIR)/Modules/_ssl.c
52 # Find multiarch system libraries on Ubuntu and disable fortify error when setting argv
53 LDFLAGS="-L/usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH`"; \
54 BASECFLAGS=-U_FORTIFY_SOURCE; \
55 export LDFLAGS BASECFLAGS; \
56 cd $(PYTHON_SRCDIR) && ./configure --prefix=$(PREFIX) && make all SVNVERSION=pwd && make install
57 printf 'import sys, zlib, bz2, ssl' | $(PREFIX)/bin/python
58 rm -rf $(PYTHON_SRCDIR)
59
60 DOCUTILSVER=0.12
61 DOCUTILS_SRCDIR=docutils-$(DOCUTILSVER)
62 DOCUTILS_SRCFILE=$(DOCUTILS_SRCDIR).tar.gz
63
64 docutils: $(PREFIX)/bin/python
65 @$(PREFIX)/bin/python -c 'import docutils' || ( set -ex; \
66 [ -f $(DOCUTILS_SRCFILE) ] || wget http://downloads.sourceforge.net/project/docutils/docutils/$(DOCUTILSVER)/$(DOCUTILS_SRCFILE) || [ -f $(DOCUTILS_SRCFILE) ]; \
67 rm -rf $(DOCUTILS_SRCDIR); \
68 tar xf $(DOCUTILS_SRCFILE); \
69 cd $(DOCUTILS_SRCDIR) && $(PREFIX)/bin/python setup.py install --prefix=$(PREFIX); \
70 $(PREFIX)/bin/python -c 'import docutils'; \
71 rm -rf $(DOCUTILS_SRCDIR); )
72
73 symlink: python $(SYMLINKDIR)
74 ln -sf $(PREFIX)/bin/python $(SYMLINKDIR)/$(PYTHONNAME)$(PYTHONVER)
75
76 .PHONY: help python docutils symlink
@@ -0,0 +1,141 b''
1 # All revsets ever used with revsetbenchmarks.py script
2 #
3 # The goal of this file is to gather all revsets ever used for benchmarking
4 # revset's performance. It should be used to gather revsets that test a
5 # specific usecase or a specific implementation of revset predicates.
6 # If you are working on the smartset implementation itself, check
7 # 'base-revsets.txt'.
8 #
9 # Please update this file with any revsets you use for benchmarking a change so
10 # that future contributors can easily find and retest it when doing further
11 # modification. Feel free to highlight interesting variants if needed.
12
13
14 ## Revset from this section are all extracted from changelog when this file was
15 # created. Feel free to dig and improve documentation.
16
17 # Used in revision da05fe01170b
18 (20000::) - (20000)
19 # Used in revision 95af98616aa7
20 parents(20000)
21 # Used in revision 186fd06283b4
22 (_intlist('20000\x0020001')) and merge()
23 # Used in revision 911f5a6579d1
24 p1(20000)
25 p2(10000)
26 # Used in revision b6dc3b79bb25
27 0::
28 # Used in revision faf4f63533ff
29 bookmark()
30 # Used in revision 22ba2c0825da
31 tip~25
32 # Used in revision 0cf46b8298fe
33 bisect(range)
34 # Used in revision 5b65429721d5
35 divergent()
36 # Used in revision 6261b9c549a2
37 file(COPYING)
38 # Used in revision 44f471102f3a
39 follow(COPYING)
40 # Used in revision 8040a44aab1c
41 origin(tip)
42 # Used in revision bbf4f3dfd700
43 rev(25)
44 # Used in revision a428db9ab61d
45 p1()
46 # Used in revision c1546d7400ef
47 min(0::)
48 # Used in revision 546fa6576815
49 author(lmoscovicz) or author(mpm)
50 author(mpm) or author(lmoscovicz)
51 # Used in revision 9bfe68357c01
52 public() and id("d82e2223f132")
53 # Used in revision ba89f7b542c9
54 rev(25)
55 # Used in revision eb763217152a
56 rev(210000)
57 # Used in revision 69524a05a7fa
58 10:100
59 parents(10):parents(100)
60 # Used in revision 6f1b8b3f12fd
61 100~5
62 parents(100)~5
63 (100~5)~5
64 # Used in revision 7a42e5d4c418
65 children(tip~100)
66 # Used in revision 7e8737e6ab08
67 100^1
68 parents(100)^1
69 (100^1)^1
70 # Used in revision 30e0dcd7c5ff
71 matching(100)
72 matching(parents(100))
73 # Used in revision aafeaba22826
74 0|1|2|3|4|5|6|7|8|9
75 # Used in revision 33c7a94d4dd0
76 tip:0
77 # Used in revision 7d369fae098e
78 (0:100000)
79 # Used in revision b333ca94403d
80 0 + 1 + 2 + ... + 200
81 0 + 1 + 2 + ... + 1000
82 sort(0 + 1 + 2 + ... + 200)
83 sort(0 + 1 + 2 + ... + 1000)
84 # Used in revision 7fbef7932af9
85 first(0 + 1 + 2 + ... + 1000)
86 # Used in revision ceaf04bb14ff
87 0:1000
88 # Used in revision 262e6ad93885
89 not public()
90 (tip~1000::) - public()
91 not public() and branch("default")
92 # Used in revision 15412bba5a68
93 0::tip
94
95 ## all the revsets from this section have been taken from the former central file
96 # for revset's benchmarking, they are undocumented for this reason.
97 all()
98 draft()
99 ::tip
100 draft() and ::tip
101 ::tip and draft()
102 author(lmoscovicz)
103 author(mpm)
104 ::p1(p1(tip))::
105 public()
106 :10000 and public()
107 :10000 and draft()
108 (not public() - obsolete())
109
110 # The one below is used by rebase
111 (children(ancestor(tip~5, tip)) and ::(tip~5))::
112
113 # those two `roots(...)` inputs are close to what phase movement use.
114 roots((tip~100::) - (tip~100::tip))
115 roots((0::) - (0::tip))
116
117 # more roots testing
118 roots(tip~100:)
119 roots(:42)
120 roots(not public())
121 roots((0:tip)::)
122 roots(0::tip)
123 42:68 and roots(42:tip)
124 # Used in revision f140d6207cca
125 roots(0:tip)
126 # test disjoint set with multiple roots
127 roots((:42) + (tip~42:))
128
129 # Testing the behavior of "head()" in various situations
130 head()
131 head() - public()
132 draft() and head()
133 head() and author("mpm")
134
135 # testing the mutable phases set
136 draft()
137 secret()
138
139 # test finding common ancestors
140 heads(commonancestors(last(head(), 2)))
141 heads(commonancestors(head()))
@@ -0,0 +1,13 b''
1 {
2 "version": 1,
3 "project": "mercurial",
4 "project_url": "https://mercurial-scm.org/",
5 "repo": "..",
6 "branches": ["default", "stable"],
7 "environment_type": "virtualenv",
8 "show_commit_url": "https://www.mercurial-scm.org/repo/hg/rev/",
9 "benchmark_dir": "benchmarks",
10 "env_dir": "../.asv/env",
11 "results_dir": "../.asv/results",
12 "html_dir": "../.asv/html"
13 }
@@ -0,0 +1,49 b''
1 # Base Revsets to be used with revsetbenchmarks.py script
2 #
3 # The goal of this file is to gather a limited amount of revsets that allow a
4 # good coverage of the internal revsets mechanisms. Revsets included should not
5 # be selected for their individual implementation, but for what they reveal of
6 # the internal implementation of smartsets classes (and their interactions).
7 #
8 # Use and update this file when you change internal implementation of these
9 # smartsets classes. Please include a comment explaining what each of your
10 # addition is testing. Also check if your changes to the smartset class makes
11 # some of the tests inadequate and replace them with a new one testing the same
12 # behavior.
13 #
14 # If you want to benchmark revsets predicate itself, check 'all-revsets.txt'.
15 #
16 # The current content of this file is currently likely not reaching this goal
17 # entirely, feel free, to audit its content and comment on each revset to
18 # highlight what internal mechanisms they test.
19
20 all()
21 draft()
22 ::tip
23 draft() and ::tip
24 ::tip and draft()
25 0::tip
26 roots(0::tip)
27 author(lmoscovicz)
28 author(mpm)
29 author(lmoscovicz) or author(mpm)
30 author(mpm) or author(lmoscovicz)
31 tip:0
32 0::
33 # those two `roots(...)` inputs are close to what phase movement use.
34 roots((tip~100::) - (tip~100::tip))
35 roots((0::) - (0::tip))
36 42:68 and roots(42:tip)
37 ::p1(p1(tip))::
38 public()
39 :10000 and public()
40 draft()
41 :10000 and draft()
42 roots((0:tip)::)
43 (not public() - obsolete())
44 (_intlist('20000\x0020001')) and merge()
45 parents(20000)
46 (20000::) - (20000)
47 # The one below is used by rebase
48 (children(ancestor(tip~5, tip)) and ::(tip~5))::
49 heads(commonancestors(last(head(), 2)))
This diff has been collapsed as it changes many lines, (644 lines changed) Show them Hide them
@@ -0,0 +1,644 b''
1 # bash completion for the Mercurial distributed SCM -*- sh -*-
2
3 # Docs:
4 #
5 # If you source this file from your .bashrc, bash should be able to
6 # complete a command line that uses hg with all the available commands
7 # and options and sometimes even arguments.
8 #
9 # Mercurial allows you to define additional commands through extensions.
10 # Bash should be able to automatically figure out the name of these new
11 # commands and their options. See below for how to define _hg_opt_foo
12 # and _hg_cmd_foo functions to fine-tune the completion for option and
13 # non-option arguments, respectively.
14 #
15 #
16 # Notes about completion for specific commands:
17 #
18 # - the completion function for the email command from the patchbomb
19 # extension will try to call _hg_emails to get a list of e-mail
20 # addresses. It's up to the user to define this function. For
21 # example, put the addresses of the lists that you usually patchbomb
22 # in ~/.patchbomb-to and the addresses that you usually use to send
23 # the patchbombs in ~/.patchbomb-from and use something like this:
24 #
25 # _hg_emails()
26 # {
27 # if [ -r ~/.patchbomb-$1 ]; then
28 # cat ~/.patchbomb-$1
29 # fi
30 # }
31 #
32 #
33 # Writing completion functions for additional commands:
34 #
35 # If it exists, the function _hg_cmd_foo will be called without
36 # arguments to generate the completion candidates for the hg command
37 # "foo". If the command receives some arguments that aren't options
38 # even though they start with a "-", you can define a function called
39 # _hg_opt_foo to generate the completion candidates. If _hg_opt_foo
40 # doesn't return 0, regular completion for options is attempted.
41 #
42 # In addition to the regular completion variables provided by bash,
43 # the following variables are also set:
44 # - $hg - the hg program being used (e.g. /usr/bin/hg)
45 # - $cmd - the name of the hg command being completed
46 # - $cmd_index - the index of $cmd in $COMP_WORDS
47 # - $cur - the current argument being completed
48 # - $prev - the argument before $cur
49 # - $global_args - "|"-separated list of global options that accept
50 # an argument (e.g. '--cwd|-R|--repository')
51 # - $canonical - 1 if we canonicalized $cmd before calling the function
52 # 0 otherwise
53 #
54
55 shopt -s extglob
56
57 _hg_cmd()
58 {
59 HGPLAIN=1 "$hg" "$@" 2>/dev/null
60 }
61
62 _hg_commands()
63 {
64 local commands
65 commands="$(HGPLAINEXCEPT=alias _hg_cmd debugcomplete "$cur")" || commands=""
66 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$commands' -- "$cur"))
67 }
68
69 _hg_paths()
70 {
71 local paths="$(_hg_cmd paths -q)"
72 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$paths' -- "$cur"))
73 }
74
75 _hg_repos()
76 {
77 local i
78 for i in $(compgen -d -- "$cur"); do
79 test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i")
80 done
81 }
82
83 _hg_debugpathcomplete()
84 {
85 local files="$(_hg_cmd debugpathcomplete $1 "$cur")"
86 local IFS=$'\n'
87 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
88 }
89
90 _hg_status()
91 {
92 if [ -z "$HGCOMPLETE_NOSTATUS" ]; then
93 local files="$(_hg_cmd status -n$1 "glob:$cur**")"
94 local IFS=$'\n'
95 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
96 fi
97 }
98
99 _hg_branches()
100 {
101 local branches="$(_hg_cmd branches -q)"
102 local IFS=$'\n'
103 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$branches' -- "$cur"))
104 }
105
106 _hg_bookmarks()
107 {
108 local bookmarks="$(_hg_cmd bookmarks -q)"
109 local IFS=$'\n'
110 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$bookmarks' -- "$cur"))
111 }
112
113 _hg_labels()
114 {
115 local labels="$(_hg_cmd debugnamecomplete "$cur")"
116 local IFS=$'\n'
117 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$labels' -- "$cur"))
118 }
119
120 # this is "kind of" ugly...
121 _hg_count_non_option()
122 {
123 local i count=0
124 local filters="$1"
125
126 for ((i=1; $i<=$COMP_CWORD; i++)); do
127 if [[ "${COMP_WORDS[i]}" != -* ]]; then
128 if [[ ${COMP_WORDS[i-1]} == @($filters|$global_args) ]]; then
129 continue
130 fi
131 count=$(($count + 1))
132 fi
133 done
134
135 echo $(($count - 1))
136 }
137
138 _hg_fix_wordlist()
139 {
140 local LASTCHAR=' '
141 if [ ${#COMPREPLY[@]} = 1 ]; then
142 [ -d "$COMPREPLY" ] && LASTCHAR=/
143 COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR")
144 else
145 for ((i=0; i < ${#COMPREPLY[@]}; i++)); do
146 [ -d "${COMPREPLY[$i]}" ] && COMPREPLY[$i]=${COMPREPLY[$i]}/
147 done
148 fi
149 }
150
151 _hg()
152 {
153 local cur prev cmd cmd_index opts i aliashg
154 # global options that receive an argument
155 local global_args='--cwd|-R|--repository'
156 local hg="$1"
157 local canonical=0
158
159 aliashg=$(alias $hg 2>/dev/null)
160 if [[ -n "$aliashg" ]]; then
161 aliashg=${aliashg#"alias $hg='"}
162 aliashg=${aliashg%"'"}
163 hg=$aliashg
164 fi
165
166 COMPREPLY=()
167 cur="$2"
168 prev="$3"
169
170 # searching for the command
171 # (first non-option argument that doesn't follow a global option that
172 # receives an argument)
173 for ((i=1; $i<=$COMP_CWORD; i++)); do
174 if [[ ${COMP_WORDS[i]} != -* ]]; then
175 if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
176 cmd="${COMP_WORDS[i]}"
177 cmd_index=$i
178 break
179 fi
180 fi
181 done
182
183 if [[ "$cur" == -* ]]; then
184 if [ "$(type -t "_hg_opt_$cmd")" = function ] && "_hg_opt_$cmd"; then
185 _hg_fix_wordlist
186 return
187 fi
188
189 opts=$(HGPLAINEXCEPT=alias _hg_cmd debugcomplete --options "$cmd")
190
191 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur"))
192 _hg_fix_wordlist
193 return
194 fi
195
196 # global options
197 case "$prev" in
198 -R|--repository)
199 _hg_paths
200 _hg_repos
201 _hg_fix_wordlist
202 return
203 ;;
204 --cwd)
205 # Stick with default bash completion
206 _hg_fix_wordlist
207 return
208 ;;
209 esac
210
211 if [ -z "$cmd" ] || [ $COMP_CWORD -eq $i ]; then
212 _hg_commands
213 _hg_fix_wordlist
214 return
215 fi
216
217 # try to generate completion candidates for whatever command the user typed
218 local help
219 if _hg_command_specific; then
220 _hg_fix_wordlist
221 return
222 fi
223
224 # canonicalize the command name and try again
225 help=$(_hg_cmd help "$cmd")
226 if [ $? -ne 0 ]; then
227 # Probably either the command doesn't exist or it's ambiguous
228 return
229 fi
230 cmd=${help#hg }
231 cmd=${cmd%%[$' \n']*}
232 canonical=1
233 _hg_command_specific
234 _hg_fix_wordlist
235 }
236
237 _hg_command_specific()
238 {
239 if [ "$(type -t "_hg_cmd_$cmd")" = function ]; then
240 "_hg_cmd_$cmd"
241 return 0
242 fi
243
244 if [ "$cmd" != status ]; then
245 case "$prev" in
246 -r|--rev)
247 if [[ $canonical = 1 || status != "$cmd"* ]]; then
248 _hg_labels
249 return 0
250 fi
251 return 1
252 ;;
253 -B|--bookmark)
254 if [[ $canonical = 1 || status != "$cmd"* ]]; then
255 _hg_bookmarks
256 return 0
257 fi
258 return 1
259 ;;
260 -b|--branch)
261 if [[ $canonical = 1 || status != "$cmd"* ]]; then
262 _hg_branches
263 return 0
264 fi
265 return 1
266 ;;
267 esac
268 fi
269
270 local aliascmd=$(_hg_cmd showconfig alias.$cmd | awk '{print $1}')
271 [ -n "$aliascmd" ] && cmd=$aliascmd
272
273 case "$cmd" in
274 help)
275 _hg_commands
276 ;;
277 export)
278 if _hg_ext_mq_patchlist qapplied && [ "${COMPREPLY[*]}" ]; then
279 return 0
280 fi
281 _hg_labels
282 ;;
283 manifest|update|up|checkout|co)
284 _hg_labels
285 ;;
286 pull|push|outgoing|incoming)
287 _hg_paths
288 _hg_repos
289 ;;
290 paths)
291 _hg_paths
292 ;;
293 add)
294 _hg_status "u"
295 ;;
296 merge)
297 _hg_labels
298 ;;
299 commit|ci|record|amend)
300 _hg_status "mar"
301 ;;
302 remove|rm)
303 _hg_debugpathcomplete -n
304 ;;
305 forget)
306 _hg_debugpathcomplete -fa
307 ;;
308 diff)
309 _hg_status "mar"
310 ;;
311 revert)
312 _hg_status "mard"
313 ;;
314 clone)
315 local count=$(_hg_count_non_option)
316 if [ $count = 1 ]; then
317 _hg_paths
318 fi
319 _hg_repos
320 ;;
321 debugindex|debugindexdot)
322 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.i" -- "$cur"))
323 ;;
324 debugdata)
325 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.d" -- "$cur"))
326 ;;
327 *)
328 return 1
329 ;;
330 esac
331
332 return 0
333 }
334
335 complete -o bashdefault -o default -o nospace -F _hg hg \
336 || complete -o default -o nospace -F _hg hg
337
338
339 # Completion for commands provided by extensions
340
341 # bookmarks
342 _hg_cmd_bookmarks()
343 {
344 _hg_bookmarks
345 return
346 }
347
348 # mq
349 _hg_ext_mq_patchlist()
350 {
351 local patches
352 patches=$(_hg_cmd $1)
353 if [ $? -eq 0 ] && [ "$patches" ]; then
354 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$patches' -- "$cur"))
355 return 0
356 fi
357 return 1
358 }
359
360 _hg_ext_mq_queues()
361 {
362 local root=$(_hg_cmd root)
363 local n
364 for n in $(cd "$root"/.hg && compgen -d -- "$cur"); do
365 # I think we're usually not interested in the regular "patches" queue
366 # so just filter it.
367 if [ "$n" != patches ] && [ -e "$root/.hg/$n/series" ]; then
368 COMPREPLY=(${COMPREPLY[@]:-} "$n")
369 fi
370 done
371 }
372
373 _hg_cmd_qpop()
374 {
375 if [[ "$prev" = @(-n|--name) ]]; then
376 _hg_ext_mq_queues
377 return
378 fi
379 _hg_ext_mq_patchlist qapplied
380 }
381
382 _hg_cmd_qpush()
383 {
384 if [[ "$prev" = @(-n|--name) ]]; then
385 _hg_ext_mq_queues
386 return
387 fi
388 _hg_ext_mq_patchlist qunapplied
389 }
390
391 _hg_cmd_qgoto()
392 {
393 if [[ "$prev" = @(-n|--name) ]]; then
394 _hg_ext_mq_queues
395 return
396 fi
397 _hg_ext_mq_patchlist qseries
398 }
399
400 _hg_cmd_qdelete()
401 {
402 local qcmd=qunapplied
403 if [[ "$prev" = @(-r|--rev) ]]; then
404 qcmd=qapplied
405 fi
406 _hg_ext_mq_patchlist $qcmd
407 }
408
409 _hg_cmd_qfinish()
410 {
411 if [[ "$prev" = @(-a|--applied) ]]; then
412 return
413 fi
414 _hg_ext_mq_patchlist qapplied
415 }
416
417 _hg_cmd_qsave()
418 {
419 if [[ "$prev" = @(-n|--name) ]]; then
420 _hg_ext_mq_queues
421 return
422 fi
423 }
424
425 _hg_cmd_rebase() {
426 if [[ "$prev" = @(-s|--source|-d|--dest|-b|--base|-r|--rev) ]]; then
427 _hg_labels
428 return
429 fi
430 }
431
432 _hg_cmd_strip()
433 {
434 if [[ "$prev" = @(-B|--bookmark) ]]; then
435 _hg_bookmarks
436 return
437 fi
438 _hg_labels
439 }
440
441 _hg_cmd_qcommit()
442 {
443 local root=$(_hg_cmd root)
444 # this is run in a sub-shell, so we can't use _hg_status
445 local files=$(cd "$root/.hg/patches" && _hg_cmd status -nmar)
446 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
447 }
448
449 _hg_cmd_qfold()
450 {
451 _hg_ext_mq_patchlist qunapplied
452 }
453
454 _hg_cmd_qrename()
455 {
456 _hg_ext_mq_patchlist qseries
457 }
458
459 _hg_cmd_qheader()
460 {
461 _hg_ext_mq_patchlist qseries
462 }
463
464 _hg_cmd_qclone()
465 {
466 local count=$(_hg_count_non_option)
467 if [ $count = 1 ]; then
468 _hg_paths
469 fi
470 _hg_repos
471 }
472
473 _hg_ext_mq_guards()
474 {
475 _hg_cmd qselect --series | sed -e 's/^.//'
476 }
477
478 _hg_cmd_qselect()
479 {
480 local guards=$(_hg_ext_mq_guards)
481 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$guards' -- "$cur"))
482 }
483
484 _hg_cmd_qguard()
485 {
486 local prefix=''
487
488 if [[ "$cur" == +* ]]; then
489 prefix=+
490 elif [[ "$cur" == -* ]]; then
491 prefix=-
492 fi
493 local ncur=${cur#[-+]}
494
495 if ! [ "$prefix" ]; then
496 _hg_ext_mq_patchlist qseries
497 return
498 fi
499
500 local guards=$(_hg_ext_mq_guards)
501 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -P $prefix -W '$guards' -- "$ncur"))
502 }
503
504 _hg_opt_qguard()
505 {
506 local i
507 for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do
508 if [[ ${COMP_WORDS[i]} != -* ]]; then
509 if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
510 _hg_cmd_qguard
511 return 0
512 fi
513 elif [ "${COMP_WORDS[i]}" = -- ]; then
514 _hg_cmd_qguard
515 return 0
516 fi
517 done
518 return 1
519 }
520
521 _hg_cmd_qqueue()
522 {
523 local q
524 local queues
525 local opts="--list --create --rename --delete --purge"
526
527 queues=$( _hg_cmd qqueue --quiet )
528
529 COMPREPLY=( $( compgen -W "${opts} ${queues}" "${cur}" ) )
530 }
531
532
533 # hbisect
534 _hg_cmd_bisect()
535 {
536 local i subcmd
537
538 # find the sub-command
539 for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do
540 if [[ ${COMP_WORDS[i]} != -* ]]; then
541 if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
542 subcmd="${COMP_WORDS[i]}"
543 break
544 fi
545 fi
546 done
547
548 if [ -z "$subcmd" ] || [ $COMP_CWORD -eq $i ] || [ "$subcmd" = help ]; then
549 COMPREPLY=(${COMPREPLY[@]:-}
550 $(compgen -W 'bad good help init next reset' -- "$cur"))
551 return
552 fi
553
554 case "$subcmd" in
555 good|bad)
556 _hg_labels
557 ;;
558 esac
559
560 return
561 }
562
563
564 # patchbomb
565 _hg_cmd_email()
566 {
567 case "$prev" in
568 -c|--cc|-t|--to|-f|--from|--bcc)
569 # we need an e-mail address. let the user provide a function
570 # to get them
571 if [ "$(type -t _hg_emails)" = function ]; then
572 local arg=to
573 if [[ "$prev" == @(-f|--from) ]]; then
574 arg=from
575 fi
576 local addresses=$(_hg_emails $arg)
577 COMPREPLY=(${COMPREPLY[@]:-}
578 $(compgen -W '$addresses' -- "$cur"))
579 fi
580 return
581 ;;
582 -m|--mbox)
583 # fallback to standard filename completion
584 return
585 ;;
586 -s|--subject)
587 # free form string
588 return
589 ;;
590 esac
591
592 _hg_labels
593 return
594 }
595
596
597 # gpg
598 _hg_cmd_sign()
599 {
600 _hg_labels
601 }
602
603
604 # transplant
605 _hg_cmd_transplant()
606 {
607 case "$prev" in
608 -s|--source)
609 _hg_paths
610 _hg_repos
611 return
612 ;;
613 --filter)
614 # standard filename completion
615 return
616 ;;
617 esac
618
619 # all other transplant options values and command parameters are revisions
620 _hg_labels
621 return
622 }
623
624 # shelve
625 _hg_shelves()
626 {
627 local shelves="$(_hg_cmd shelve -ql)"
628 local IFS=$'\n'
629 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$shelves' -- "$cur"))
630 }
631
632 _hg_cmd_shelve()
633 {
634 if [[ "$prev" = @(-d|--delete|-l|--list|-p|--patch|--stat) ]]; then
635 _hg_shelves
636 else
637 _hg_status "mard"
638 fi
639 }
640
641 _hg_cmd_unshelve()
642 {
643 _hg_shelves
644 }
@@ -0,0 +1,99 b''
1 # Randomized torture test generation for bdiff
2
3 from __future__ import absolute_import, print_function
4 import random
5 import sys
6
7 from mercurial import (
8 mdiff,
9 )
10
11 def reducetest(a, b):
12 tries = 0
13 reductions = 0
14 print("reducing...")
15 while tries < 1000:
16 a2 = "\n".join(l for l in a.splitlines()
17 if random.randint(0, 100) > 0) + "\n"
18 b2 = "\n".join(l for l in b.splitlines()
19 if random.randint(0, 100) > 0) + "\n"
20 if a2 == a and b2 == b:
21 continue
22 if a2 == b2:
23 continue
24 tries += 1
25
26 try:
27 test1(a, b)
28 except Exception as inst:
29 reductions += 1
30 tries = 0
31 a = a2
32 b = b2
33
34 print("reduced:", reductions, len(a) + len(b),
35 repr(a), repr(b))
36 try:
37 test1(a, b)
38 except Exception as inst:
39 print("failed:", inst)
40
41 sys.exit(0)
42
43 def test1(a, b):
44 d = mdiff.textdiff(a, b)
45 if not d:
46 raise ValueError("empty")
47 c = mdiff.patches(a, [d])
48 if c != b:
49 raise ValueError("bad")
50
51 def testwrap(a, b):
52 try:
53 test1(a, b)
54 return
55 except Exception as inst:
56 pass
57 print("exception:", inst)
58 reducetest(a, b)
59
60 def test(a, b):
61 testwrap(a, b)
62 testwrap(b, a)
63
64 def rndtest(size, noise):
65 a = []
66 src = " aaaaaaaabbbbccd"
67 for x in xrange(size):
68 a.append(src[random.randint(0, len(src) - 1)])
69
70 while True:
71 b = [c for c in a if random.randint(0, 99) > noise]
72 b2 = []
73 for c in b:
74 b2.append(c)
75 while random.randint(0, 99) < noise:
76 b2.append(src[random.randint(0, len(src) - 1)])
77 if b2 != a:
78 break
79
80 a = "\n".join(a) + "\n"
81 b = "\n".join(b2) + "\n"
82
83 test(a, b)
84
85 maxvol = 10000
86 startsize = 2
87 while True:
88 size = startsize
89 count = 0
90 while size < maxvol:
91 print(size)
92 volume = 0
93 while volume < maxvol:
94 rndtest(size, 2)
95 volume += size
96 count += 2
97 size *= 2
98 maxvol *= 4
99 startsize *= 4
@@ -0,0 +1,113 b''
1 # __init__.py - asv benchmark suite
2 #
3 # Copyright 2016 Logilab SA <contact@logilab.fr>
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
7
8 # "historical portability" policy of contrib/benchmarks:
9 #
10 # We have to make this code work correctly with current mercurial stable branch
11 # and if possible with reasonable cost with early Mercurial versions.
12
13 '''ASV (https://asv.readthedocs.io) benchmark suite
14
15 Benchmark are parameterized against reference repositories found in the
16 directory pointed by the REPOS_DIR environment variable.
17
18 Invocation example:
19
20 $ export REPOS_DIR=~/hgperf/repos
21 # run suite on given revision
22 $ asv --config contrib/asv.conf.json run REV
23 # run suite on new changesets found in stable and default branch
24 $ asv --config contrib/asv.conf.json run NEW
25 # display a comparative result table of benchmark results between two given
26 # revisions
27 $ asv --config contrib/asv.conf.json compare REV1 REV2
28 # compute regression detection and generate ASV static website
29 $ asv --config contrib/asv.conf.json publish
30 # serve the static website
31 $ asv --config contrib/asv.conf.json preview
32 '''
33
34 from __future__ import absolute_import
35
36 import functools
37 import os
38 import re
39
40 from mercurial import (
41 extensions,
42 hg,
43 ui as uimod,
44 util,
45 )
46
47 basedir = os.path.abspath(os.path.join(os.path.dirname(__file__),
48 os.path.pardir, os.path.pardir))
49 reposdir = os.environ['REPOS_DIR']
50 reposnames = [name for name in os.listdir(reposdir)
51 if os.path.isdir(os.path.join(reposdir, name, ".hg"))]
52 if not reposnames:
53 raise ValueError("No repositories found in $REPO_DIR")
54 outputre = re.compile((r'! wall (\d+.\d+) comb \d+.\d+ user \d+.\d+ sys '
55 r'\d+.\d+ \(best of \d+\)'))
56
57 def runperfcommand(reponame, command, *args, **kwargs):
58 os.environ["HGRCPATH"] = os.environ.get("ASVHGRCPATH", "")
59 # for "historical portability"
60 # ui.load() has been available since d83ca85
61 if util.safehasattr(uimod.ui, "load"):
62 ui = uimod.ui.load()
63 else:
64 ui = uimod.ui()
65 repo = hg.repository(ui, os.path.join(reposdir, reponame))
66 perfext = extensions.load(ui, 'perfext',
67 os.path.join(basedir, 'contrib', 'perf.py'))
68 cmd = getattr(perfext, command)
69 ui.pushbuffer()
70 cmd(ui, repo, *args, **kwargs)
71 output = ui.popbuffer()
72 match = outputre.search(output)
73 if not match:
74 raise ValueError("Invalid output {0}".format(output))
75 return float(match.group(1))
76
77 def perfbench(repos=reposnames, name=None, params=None):
78 """decorator to declare ASV benchmark based on contrib/perf.py extension
79
80 An ASV benchmark is a python function with the given attributes:
81
82 __name__: should start with track_, time_ or mem_ to be collected by ASV
83 params and param_name: parameter matrix to display multiple graphs on the
84 same page.
85 pretty_name: If defined it's displayed in web-ui instead of __name__
86 (useful for revsets)
87 the module name is prepended to the benchmark name and displayed as
88 "category" in webui.
89
90 Benchmarks are automatically parameterized with repositories found in the
91 REPOS_DIR environment variable.
92
93 `params` is the param matrix in the form of a list of tuple
94 (param_name, [value0, value1])
95
96 For example [(x, [a, b]), (y, [c, d])] declare benchmarks for
97 (a, c), (a, d), (b, c) and (b, d).
98 """
99 params = list(params or [])
100 params.insert(0, ("repo", repos))
101
102 def decorator(func):
103 @functools.wraps(func)
104 def wrapped(repo, *args):
105 def perf(command, *a, **kw):
106 return runperfcommand(repo, command, *a, **kw)
107 return func(perf, *args)
108
109 wrapped.params = [p[1] for p in params]
110 wrapped.param_names = [p[0] for p in params]
111 wrapped.pretty_name = name
112 return wrapped
113 return decorator
@@ -0,0 +1,26 b''
1 # perf.py - asv benchmarks using contrib/perf.py extension
2 #
3 # Copyright 2016 Logilab SA <contact@logilab.fr>
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
7
8 from __future__ import absolute_import
9
10 from . import perfbench
11
12 @perfbench()
13 def track_tags(perf):
14 return perf("perftags")
15
16 @perfbench()
17 def track_status(perf):
18 return perf("perfstatus", unknown=False)
19
20 @perfbench(params=[('rev', ['1000', '10000', 'tip'])])
21 def track_manifest(perf, rev):
22 return perf("perfmanifest", rev)
23
24 @perfbench()
25 def track_heads(perf):
26 return perf("perfheads")
@@ -0,0 +1,53 b''
1 # revset.py - asv revset benchmarks
2 #
3 # Copyright 2016 Logilab SA <contact@logilab.fr>
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
7
8 '''ASV revset benchmarks generated from contrib/base-revsets.txt
9
10 Each revset benchmark is parameterized with variants (first, last, sort, ...)
11 '''
12
13 from __future__ import absolute_import
14
15 import os
16 import string
17 import sys
18
19 from . import basedir, perfbench
20
21 def createrevsetbenchmark(baseset, variants=None):
22 if variants is None:
23 # Default variants
24 variants = ["plain", "first", "last", "sort", "sort+first",
25 "sort+last"]
26 fname = "track_" + "_".join("".join([
27 c if c in string.digits + string.letters else " "
28 for c in baseset
29 ]).split())
30
31 def wrap(fname, baseset):
32 @perfbench(name=baseset, params=[("variant", variants)])
33 def f(perf, variant):
34 revset = baseset
35 if variant != "plain":
36 for var in variant.split("+"):
37 revset = "%s(%s)" % (var, revset)
38 return perf("perfrevset", revset)
39 f.__name__ = fname
40 return f
41 return wrap(fname, baseset)
42
43 def initializerevsetbenchmarks():
44 mod = sys.modules[__name__]
45 with open(os.path.join(basedir, 'contrib', 'base-revsets.txt'),
46 'rb') as fh:
47 for line in fh:
48 baseset = line.strip()
49 if baseset and not baseset.startswith('#'):
50 func = createrevsetbenchmark(baseset)
51 setattr(mod, func.__name__, func)
52
53 initializerevsetbenchmarks()
@@ -0,0 +1,225 b''
1 #!/usr/bin/env python3
2 #
3 # byteify-strings.py - transform string literals to be Python 3 safe
4 #
5 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
6 #
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
9
10 from __future__ import absolute_import
11
12 import argparse
13 import contextlib
14 import errno
15 import os
16 import sys
17 import tempfile
18 import token
19 import tokenize
20
21 def adjusttokenpos(t, ofs):
22 """Adjust start/end column of the given token"""
23 return t._replace(start=(t.start[0], t.start[1] + ofs),
24 end=(t.end[0], t.end[1] + ofs))
25
26 def replacetokens(tokens, opts):
27 """Transform a stream of tokens from raw to Python 3.
28
29 Returns a generator of possibly rewritten tokens.
30
31 The input token list may be mutated as part of processing. However,
32 its changes do not necessarily match the output token stream.
33 """
34 sysstrtokens = set()
35
36 # The following utility functions access the tokens list and i index of
37 # the for i, t enumerate(tokens) loop below
38 def _isop(j, *o):
39 """Assert that tokens[j] is an OP with one of the given values"""
40 try:
41 return tokens[j].type == token.OP and tokens[j].string in o
42 except IndexError:
43 return False
44
45 def _findargnofcall(n):
46 """Find arg n of a call expression (start at 0)
47
48 Returns index of the first token of that argument, or None if
49 there is not that many arguments.
50
51 Assumes that token[i + 1] is '('.
52
53 """
54 nested = 0
55 for j in range(i + 2, len(tokens)):
56 if _isop(j, ')', ']', '}'):
57 # end of call, tuple, subscription or dict / set
58 nested -= 1
59 if nested < 0:
60 return None
61 elif n == 0:
62 # this is the starting position of arg
63 return j
64 elif _isop(j, '(', '[', '{'):
65 nested += 1
66 elif _isop(j, ',') and nested == 0:
67 n -= 1
68
69 return None
70
71 def _ensuresysstr(j):
72 """Make sure the token at j is a system string
73
74 Remember the given token so the string transformer won't add
75 the byte prefix.
76
77 Ignores tokens that are not strings. Assumes bounds checking has
78 already been done.
79
80 """
81 st = tokens[j]
82 if st.type == token.STRING and st.string.startswith(("'", '"')):
83 sysstrtokens.add(st)
84
85 coldelta = 0 # column increment for new opening parens
86 coloffset = -1 # column offset for the current line (-1: TBD)
87 parens = [(0, 0, 0)] # stack of (line, end-column, column-offset)
88 for i, t in enumerate(tokens):
89 # Compute the column offset for the current line, such that
90 # the current line will be aligned to the last opening paren
91 # as before.
92 if coloffset < 0:
93 if t.start[1] == parens[-1][1]:
94 coloffset = parens[-1][2]
95 elif t.start[1] + 1 == parens[-1][1]:
96 # fix misaligned indent of s/util.Abort/error.Abort/
97 coloffset = parens[-1][2] + (parens[-1][1] - t.start[1])
98 else:
99 coloffset = 0
100
101 # Reset per-line attributes at EOL.
102 if t.type in (token.NEWLINE, tokenize.NL):
103 yield adjusttokenpos(t, coloffset)
104 coldelta = 0
105 coloffset = -1
106 continue
107
108 # Remember the last paren position.
109 if _isop(i, '(', '[', '{'):
110 parens.append(t.end + (coloffset + coldelta,))
111 elif _isop(i, ')', ']', '}'):
112 parens.pop()
113
114 # Convert most string literals to byte literals. String literals
115 # in Python 2 are bytes. String literals in Python 3 are unicode.
116 # Most strings in Mercurial are bytes and unicode strings are rare.
117 # Rather than rewrite all string literals to use ``b''`` to indicate
118 # byte strings, we apply this token transformer to insert the ``b``
119 # prefix nearly everywhere.
120 if t.type == token.STRING and t not in sysstrtokens:
121 s = t.string
122
123 # Preserve docstrings as string literals. This is inconsistent
124 # with regular unprefixed strings. However, the
125 # "from __future__" parsing (which allows a module docstring to
126 # exist before it) doesn't properly handle the docstring if it
127 # is b''' prefixed, leading to a SyntaxError. We leave all
128 # docstrings as unprefixed to avoid this. This means Mercurial
129 # components touching docstrings need to handle unicode,
130 # unfortunately.
131 if s[0:3] in ("'''", '"""'):
132 yield adjusttokenpos(t, coloffset)
133 continue
134
135 # If the first character isn't a quote, it is likely a string
136 # prefixing character (such as 'b', 'u', or 'r'. Ignore.
137 if s[0] not in ("'", '"'):
138 yield adjusttokenpos(t, coloffset)
139 continue
140
141 # String literal. Prefix to make a b'' string.
142 yield adjusttokenpos(t._replace(string='b%s' % t.string),
143 coloffset)
144 coldelta += 1
145 continue
146
147 # This looks like a function call.
148 if t.type == token.NAME and _isop(i + 1, '('):
149 fn = t.string
150
151 # *attr() builtins don't accept byte strings to 2nd argument.
152 if (fn in ('getattr', 'setattr', 'hasattr', 'safehasattr') and
153 not _isop(i - 1, '.')):
154 arg1idx = _findargnofcall(1)
155 if arg1idx is not None:
156 _ensuresysstr(arg1idx)
157
158 # .encode() and .decode() on str/bytes/unicode don't accept
159 # byte strings on Python 3.
160 elif fn in ('encode', 'decode') and _isop(i - 1, '.'):
161 for argn in range(2):
162 argidx = _findargnofcall(argn)
163 if argidx is not None:
164 _ensuresysstr(argidx)
165
166 # It changes iteritems/values to items/values as they are not
167 # present in Python 3 world.
168 elif opts['dictiter'] and fn in ('iteritems', 'itervalues'):
169 yield adjusttokenpos(t._replace(string=fn[4:]), coloffset)
170 continue
171
172 # Emit unmodified token.
173 yield adjusttokenpos(t, coloffset)
174
175 def process(fin, fout, opts):
176 tokens = tokenize.tokenize(fin.readline)
177 tokens = replacetokens(list(tokens), opts)
178 fout.write(tokenize.untokenize(tokens))
179
180 def tryunlink(fname):
181 try:
182 os.unlink(fname)
183 except OSError as err:
184 if err.errno != errno.ENOENT:
185 raise
186
187 @contextlib.contextmanager
188 def editinplace(fname):
189 n = os.path.basename(fname)
190 d = os.path.dirname(fname)
191 fp = tempfile.NamedTemporaryFile(prefix='.%s-' % n, suffix='~', dir=d,
192 delete=False)
193 try:
194 yield fp
195 fp.close()
196 if os.name == 'nt':
197 tryunlink(fname)
198 os.rename(fp.name, fname)
199 finally:
200 fp.close()
201 tryunlink(fp.name)
202
203 def main():
204 ap = argparse.ArgumentParser()
205 ap.add_argument('-i', '--inplace', action='store_true', default=False,
206 help='edit files in place')
207 ap.add_argument('--dictiter', action='store_true', default=False,
208 help='rewrite iteritems() and itervalues()'),
209 ap.add_argument('files', metavar='FILE', nargs='+', help='source file')
210 args = ap.parse_args()
211 opts = {
212 'dictiter': args.dictiter,
213 }
214 for fname in args.files:
215 if args.inplace:
216 with editinplace(fname) as fout:
217 with open(fname, 'rb') as fin:
218 process(fin, fout, opts)
219 else:
220 with open(fname, 'rb') as fin:
221 fout = sys.stdout.buffer
222 process(fin, fout, opts)
223
224 if __name__ == '__main__':
225 main()
@@ -0,0 +1,38 b''
1 from __future__ import absolute_import
2 import __builtin__
3 import os
4 from mercurial import (
5 util,
6 )
7
8 def lowerwrap(scope, funcname):
9 f = getattr(scope, funcname)
10 def wrap(fname, *args, **kwargs):
11 d, base = os.path.split(fname)
12 try:
13 files = os.listdir(d or '.')
14 except OSError:
15 files = []
16 if base in files:
17 return f(fname, *args, **kwargs)
18 for fn in files:
19 if fn.lower() == base.lower():
20 return f(os.path.join(d, fn), *args, **kwargs)
21 return f(fname, *args, **kwargs)
22 scope.__dict__[funcname] = wrap
23
24 def normcase(path):
25 return path.lower()
26
27 os.path.normcase = normcase
28
29 for f in 'file open'.split():
30 lowerwrap(__builtin__, f)
31
32 for f in "chmod chown open lstat stat remove unlink".split():
33 lowerwrap(os, f)
34
35 for f in "exists lexists".split():
36 lowerwrap(os.path, f)
37
38 lowerwrap(util, 'posixfile')
This diff has been collapsed as it changes many lines, (743 lines changed) Show them Hide them
@@ -0,0 +1,743 b''
1 #!/usr/bin/env python
2 #
3 # check-code - a style and portability checker for Mercurial
4 #
5 # Copyright 2010 Matt Mackall <mpm@selenic.com>
6 #
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
9
10 """style and portability checker for Mercurial
11
12 when a rule triggers wrong, do one of the following (prefer one from top):
13 * do the work-around the rule suggests
14 * doublecheck that it is a false match
15 * improve the rule pattern
16 * add an ignore pattern to the rule (3rd arg) which matches your good line
17 (you can append a short comment and match this, like: #re-raises)
18 * change the pattern to a warning and list the exception in test-check-code-hg
19 * ONLY use no--check-code for skipping entire files from external sources
20 """
21
22 from __future__ import absolute_import, print_function
23 import glob
24 import keyword
25 import optparse
26 import os
27 import re
28 import sys
29 if sys.version_info[0] < 3:
30 opentext = open
31 else:
32 def opentext(f):
33 return open(f, encoding='ascii')
34 try:
35 xrange
36 except NameError:
37 xrange = range
38 try:
39 import re2
40 except ImportError:
41 re2 = None
42
43 def compilere(pat, multiline=False):
44 if multiline:
45 pat = '(?m)' + pat
46 if re2:
47 try:
48 return re2.compile(pat)
49 except re2.error:
50 pass
51 return re.compile(pat)
52
53 # check "rules depending on implementation of repquote()" in each
54 # patterns (especially pypats), before changing around repquote()
55 _repquotefixedmap = {' ': ' ', '\n': '\n', '.': 'p', ':': 'q',
56 '%': '%', '\\': 'b', '*': 'A', '+': 'P', '-': 'M'}
57 def _repquoteencodechr(i):
58 if i > 255:
59 return 'u'
60 c = chr(i)
61 if c in _repquotefixedmap:
62 return _repquotefixedmap[c]
63 if c.isalpha():
64 return 'x'
65 if c.isdigit():
66 return 'n'
67 return 'o'
68 _repquotett = ''.join(_repquoteencodechr(i) for i in xrange(256))
69
70 def repquote(m):
71 t = m.group('text')
72 t = t.translate(_repquotett)
73 return m.group('quote') + t + m.group('quote')
74
75 def reppython(m):
76 comment = m.group('comment')
77 if comment:
78 l = len(comment.rstrip())
79 return "#" * l + comment[l:]
80 return repquote(m)
81
82 def repcomment(m):
83 return m.group(1) + "#" * len(m.group(2))
84
85 def repccomment(m):
86 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
87 return m.group(1) + t + "*/"
88
89 def repcallspaces(m):
90 t = re.sub(r"\n\s+", "\n", m.group(2))
91 return m.group(1) + t
92
93 def repinclude(m):
94 return m.group(1) + "<foo>"
95
96 def rephere(m):
97 t = re.sub(r"\S", "x", m.group(2))
98 return m.group(1) + t
99
100
101 testpats = [
102 [
103 (r'\b(push|pop)d\b', "don't use 'pushd' or 'popd', use 'cd'"),
104 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
105 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
106 (r'(?<!hg )grep.* -a', "don't use 'grep -a', use in-line python"),
107 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
108 (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"),
109 (r'echo -n', "don't use 'echo -n', use printf"),
110 (r'(^|\|\s*)\bwc\b[^|]*$\n(?!.*\(re\))', "filter wc output"),
111 (r'head -c', "don't use 'head -c', use 'dd'"),
112 (r'tail -n', "don't use the '-n' option to tail, just use '-<num>'"),
113 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
114 (r'\bls\b.*-\w*R', "don't use 'ls -R', use 'find'"),
115 (r'printf.*[^\\]\\([1-9]|0\d)', r"don't use 'printf \NNN', use Python"),
116 (r'printf.*[^\\]\\x', "don't use printf \\x, use Python"),
117 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
118 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
119 (r'\[[^\]]+==', '[ foo == bar ] is a bashism, use [ foo = bar ] instead'),
120 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
121 "use egrep for extended grep syntax"),
122 (r'(^|\|\s*)e?grep .*\\S', "don't use \\S in regular expression"),
123 (r'(?<!!)/bin/', "don't use explicit paths for tools"),
124 (r'#!.*/bash', "don't use bash in shebang, use sh"),
125 (r'[^\n]\Z', "no trailing newline"),
126 (r'export .*=', "don't export and assign at once"),
127 (r'^source\b', "don't use 'source', use '.'"),
128 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
129 (r'\bls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
130 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
131 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
132 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
133 (r'\[\[\s+[^\]]*\]\]', "don't use '[[ ]]', use '[ ]'"),
134 (r'^alias\b.*=', "don't use alias, use a function"),
135 (r'if\s*!', "don't use '!' to negate exit status"),
136 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
137 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
138 (r'sed (-e )?\'(\d+|/[^/]*/)i(?!\\\n)',
139 "put a backslash-escaped newline after sed 'i' command"),
140 (r'^diff *-\w*[uU].*$\n(^ \$ |^$)', "prefix diff -u/-U with cmp"),
141 (r'^\s+(if)? diff *-\w*[uU]', "prefix diff -u/-U with cmp"),
142 (r'[\s="`\']python\s(?!bindings)', "don't use 'python', use '$PYTHON'"),
143 (r'seq ', "don't use 'seq', use $TESTDIR/seq.py"),
144 (r'\butil\.Abort\b', "directly use error.Abort"),
145 (r'\|&', "don't use |&, use 2>&1"),
146 (r'\w = +\w', "only one space after = allowed"),
147 (r'\bsed\b.*[^\\]\\n', "don't use 'sed ... \\n', use a \\ and a newline"),
148 (r'env.*-u', "don't use 'env -u VAR', use 'unset VAR'"),
149 (r'cp.* -r ', "don't use 'cp -r', use 'cp -R'"),
150 (r'grep.* -[ABC]', "don't use grep's context flags"),
151 (r'find.*-printf',
152 "don't use 'find -printf', it doesn't exist on BSD find(1)"),
153 (r'\$RANDOM ', "don't use bash-only $RANDOM to generate random values"),
154 ],
155 # warnings
156 [
157 (r'^function', "don't use 'function', use old style"),
158 (r'^diff.*-\w*N', "don't use 'diff -N'"),
159 (r'\$PWD|\${PWD}', "don't use $PWD, use `pwd`"),
160 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
161 (r'kill (`|\$\()', "don't use kill, use killdaemons.py")
162 ]
163 ]
164
165 testfilters = [
166 (r"( *)(#([^!][^\n]*\S)?)", repcomment),
167 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
168 ]
169
170 uprefix = r"^ \$ "
171 utestpats = [
172 [
173 (r'^(\S.*|| [$>] \S.*)[ \t]\n', "trailing whitespace on non-output"),
174 (uprefix + r'.*\|\s*sed[^|>\n]*\n',
175 "use regex test output patterns instead of sed"),
176 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
177 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
178 (uprefix + r'.*\|\| echo.*(fail|error)',
179 "explicit exit code checks unnecessary"),
180 (uprefix + r'set -e', "don't use set -e"),
181 (uprefix + r'(\s|fi\b|done\b)', "use > for continued lines"),
182 (uprefix + r'.*:\.\S*/', "x:.y in a path does not work on msys, rewrite "
183 "as x://.y, or see `hg log -k msys` for alternatives", r'-\S+:\.|' #-Rxxx
184 '# no-msys'), # in test-pull.t which is skipped on windows
185 (r'^ [^$>].*27\.0\.0\.1',
186 'use $LOCALIP not an explicit loopback address'),
187 (r'^ (?![>$] ).*\$LOCALIP.*[^)]$',
188 'mark $LOCALIP output lines with (glob) to help tests in BSD jails'),
189 (r'^ (cat|find): .*: \$ENOENT\$',
190 'use test -f to test for file existence'),
191 (r'^ diff -[^ -]*p',
192 "don't use (external) diff with -p for portability"),
193 (r' readlink ', 'use readlink.py instead of readlink'),
194 (r'^ [-+][-+][-+] .* [-+]0000 \(glob\)',
195 "glob timezone field in diff output for portability"),
196 (r'^ @@ -[0-9]+ [+][0-9]+,[0-9]+ @@',
197 "use '@@ -N* +N,n @@ (glob)' style chunk header for portability"),
198 (r'^ @@ -[0-9]+,[0-9]+ [+][0-9]+ @@',
199 "use '@@ -N,n +N* @@ (glob)' style chunk header for portability"),
200 (r'^ @@ -[0-9]+ [+][0-9]+ @@',
201 "use '@@ -N* +N* @@ (glob)' style chunk header for portability"),
202 (uprefix + r'hg( +-[^ ]+( +[^ ]+)?)* +extdiff'
203 r'( +(-[^ po-]+|--(?!program|option)[^ ]+|[^-][^ ]*))*$',
204 "use $RUNTESTDIR/pdiff via extdiff (or -o/-p for false-positives)"),
205 ],
206 # warnings
207 [
208 (r'^ (?!.*\$LOCALIP)[^*?/\n]* \(glob\)$',
209 "glob match with no glob string (?, *, /, and $LOCALIP)"),
210 ]
211 ]
212
213 # transform plain test rules to unified test's
214 for i in [0, 1]:
215 for tp in testpats[i]:
216 p = tp[0]
217 m = tp[1]
218 if p.startswith(r'^'):
219 p = r"^ [$>] (%s)" % p[1:]
220 else:
221 p = r"^ [$>] .*(%s)" % p
222 utestpats[i].append((p, m) + tp[2:])
223
224 # don't transform the following rules:
225 # " > \t" and " \t" should be allowed in unified tests
226 testpats[0].append((r'^( *)\t', "don't use tabs to indent"))
227 utestpats[0].append((r'^( ?)\t', "don't use tabs to indent"))
228
229 utestfilters = [
230 (r"<<(\S+)((.|\n)*?\n > \1)", rephere),
231 (r"( +)(#([^!][^\n]*\S)?)", repcomment),
232 ]
233
234 pypats = [
235 [
236 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
237 "tuple parameter unpacking not available in Python 3+"),
238 (r'lambda\s*\(.*,.*\)',
239 "tuple parameter unpacking not available in Python 3+"),
240 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
241 (r'(?<!\.)\breduce\s*\(.*', "reduce is not available in Python 3+"),
242 (r'\bdict\(.*=', 'dict() is different in Py2 and 3 and is slower than {}',
243 'dict-from-generator'),
244 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
245 (r'\s<>\s', '<> operator is not available in Python 3+, use !='),
246 (r'^\s*\t', "don't use tabs"),
247 (r'\S;\s*\n', "semicolon"),
248 (r'[^_]_\([ \t\n]*(?:"[^"]+"[ \t\n+]*)+%', "don't use % inside _()"),
249 (r"[^_]_\([ \t\n]*(?:'[^']+'[ \t\n+]*)+%", "don't use % inside _()"),
250 (r'(\w|\)),\w', "missing whitespace after ,"),
251 (r'(\w|\))[+/*\-<>]\w', "missing whitespace in expression"),
252 (r'^\s+(\w|\.)+=\w[^,()\n]*$', "missing whitespace in assignment"),
253 (r'\w\s=\s\s+\w', "gratuitous whitespace after ="),
254 ((
255 # a line ending with a colon, potentially with trailing comments
256 r':([ \t]*#[^\n]*)?\n'
257 # one that is not a pass and not only a comment
258 r'(?P<indent>[ \t]+)[^#][^\n]+\n'
259 # more lines at the same indent level
260 r'((?P=indent)[^\n]+\n)*'
261 # a pass at the same indent level, which is bogus
262 r'(?P=indent)pass[ \t\n#]'
263 ), 'omit superfluous pass'),
264 (r'.{81}', "line too long"),
265 (r'[^\n]\Z', "no trailing newline"),
266 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
267 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
268 # "don't use underbars in identifiers"),
269 (r'^\s+(self\.)?[A-Za-z][a-z0-9]+[A-Z]\w* = ',
270 "don't use camelcase in identifiers", r'#.*camelcase-required'),
271 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
272 "linebreak after :"),
273 (r'class\s[^( \n]+:', "old-style class, use class foo(object)",
274 r'#.*old-style'),
275 (r'class\s[^( \n]+\(\):',
276 "class foo() creates old style object, use class foo(object)",
277 r'#.*old-style'),
278 (r'\b(%s)\(' % '|'.join(k for k in keyword.kwlist
279 if k not in ('print', 'exec')),
280 "Python keyword is not a function"),
281 (r',]', "unneeded trailing ',' in list"),
282 # (r'class\s[A-Z][^\(]*\((?!Exception)',
283 # "don't capitalize non-exception classes"),
284 # (r'in range\(', "use xrange"),
285 # (r'^\s*print\s+', "avoid using print in core and extensions"),
286 (r'[\x80-\xff]', "non-ASCII character literal"),
287 (r'("\')\.format\(', "str.format() has no bytes counterpart, use %"),
288 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
289 "gratuitous whitespace after Python keyword"),
290 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
291 # (r'\s\s=', "gratuitous whitespace before ="),
292 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
293 "missing whitespace around operator"),
294 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\s',
295 "missing whitespace around operator"),
296 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
297 "missing whitespace around operator"),
298 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]',
299 "wrong whitespace around ="),
300 (r'\([^()]*( =[^=]|[^<>!=]= )',
301 "no whitespace around = for named parameters"),
302 (r'raise Exception', "don't raise generic exceptions"),
303 (r'raise [^,(]+, (\([^\)]+\)|[^,\(\)]+)$',
304 "don't use old-style two-argument raise, use Exception(message)"),
305 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
306 (r' [=!]=\s+(True|False|None)',
307 "comparison with singleton, use 'is' or 'is not' instead"),
308 (r'^\s*(while|if) [01]:',
309 "use True/False for constant Boolean expression"),
310 (r'^\s*if False(:| +and)', 'Remove code instead of using `if False`'),
311 (r'(?:(?<!def)\s+|\()hasattr\(',
312 'hasattr(foo, bar) is broken on py2, use util.safehasattr(foo, bar) '
313 'instead', r'#.*hasattr-py3-only'),
314 (r'opener\([^)]*\).read\(',
315 "use opener.read() instead"),
316 (r'opener\([^)]*\).write\(',
317 "use opener.write() instead"),
318 (r'[\s\(](open|file)\([^)]*\)\.read\(',
319 "use util.readfile() instead"),
320 (r'[\s\(](open|file)\([^)]*\)\.write\(',
321 "use util.writefile() instead"),
322 (r'^[\s\(]*(open(er)?|file)\([^)]*\)(?!\.close\(\))',
323 "always assign an opened file to a variable, and close it afterwards"),
324 (r'[\s\(](open|file)\([^)]*\)\.(?!close\(\))',
325 "always assign an opened file to a variable, and close it afterwards"),
326 (r'(?i)descend[e]nt', "the proper spelling is descendAnt"),
327 (r'\.debug\(\_', "don't mark debug messages for translation"),
328 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"),
329 (r'^\s*except\s*:', "naked except clause", r'#.*re-raises'),
330 (r'^\s*except\s([^\(,]+|\([^\)]+\))\s*,',
331 'legacy exception syntax; use "as" instead of ","'),
332 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"),
333 (r'release\(.*wlock, .*lock\)', "wrong lock release order"),
334 (r'\bdef\s+__bool__\b', "__bool__ should be __nonzero__ in Python 2"),
335 (r'os\.path\.join\(.*, *(""|\'\')\)',
336 "use pathutil.normasprefix(path) instead of os.path.join(path, '')"),
337 (r'\s0[0-7]+\b', 'legacy octal syntax; use "0o" prefix instead of "0"'),
338 # XXX only catch mutable arguments on the first line of the definition
339 (r'def.*[( ]\w+=\{\}', "don't use mutable default arguments"),
340 (r'\butil\.Abort\b', "directly use error.Abort"),
341 (r'^@(\w*\.)?cachefunc', "module-level @cachefunc is risky, please avoid"),
342 (r'^import atexit', "don't use atexit, use ui.atexit"),
343 (r'^import Queue', "don't use Queue, use pycompat.queue.Queue + "
344 "pycompat.queue.Empty"),
345 (r'^import cStringIO', "don't use cStringIO.StringIO, use util.stringio"),
346 (r'^import urllib', "don't use urllib, use util.urlreq/util.urlerr"),
347 (r'^import SocketServer', "don't use SockerServer, use util.socketserver"),
348 (r'^import urlparse', "don't use urlparse, use util.urlreq"),
349 (r'^import xmlrpclib', "don't use xmlrpclib, use util.xmlrpclib"),
350 (r'^import cPickle', "don't use cPickle, use util.pickle"),
351 (r'^import pickle', "don't use pickle, use util.pickle"),
352 (r'^import httplib', "don't use httplib, use util.httplib"),
353 (r'^import BaseHTTPServer', "use util.httpserver instead"),
354 (r'^(from|import) mercurial\.(cext|pure|cffi)',
355 "use mercurial.policy.importmod instead"),
356 (r'\.next\(\)', "don't use .next(), use next(...)"),
357 (r'([a-z]*).revision\(\1\.node\(',
358 "don't convert rev to node before passing to revision(nodeorrev)"),
359 (r'platform\.system\(\)', "don't use platform.system(), use pycompat"),
360
361 # rules depending on implementation of repquote()
362 (r' x+[xpqo%APM][\'"]\n\s+[\'"]x',
363 'string join across lines with no space'),
364 (r'''(?x)ui\.(status|progress|write|note|warn)\(
365 [ \t\n#]*
366 (?# any strings/comments might precede a string, which
367 # contains translatable message)
368 ((['"]|\'\'\'|""")[ \npq%bAPMxno]*(['"]|\'\'\'|""")[ \t\n#]+)*
369 (?# sequence consisting of below might precede translatable message
370 # - formatting string: "% 10s", "%05d", "% -3.2f", "%*s", "%%" ...
371 # - escaped character: "\\", "\n", "\0" ...
372 # - character other than '%', 'b' as '\', and 'x' as alphabet)
373 (['"]|\'\'\'|""")
374 ((%([ n]?[PM]?([np]+|A))?x)|%%|b[bnx]|[ \nnpqAPMo])*x
375 (?# this regexp can't use [^...] style,
376 # because _preparepats forcibly adds "\n" into [^...],
377 # even though this regexp wants match it against "\n")''',
378 "missing _() in ui message (use () to hide false-positives)"),
379 ],
380 # warnings
381 [
382 # rules depending on implementation of repquote()
383 (r'(^| )pp +xxxxqq[ \n][^\n]', "add two newlines after '.. note::'"),
384 ]
385 ]
386
387 pyfilters = [
388 (r"""(?msx)(?P<comment>\#.*?$)|
389 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
390 (?P<text>(([^\\]|\\.)*?))
391 (?P=quote))""", reppython),
392 ]
393
394 # non-filter patterns
395 pynfpats = [
396 [
397 (r'pycompat\.osname\s*[=!]=\s*[\'"]nt[\'"]', "use pycompat.iswindows"),
398 (r'pycompat\.osname\s*[=!]=\s*[\'"]posix[\'"]', "use pycompat.isposix"),
399 (r'pycompat\.sysplatform\s*[!=]=\s*[\'"]darwin[\'"]',
400 "use pycompat.isdarwin"),
401 ],
402 # warnings
403 [],
404 ]
405
406 # extension non-filter patterns
407 pyextnfpats = [
408 [(r'^"""\n?[A-Z]', "don't capitalize docstring title")],
409 # warnings
410 [],
411 ]
412
413 txtfilters = []
414
415 txtpats = [
416 [
417 ('\s$', 'trailing whitespace'),
418 ('.. note::[ \n][^\n]', 'add two newlines after note::')
419 ],
420 []
421 ]
422
423 cpats = [
424 [
425 (r'//', "don't use //-style comments"),
426 (r'\S\t', "don't use tabs except for indent"),
427 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
428 (r'.{81}', "line too long"),
429 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
430 (r'return\(', "return is not a function"),
431 (r' ;', "no space before ;"),
432 (r'[^;] \)', "no space before )"),
433 (r'[)][{]', "space between ) and {"),
434 (r'\w+\* \w+', "use int *foo, not int* foo"),
435 (r'\W\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
436 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
437 (r'\w,\w', "missing whitespace after ,"),
438 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
439 (r'\w\s=\s\s+\w', "gratuitous whitespace after ="),
440 (r'^#\s+\w', "use #foo, not # foo"),
441 (r'[^\n]\Z', "no trailing newline"),
442 (r'^\s*#import\b', "use only #include in standard C code"),
443 (r'strcpy\(', "don't use strcpy, use strlcpy or memcpy"),
444 (r'strcat\(', "don't use strcat"),
445
446 # rules depending on implementation of repquote()
447 ],
448 # warnings
449 [
450 # rules depending on implementation of repquote()
451 ]
452 ]
453
454 cfilters = [
455 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
456 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
457 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
458 (r'(\()([^)]+\))', repcallspaces),
459 ]
460
461 inutilpats = [
462 [
463 (r'\bui\.', "don't use ui in util"),
464 ],
465 # warnings
466 []
467 ]
468
469 inrevlogpats = [
470 [
471 (r'\brepo\.', "don't use repo in revlog"),
472 ],
473 # warnings
474 []
475 ]
476
477 webtemplatefilters = []
478
479 webtemplatepats = [
480 [],
481 [
482 (r'{desc(\|(?!websub|firstline)[^\|]*)+}',
483 'follow desc keyword with either firstline or websub'),
484 ]
485 ]
486
487 allfilesfilters = []
488
489 allfilespats = [
490 [
491 (r'(http|https)://[a-zA-Z0-9./]*selenic.com/',
492 'use mercurial-scm.org domain URL'),
493 (r'mercurial@selenic\.com',
494 'use mercurial-scm.org domain for mercurial ML address'),
495 (r'mercurial-devel@selenic\.com',
496 'use mercurial-scm.org domain for mercurial-devel ML address'),
497 ],
498 # warnings
499 [],
500 ]
501
502 py3pats = [
503 [
504 (r'os\.environ', "use encoding.environ instead (py3)", r'#.*re-exports'),
505 (r'os\.name', "use pycompat.osname instead (py3)"),
506 (r'os\.getcwd', "use pycompat.getcwd instead (py3)"),
507 (r'os\.sep', "use pycompat.ossep instead (py3)"),
508 (r'os\.pathsep', "use pycompat.ospathsep instead (py3)"),
509 (r'os\.altsep', "use pycompat.osaltsep instead (py3)"),
510 (r'sys\.platform', "use pycompat.sysplatform instead (py3)"),
511 (r'getopt\.getopt', "use pycompat.getoptb instead (py3)"),
512 (r'os\.getenv', "use encoding.environ.get instead"),
513 (r'os\.setenv', "modifying the environ dict is not preferred"),
514 (r'(?<!pycompat\.)xrange', "use pycompat.xrange instead (py3)"),
515 ],
516 # warnings
517 [],
518 ]
519
520 checks = [
521 ('python', r'.*\.(py|cgi)$', r'^#!.*python', pyfilters, pypats),
522 ('python', r'.*\.(py|cgi)$', r'^#!.*python', [], pynfpats),
523 ('python', r'.*hgext.*\.py$', '', [], pyextnfpats),
524 ('python 3', r'.*(hgext|mercurial)/(?!demandimport|policy|pycompat).*\.py',
525 '', pyfilters, py3pats),
526 ('test script', r'(.*/)?test-[^.~]*$', '', testfilters, testpats),
527 ('c', r'.*\.[ch]$', '', cfilters, cpats),
528 ('unified test', r'.*\.t$', '', utestfilters, utestpats),
529 ('layering violation repo in revlog', r'mercurial/revlog\.py', '',
530 pyfilters, inrevlogpats),
531 ('layering violation ui in util', r'mercurial/util\.py', '', pyfilters,
532 inutilpats),
533 ('txt', r'.*\.txt$', '', txtfilters, txtpats),
534 ('web template', r'mercurial/templates/.*\.tmpl', '',
535 webtemplatefilters, webtemplatepats),
536 ('all except for .po', r'.*(?<!\.po)$', '',
537 allfilesfilters, allfilespats),
538 ]
539
540 def _preparepats():
541 for c in checks:
542 failandwarn = c[-1]
543 for pats in failandwarn:
544 for i, pseq in enumerate(pats):
545 # fix-up regexes for multi-line searches
546 p = pseq[0]
547 # \s doesn't match \n (done in two steps)
548 # first, we replace \s that appears in a set already
549 p = re.sub(r'\[\\s', r'[ \\t', p)
550 # now we replace other \s instances.
551 p = re.sub(r'(?<!(\\|\[))\\s', r'[ \\t]', p)
552 # [^...] doesn't match newline
553 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
554
555 pats[i] = (re.compile(p, re.MULTILINE),) + pseq[1:]
556 filters = c[3]
557 for i, flt in enumerate(filters):
558 filters[i] = re.compile(flt[0]), flt[1]
559
560 class norepeatlogger(object):
561 def __init__(self):
562 self._lastseen = None
563
564 def log(self, fname, lineno, line, msg, blame):
565 """print error related a to given line of a given file.
566
567 The faulty line will also be printed but only once in the case
568 of multiple errors.
569
570 :fname: filename
571 :lineno: line number
572 :line: actual content of the line
573 :msg: error message
574 """
575 msgid = fname, lineno, line
576 if msgid != self._lastseen:
577 if blame:
578 print("%s:%d (%s):" % (fname, lineno, blame))
579 else:
580 print("%s:%d:" % (fname, lineno))
581 print(" > %s" % line)
582 self._lastseen = msgid
583 print(" " + msg)
584
585 _defaultlogger = norepeatlogger()
586
587 def getblame(f):
588 lines = []
589 for l in os.popen('hg annotate -un %s' % f):
590 start, line = l.split(':', 1)
591 user, rev = start.split()
592 lines.append((line[1:-1], user, rev))
593 return lines
594
595 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
596 blame=False, debug=False, lineno=True):
597 """checks style and portability of a given file
598
599 :f: filepath
600 :logfunc: function used to report error
601 logfunc(filename, linenumber, linecontent, errormessage)
602 :maxerr: number of error to display before aborting.
603 Set to false (default) to report all errors
604
605 return True if no error is found, False otherwise.
606 """
607 blamecache = None
608 result = True
609
610 try:
611 with opentext(f) as fp:
612 try:
613 pre = post = fp.read()
614 except UnicodeDecodeError as e:
615 print("%s while reading %s" % (e, f))
616 return result
617 except IOError as e:
618 print("Skipping %s, %s" % (f, str(e).split(':', 1)[0]))
619 return result
620
621 for name, match, magic, filters, pats in checks:
622 post = pre # discard filtering result of previous check
623 if debug:
624 print(name, f)
625 fc = 0
626 if not (re.match(match, f) or (magic and re.search(magic, pre))):
627 if debug:
628 print("Skipping %s for %s it doesn't match %s" % (
629 name, match, f))
630 continue
631 if "no-" "check-code" in pre:
632 # If you're looking at this line, it's because a file has:
633 # no- check- code
634 # but the reason to output skipping is to make life for
635 # tests easier. So, instead of writing it with a normal
636 # spelling, we write it with the expected spelling from
637 # tests/test-check-code.t
638 print("Skipping %s it has no-che?k-code (glob)" % f)
639 return "Skip" # skip checking this file
640 for p, r in filters:
641 post = re.sub(p, r, post)
642 nerrs = len(pats[0]) # nerr elements are errors
643 if warnings:
644 pats = pats[0] + pats[1]
645 else:
646 pats = pats[0]
647 # print post # uncomment to show filtered version
648
649 if debug:
650 print("Checking %s for %s" % (name, f))
651
652 prelines = None
653 errors = []
654 for i, pat in enumerate(pats):
655 if len(pat) == 3:
656 p, msg, ignore = pat
657 else:
658 p, msg = pat
659 ignore = None
660 if i >= nerrs:
661 msg = "warning: " + msg
662
663 pos = 0
664 n = 0
665 for m in p.finditer(post):
666 if prelines is None:
667 prelines = pre.splitlines()
668 postlines = post.splitlines(True)
669
670 start = m.start()
671 while n < len(postlines):
672 step = len(postlines[n])
673 if pos + step > start:
674 break
675 pos += step
676 n += 1
677 l = prelines[n]
678
679 if ignore and re.search(ignore, l, re.MULTILINE):
680 if debug:
681 print("Skipping %s for %s:%s (ignore pattern)" % (
682 name, f, n))
683 continue
684 bd = ""
685 if blame:
686 bd = 'working directory'
687 if not blamecache:
688 blamecache = getblame(f)
689 if n < len(blamecache):
690 bl, bu, br = blamecache[n]
691 if bl == l:
692 bd = '%s@%s' % (bu, br)
693
694 errors.append((f, lineno and n + 1, l, msg, bd))
695 result = False
696
697 errors.sort()
698 for e in errors:
699 logfunc(*e)
700 fc += 1
701 if maxerr and fc >= maxerr:
702 print(" (too many errors, giving up)")
703 break
704
705 return result
706
707 def main():
708 parser = optparse.OptionParser("%prog [options] [files | -]")
709 parser.add_option("-w", "--warnings", action="store_true",
710 help="include warning-level checks")
711 parser.add_option("-p", "--per-file", type="int",
712 help="max warnings per file")
713 parser.add_option("-b", "--blame", action="store_true",
714 help="use annotate to generate blame info")
715 parser.add_option("", "--debug", action="store_true",
716 help="show debug information")
717 parser.add_option("", "--nolineno", action="store_false",
718 dest='lineno', help="don't show line numbers")
719
720 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
721 lineno=True)
722 (options, args) = parser.parse_args()
723
724 if len(args) == 0:
725 check = glob.glob("*")
726 elif args == ['-']:
727 # read file list from stdin
728 check = sys.stdin.read().splitlines()
729 else:
730 check = args
731
732 _preparepats()
733
734 ret = 0
735 for f in check:
736 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
737 blame=options.blame, debug=options.debug,
738 lineno=options.lineno):
739 ret = 1
740 return ret
741
742 if __name__ == "__main__":
743 sys.exit(main())
@@ -0,0 +1,111 b''
1 #!/usr/bin/env python
2 #
3 # Copyright 2014 Matt Mackall <mpm@selenic.com>
4 #
5 # A tool/hook to run basic sanity checks on commits/patches for
6 # submission to Mercurial. Install by adding the following to your
7 # .hg/hgrc:
8 #
9 # [hooks]
10 # pretxncommit = contrib/check-commit
11 #
12 # The hook can be temporarily bypassed with:
13 #
14 # $ BYPASS= hg commit
15 #
16 # See also: https://mercurial-scm.org/wiki/ContributingChanges
17
18 from __future__ import absolute_import, print_function
19
20 import os
21 import re
22 import sys
23
24 commitheader = r"^(?:# [^\n]*\n)*"
25 afterheader = commitheader + r"(?!#)"
26 beforepatch = afterheader + r"(?!\n(?!@@))"
27
28 errors = [
29 (beforepatch + r".*[(]bc[)]", "(BC) needs to be uppercase"),
30 (beforepatch + r".*[(]issue \d\d\d",
31 "no space allowed between issue and number"),
32 (beforepatch + r".*[(]bug(\d|\s)", "use (issueDDDD) instead of bug"),
33 (commitheader + r"# User [^@\n]+\n", "username is not an email address"),
34 (commitheader + r"(?!merge with )[^#]\S+[^:] ",
35 "summary line doesn't start with 'topic: '"),
36 (afterheader + r"[A-Z][a-z]\S+", "don't capitalize summary lines"),
37 (afterheader + r"[^\n]*: *[A-Z][a-z]\S+", "don't capitalize summary lines"),
38 (afterheader + r"\S*[^A-Za-z0-9-_]\S*: ",
39 "summary keyword should be most user-relevant one-word command or topic"),
40 (afterheader + r".*\.\s*\n", "don't add trailing period on summary line"),
41 (afterheader + r".{79,}", "summary line too long (limit is 78)"),
42 (r"\n\+\n( |\+)\n", "adds double empty line"),
43 (r"\n \n\+\n", "adds double empty line"),
44 # Forbid "_" in function name.
45 #
46 # We skip the check for cffi related functions. They use names mapping the
47 # name of the C function. C function names may contain "_".
48 (r"\n\+[ \t]+def (?!cffi)[a-z]+_[a-z]",
49 "adds a function with foo_bar naming"),
50 ]
51
52 word = re.compile('\S')
53 def nonempty(first, second):
54 if word.search(first):
55 return first
56 return second
57
58 def checkcommit(commit, node=None):
59 exitcode = 0
60 printed = node is None
61 hits = []
62 signtag = (afterheader +
63 r'Added (tag [^ ]+|signature) for changeset [a-f0-9]{12}')
64 if re.search(signtag, commit):
65 return 0
66 for exp, msg in errors:
67 for m in re.finditer(exp, commit):
68 end = m.end()
69 trailing = re.search(r'(\\n)+$', exp)
70 if trailing:
71 end -= len(trailing.group()) / 2
72 hits.append((end, exp, msg))
73 if hits:
74 hits.sort()
75 pos = 0
76 last = ''
77 for n, l in enumerate(commit.splitlines(True)):
78 pos += len(l)
79 while len(hits):
80 end, exp, msg = hits[0]
81 if pos < end:
82 break
83 if not printed:
84 printed = True
85 print("node: %s" % node)
86 print("%d: %s" % (n, msg))
87 print(" %s" % nonempty(l, last)[:-1])
88 if "BYPASS" not in os.environ:
89 exitcode = 1
90 del hits[0]
91 last = nonempty(l, last)
92
93 return exitcode
94
95 def readcommit(node):
96 return os.popen("hg export %s" % node).read()
97
98 if __name__ == "__main__":
99 exitcode = 0
100 node = os.environ.get("HG_NODE")
101
102 if node:
103 commit = readcommit(node)
104 exitcode = checkcommit(commit)
105 elif sys.argv[1:]:
106 for node in sys.argv[1:]:
107 exitcode |= checkcommit(readcommit(node), node)
108 else:
109 commit = sys.stdin.read()
110 exitcode = checkcommit(commit)
111 sys.exit(exitcode)
@@ -0,0 +1,142 b''
1 #!/usr/bin/env python
2 #
3 # check-config - a config flag documentation checker for Mercurial
4 #
5 # Copyright 2015 Matt Mackall <mpm@selenic.com>
6 #
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
9
10 from __future__ import absolute_import, print_function
11 import re
12 import sys
13
14 foundopts = {}
15 documented = {}
16 allowinconsistent = set()
17
18 configre = re.compile(br'''
19 # Function call
20 ui\.config(?P<ctype>|int|bool|list)\(
21 # First argument.
22 ['"](?P<section>\S+)['"],\s*
23 # Second argument
24 ['"](?P<option>\S+)['"](,\s+
25 (?:default=)?(?P<default>\S+?))?
26 \)''', re.VERBOSE | re.MULTILINE)
27
28 configwithre = re.compile(b'''
29 ui\.config(?P<ctype>with)\(
30 # First argument is callback function. This doesn't parse robustly
31 # if it is e.g. a function call.
32 [^,]+,\s*
33 ['"](?P<section>\S+)['"],\s*
34 ['"](?P<option>\S+)['"](,\s+
35 (?:default=)?(?P<default>\S+?))?
36 \)''', re.VERBOSE | re.MULTILINE)
37
38 configpartialre = (br"""ui\.config""")
39
40 ignorere = re.compile(br'''
41 \#\s(?P<reason>internal|experimental|deprecated|developer|inconsistent)\s
42 config:\s(?P<config>\S+\.\S+)$
43 ''', re.VERBOSE | re.MULTILINE)
44
45 def main(args):
46 for f in args:
47 sect = b''
48 prevname = b''
49 confsect = b''
50 carryover = b''
51 linenum = 0
52 for l in open(f, 'rb'):
53 linenum += 1
54
55 # check topic-like bits
56 m = re.match(b'\s*``(\S+)``', l)
57 if m:
58 prevname = m.group(1)
59 if re.match(b'^\s*-+$', l):
60 sect = prevname
61 prevname = b''
62
63 if sect and prevname:
64 name = sect + b'.' + prevname
65 documented[name] = 1
66
67 # check docstring bits
68 m = re.match(br'^\s+\[(\S+)\]', l)
69 if m:
70 confsect = m.group(1)
71 continue
72 m = re.match(br'^\s+(?:#\s*)?(\S+) = ', l)
73 if m:
74 name = confsect + b'.' + m.group(1)
75 documented[name] = 1
76
77 # like the bugzilla extension
78 m = re.match(br'^\s*(\S+\.\S+)$', l)
79 if m:
80 documented[m.group(1)] = 1
81
82 # like convert
83 m = re.match(br'^\s*:(\S+\.\S+):\s+', l)
84 if m:
85 documented[m.group(1)] = 1
86
87 # quoted in help or docstrings
88 m = re.match(br'.*?``(\S+\.\S+)``', l)
89 if m:
90 documented[m.group(1)] = 1
91
92 # look for ignore markers
93 m = ignorere.search(l)
94 if m:
95 if m.group('reason') == 'inconsistent':
96 allowinconsistent.add(m.group('config'))
97 else:
98 documented[m.group('config')] = 1
99
100 # look for code-like bits
101 line = carryover + l
102 m = configre.search(line) or configwithre.search(line)
103 if m:
104 ctype = m.group('ctype')
105 if not ctype:
106 ctype = 'str'
107 name = m.group('section') + "." + m.group('option')
108 default = m.group('default')
109 if default in (None, 'False', 'None', '0', '[]', '""', "''"):
110 default = ''
111 if re.match(b'[a-z.]+$', default):
112 default = '<variable>'
113 if (name in foundopts and (ctype, default) != foundopts[name]
114 and name not in allowinconsistent):
115 print(l.rstrip())
116 print("conflict on %s: %r != %r" % (name, (ctype, default),
117 foundopts[name]))
118 print("at %s:%d:" % (f, linenum))
119 foundopts[name] = (ctype, default)
120 carryover = ''
121 else:
122 m = re.search(configpartialre, line)
123 if m:
124 carryover = line
125 else:
126 carryover = ''
127
128 for name in sorted(foundopts):
129 if name not in documented:
130 if not (name.startswith("devel.") or
131 name.startswith("experimental.") or
132 name.startswith("debug.")):
133 ctype, default = foundopts[name]
134 if default:
135 default = ' [%s]' % default
136 print("undocumented: %s (%s)%s" % (name, ctype, default))
137
138 if __name__ == "__main__":
139 if len(sys.argv) > 1:
140 sys.exit(main(sys.argv[1:]))
141 else:
142 sys.exit(main([l.rstrip() for l in sys.stdin]))
@@ -0,0 +1,96 b''
1 #!/usr/bin/env python
2 #
3 # check-py3-compat - check Python 3 compatibility of Mercurial files
4 #
5 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
6 #
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
9
10 from __future__ import absolute_import, print_function
11
12 import ast
13 import importlib
14 import os
15 import sys
16 import traceback
17
18 def check_compat_py2(f):
19 """Check Python 3 compatibility for a file with Python 2"""
20 with open(f, 'rb') as fh:
21 content = fh.read()
22 root = ast.parse(content)
23
24 # Ignore empty files.
25 if not root.body:
26 return
27
28 futures = set()
29 haveprint = False
30 for node in ast.walk(root):
31 if isinstance(node, ast.ImportFrom):
32 if node.module == '__future__':
33 futures |= set(n.name for n in node.names)
34 elif isinstance(node, ast.Print):
35 haveprint = True
36
37 if 'absolute_import' not in futures:
38 print('%s not using absolute_import' % f)
39 if haveprint and 'print_function' not in futures:
40 print('%s requires print_function' % f)
41
42 def check_compat_py3(f):
43 """Check Python 3 compatibility of a file with Python 3."""
44 with open(f, 'rb') as fh:
45 content = fh.read()
46
47 try:
48 ast.parse(content)
49 except SyntaxError as e:
50 print('%s: invalid syntax: %s' % (f, e))
51 return
52
53 # Try to import the module.
54 # For now we only support modules in packages because figuring out module
55 # paths for things not in a package can be confusing.
56 if (f.startswith(('hgdemandimport/', 'hgext/', 'mercurial/'))
57 and not f.endswith('__init__.py')):
58 assert f.endswith('.py')
59 name = f.replace('/', '.')[:-3]
60 try:
61 importlib.import_module(name)
62 except Exception as e:
63 exc_type, exc_value, tb = sys.exc_info()
64 # We walk the stack and ignore frames from our custom importer,
65 # import mechanisms, and stdlib modules. This kinda/sorta
66 # emulates CPython behavior in import.c while also attempting
67 # to pin blame on a Mercurial file.
68 for frame in reversed(traceback.extract_tb(tb)):
69 if frame.name == '_call_with_frames_removed':
70 continue
71 if 'importlib' in frame.filename:
72 continue
73 if 'mercurial/__init__.py' in frame.filename:
74 continue
75 if frame.filename.startswith(sys.prefix):
76 continue
77 break
78
79 if frame.filename:
80 filename = os.path.basename(frame.filename)
81 print('%s: error importing: <%s> %s (error at %s:%d)' % (
82 f, type(e).__name__, e, filename, frame.lineno))
83 else:
84 print('%s: error importing module: <%s> %s (line %d)' % (
85 f, type(e).__name__, e, frame.lineno))
86
87 if __name__ == '__main__':
88 if sys.version_info[0] == 2:
89 fn = check_compat_py2
90 else:
91 fn = check_compat_py3
92
93 for f in sys.argv[1:]:
94 fn(f)
95
96 sys.exit(0)
@@ -0,0 +1,40 b''
1 TARGET = chg
2 SRCS = chg.c hgclient.c procutil.c util.c
3 OBJS = $(SRCS:.c=.o)
4
5 CFLAGS ?= -O2 -Wall -Wextra -pedantic -g
6 CPPFLAGS ?= -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE
7 override CFLAGS += -std=gnu99
8 ifdef HGPATH
9 override CPPFLAGS += -DHGPATH=\"$(HGPATH)\"
10 endif
11
12 DESTDIR =
13 PREFIX = /usr/local
14 MANDIR = $(PREFIX)/share/man/man1
15
16 .PHONY: all
17 all: $(TARGET)
18
19 $(TARGET): $(OBJS)
20 $(CC) $(LDFLAGS) -o $@ $(OBJS)
21
22 chg.o: hgclient.h procutil.h util.h
23 hgclient.o: hgclient.h procutil.h util.h
24 procutil.o: procutil.h util.h
25 util.o: util.h
26
27 .PHONY: install
28 install: $(TARGET)
29 install -d "$(DESTDIR)$(PREFIX)"/bin
30 install -m 755 "$(TARGET)" "$(DESTDIR)$(PREFIX)"/bin
31 install -d "$(DESTDIR)$(MANDIR)"
32 install -m 644 chg.1 "$(DESTDIR)$(MANDIR)"
33
34 .PHONY: clean
35 clean:
36 $(RM) $(OBJS)
37
38 .PHONY: distclean
39 distclean:
40 $(RM) $(OBJS) $(TARGET)
@@ -0,0 +1,32 b''
1 cHg
2 ===
3
4 A fast client for Mercurial command server running on Unix.
5
6 Install:
7
8 $ make
9 $ make install
10
11 Usage:
12
13 $ chg help # show help of Mercurial
14 $ alias hg=chg # replace hg command
15 $ chg --kill-chg-daemon # terminate background server
16
17 Environment variables:
18
19 Although cHg tries to update environment variables, some of them cannot be
20 changed after spawning the server. The following variables are specially
21 handled:
22
23 * configuration files are reloaded automatically by default.
24 * CHGHG or HG specifies the path to the hg executable spawned as the
25 background command server.
26
27 The following variables are available for testing:
28
29 * CHGDEBUG enables debug messages.
30 * CHGSOCKNAME specifies the socket path of the background cmdserver.
31 * CHGTIMEOUT specifies how many seconds chg will wait before giving up
32 connecting to a cmdserver. If it is 0, chg will wait forever. Default: 60
@@ -0,0 +1,41 b''
1 .\" Hey, EMACS: -*- nroff -*-
2 .\" First parameter, NAME, should be all caps
3 .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
4 .\" other parameters are allowed: see man(7), man(1)
5 .TH CHG 1 "March 3, 2013"
6 .\" Please adjust this date whenever revising the manpage.
7 .\"
8 .\" Some roff macros, for reference:
9 .\" .nh disable hyphenation
10 .\" .hy enable hyphenation
11 .\" .ad l left justify
12 .\" .ad b justify to both left and right margins
13 .\" .nf disable filling
14 .\" .fi enable filling
15 .\" .br insert line break
16 .\" .sp <n> insert n+1 empty lines
17 .\" for manpage-specific macros, see man(7)
18 .SH NAME
19 chg \- a fast client for Mercurial command server
20 .SH SYNOPSIS
21 .B chg
22 .IR command " [" options "] [" arguments "]..."
23 .br
24 .SH DESCRIPTION
25 The
26 .B chg
27 command is the wrapper for
28 .B hg
29 command.
30 It uses the Mercurial command server to reduce start-up overhead.
31 .SH OPTIONS
32 This program accepts the same command line syntax as the
33 .B hg
34 command. Additionally it accepts the following options.
35 .TP
36 .B \-\-kill\-chg\-daemon
37 Terminate the background command servers.
38 .SH SEE ALSO
39 .BR hg (1),
40 .SH AUTHOR
41 Written by Yuya Nishihara <yuya@tcha.org>.
@@ -0,0 +1,456 b''
1 /*
2 * A fast client for Mercurial command server
3 *
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 *
6 * This software may be used and distributed according to the terms of the
7 * GNU General Public License version 2 or any later version.
8 */
9
10 #include <assert.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <signal.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/file.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/un.h>
21 #include <sys/wait.h>
22 #include <time.h>
23 #include <unistd.h>
24
25 #include "hgclient.h"
26 #include "procutil.h"
27 #include "util.h"
28
29 #ifndef PATH_MAX
30 #define PATH_MAX 4096
31 #endif
32
33 struct cmdserveropts {
34 char sockname[PATH_MAX];
35 char initsockname[PATH_MAX];
36 char redirectsockname[PATH_MAX];
37 size_t argsize;
38 const char **args;
39 };
40
41 static void initcmdserveropts(struct cmdserveropts *opts)
42 {
43 memset(opts, 0, sizeof(struct cmdserveropts));
44 }
45
46 static void freecmdserveropts(struct cmdserveropts *opts)
47 {
48 free(opts->args);
49 opts->args = NULL;
50 opts->argsize = 0;
51 }
52
53 /*
54 * Test if an argument is a sensitive flag that should be passed to the server.
55 * Return 0 if not, otherwise the number of arguments starting from the current
56 * one that should be passed to the server.
57 */
58 static size_t testsensitiveflag(const char *arg)
59 {
60 static const struct {
61 const char *name;
62 size_t narg;
63 } flags[] = {
64 {"--config", 1}, {"--cwd", 1}, {"--repo", 1},
65 {"--repository", 1}, {"--traceback", 0}, {"-R", 1},
66 };
67 size_t i;
68 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) {
69 size_t len = strlen(flags[i].name);
70 size_t narg = flags[i].narg;
71 if (memcmp(arg, flags[i].name, len) == 0) {
72 if (arg[len] == '\0') {
73 /* --flag (value) */
74 return narg + 1;
75 } else if (arg[len] == '=' && narg > 0) {
76 /* --flag=value */
77 return 1;
78 } else if (flags[i].name[1] != '-') {
79 /* short flag */
80 return 1;
81 }
82 }
83 }
84 return 0;
85 }
86
87 /*
88 * Parse argv[] and put sensitive flags to opts->args
89 */
90 static void setcmdserverargs(struct cmdserveropts *opts, int argc,
91 const char *argv[])
92 {
93 size_t i, step;
94 opts->argsize = 0;
95 for (i = 0, step = 1; i < (size_t)argc; i += step, step = 1) {
96 if (!argv[i])
97 continue; /* pass clang-analyse */
98 if (strcmp(argv[i], "--") == 0)
99 break;
100 size_t n = testsensitiveflag(argv[i]);
101 if (n == 0 || i + n > (size_t)argc)
102 continue;
103 opts->args =
104 reallocx(opts->args, (n + opts->argsize) * sizeof(char *));
105 memcpy(opts->args + opts->argsize, argv + i,
106 sizeof(char *) * n);
107 opts->argsize += n;
108 step = n;
109 }
110 }
111
112 static void preparesockdir(const char *sockdir)
113 {
114 int r;
115 r = mkdir(sockdir, 0700);
116 if (r < 0 && errno != EEXIST)
117 abortmsgerrno("cannot create sockdir %s", sockdir);
118
119 struct stat st;
120 r = lstat(sockdir, &st);
121 if (r < 0)
122 abortmsgerrno("cannot stat %s", sockdir);
123 if (!S_ISDIR(st.st_mode))
124 abortmsg("cannot create sockdir %s (file exists)", sockdir);
125 if (st.st_uid != geteuid() || st.st_mode & 0077)
126 abortmsg("insecure sockdir %s", sockdir);
127 }
128
129 /*
130 * Check if a socket directory exists and is only owned by the current user.
131 * Return 1 if so, 0 if not. This is used to check if XDG_RUNTIME_DIR can be
132 * used or not. According to the specification [1], XDG_RUNTIME_DIR should be
133 * ignored if the directory is not owned by the user with mode 0700.
134 * [1]: https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
135 */
136 static int checkruntimedir(const char *sockdir)
137 {
138 struct stat st;
139 int r = lstat(sockdir, &st);
140 if (r < 0) /* ex. does not exist */
141 return 0;
142 if (!S_ISDIR(st.st_mode)) /* ex. is a file, not a directory */
143 return 0;
144 return st.st_uid == geteuid() && (st.st_mode & 0777) == 0700;
145 }
146
147 static void getdefaultsockdir(char sockdir[], size_t size)
148 {
149 /* by default, put socket file in secure directory
150 * (${XDG_RUNTIME_DIR}/chg, or /${TMPDIR:-tmp}/chg$UID)
151 * (permission of socket file may be ignored on some Unices) */
152 const char *runtimedir = getenv("XDG_RUNTIME_DIR");
153 int r;
154 if (runtimedir && checkruntimedir(runtimedir)) {
155 r = snprintf(sockdir, size, "%s/chg", runtimedir);
156 } else {
157 const char *tmpdir = getenv("TMPDIR");
158 if (!tmpdir)
159 tmpdir = "/tmp";
160 r = snprintf(sockdir, size, "%s/chg%d", tmpdir, geteuid());
161 }
162 if (r < 0 || (size_t)r >= size)
163 abortmsg("too long TMPDIR (r = %d)", r);
164 }
165
166 static void setcmdserveropts(struct cmdserveropts *opts)
167 {
168 int r;
169 char sockdir[PATH_MAX];
170 const char *envsockname = getenv("CHGSOCKNAME");
171 if (!envsockname) {
172 getdefaultsockdir(sockdir, sizeof(sockdir));
173 preparesockdir(sockdir);
174 }
175
176 const char *basename = (envsockname) ? envsockname : sockdir;
177 const char *sockfmt = (envsockname) ? "%s" : "%s/server";
178 r = snprintf(opts->sockname, sizeof(opts->sockname), sockfmt, basename);
179 if (r < 0 || (size_t)r >= sizeof(opts->sockname))
180 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
181 r = snprintf(opts->initsockname, sizeof(opts->initsockname), "%s.%u",
182 opts->sockname, (unsigned)getpid());
183 if (r < 0 || (size_t)r >= sizeof(opts->initsockname))
184 abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
185 }
186
187 static const char *gethgcmd(void)
188 {
189 static const char *hgcmd = NULL;
190 if (!hgcmd) {
191 hgcmd = getenv("CHGHG");
192 if (!hgcmd || hgcmd[0] == '\0')
193 hgcmd = getenv("HG");
194 if (!hgcmd || hgcmd[0] == '\0')
195 #ifdef HGPATH
196 hgcmd = (HGPATH);
197 #else
198 hgcmd = "hg";
199 #endif
200 }
201 return hgcmd;
202 }
203
204 static void execcmdserver(const struct cmdserveropts *opts)
205 {
206 const char *hgcmd = gethgcmd();
207
208 const char *baseargv[] = {
209 hgcmd,
210 "serve",
211 "--cmdserver",
212 "chgunix",
213 "--address",
214 opts->initsockname,
215 "--daemon-postexec",
216 "chdir:/",
217 };
218 size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]);
219 size_t argsize = baseargvsize + opts->argsize + 1;
220
221 const char **argv = mallocx(sizeof(char *) * argsize);
222 memcpy(argv, baseargv, sizeof(baseargv));
223 if (opts->args) {
224 size_t size = sizeof(char *) * opts->argsize;
225 memcpy(argv + baseargvsize, opts->args, size);
226 }
227 argv[argsize - 1] = NULL;
228
229 if (putenv("CHGINTERNALMARK=") != 0)
230 abortmsgerrno("failed to putenv");
231 if (execvp(hgcmd, (char **)argv) < 0)
232 abortmsgerrno("failed to exec cmdserver");
233 free(argv);
234 }
235
236 /* Retry until we can connect to the server. Give up after some time. */
237 static hgclient_t *retryconnectcmdserver(struct cmdserveropts *opts, pid_t pid)
238 {
239 static const struct timespec sleepreq = {0, 10 * 1000000};
240 int pst = 0;
241
242 debugmsg("try connect to %s repeatedly", opts->initsockname);
243
244 unsigned int timeoutsec = 60; /* default: 60 seconds */
245 const char *timeoutenv = getenv("CHGTIMEOUT");
246 if (timeoutenv)
247 sscanf(timeoutenv, "%u", &timeoutsec);
248
249 for (unsigned int i = 0; !timeoutsec || i < timeoutsec * 100; i++) {
250 hgclient_t *hgc = hgc_open(opts->initsockname);
251 if (hgc) {
252 debugmsg("rename %s to %s", opts->initsockname,
253 opts->sockname);
254 int r = rename(opts->initsockname, opts->sockname);
255 if (r != 0)
256 abortmsgerrno("cannot rename");
257 return hgc;
258 }
259
260 if (pid > 0) {
261 /* collect zombie if child process fails to start */
262 int r = waitpid(pid, &pst, WNOHANG);
263 if (r != 0)
264 goto cleanup;
265 }
266
267 nanosleep(&sleepreq, NULL);
268 }
269
270 abortmsg("timed out waiting for cmdserver %s", opts->initsockname);
271 return NULL;
272
273 cleanup:
274 if (WIFEXITED(pst)) {
275 if (WEXITSTATUS(pst) == 0)
276 abortmsg("could not connect to cmdserver "
277 "(exited with status 0)");
278 debugmsg("cmdserver exited with status %d", WEXITSTATUS(pst));
279 exit(WEXITSTATUS(pst));
280 } else if (WIFSIGNALED(pst)) {
281 abortmsg("cmdserver killed by signal %d", WTERMSIG(pst));
282 } else {
283 abortmsg("error while waiting for cmdserver");
284 }
285 return NULL;
286 }
287
288 /* Connect to a cmdserver. Will start a new server on demand. */
289 static hgclient_t *connectcmdserver(struct cmdserveropts *opts)
290 {
291 const char *sockname =
292 opts->redirectsockname[0] ? opts->redirectsockname : opts->sockname;
293 debugmsg("try connect to %s", sockname);
294 hgclient_t *hgc = hgc_open(sockname);
295 if (hgc)
296 return hgc;
297
298 /* prevent us from being connected to an outdated server: we were
299 * told by a server to redirect to opts->redirectsockname and that
300 * address does not work. we do not want to connect to the server
301 * again because it will probably tell us the same thing. */
302 if (sockname == opts->redirectsockname)
303 unlink(opts->sockname);
304
305 debugmsg("start cmdserver at %s", opts->initsockname);
306
307 pid_t pid = fork();
308 if (pid < 0)
309 abortmsg("failed to fork cmdserver process");
310 if (pid == 0) {
311 execcmdserver(opts);
312 } else {
313 hgc = retryconnectcmdserver(opts, pid);
314 }
315
316 return hgc;
317 }
318
319 static void killcmdserver(const struct cmdserveropts *opts)
320 {
321 /* resolve config hash */
322 char *resolvedpath = realpath(opts->sockname, NULL);
323 if (resolvedpath) {
324 unlink(resolvedpath);
325 free(resolvedpath);
326 }
327 }
328
329 /* Run instructions sent from the server like unlink and set redirect path
330 * Return 1 if reconnect is needed, otherwise 0 */
331 static int runinstructions(struct cmdserveropts *opts, const char **insts)
332 {
333 int needreconnect = 0;
334 if (!insts)
335 return needreconnect;
336
337 assert(insts);
338 opts->redirectsockname[0] = '\0';
339 const char **pinst;
340 for (pinst = insts; *pinst; pinst++) {
341 debugmsg("instruction: %s", *pinst);
342 if (strncmp(*pinst, "unlink ", 7) == 0) {
343 unlink(*pinst + 7);
344 } else if (strncmp(*pinst, "redirect ", 9) == 0) {
345 int r = snprintf(opts->redirectsockname,
346 sizeof(opts->redirectsockname), "%s",
347 *pinst + 9);
348 if (r < 0 || r >= (int)sizeof(opts->redirectsockname))
349 abortmsg("redirect path is too long (%d)", r);
350 needreconnect = 1;
351 } else if (strncmp(*pinst, "exit ", 5) == 0) {
352 int n = 0;
353 if (sscanf(*pinst + 5, "%d", &n) != 1)
354 abortmsg("cannot read the exit code");
355 exit(n);
356 } else if (strcmp(*pinst, "reconnect") == 0) {
357 needreconnect = 1;
358 } else {
359 abortmsg("unknown instruction: %s", *pinst);
360 }
361 }
362 return needreconnect;
363 }
364
365 /*
366 * Test whether the command is unsupported or not. This is not designed to
367 * cover all cases. But it's fast, does not depend on the server and does
368 * not return false positives.
369 */
370 static int isunsupported(int argc, const char *argv[])
371 {
372 enum { SERVE = 1,
373 DAEMON = 2,
374 SERVEDAEMON = SERVE | DAEMON,
375 };
376 unsigned int state = 0;
377 int i;
378 for (i = 0; i < argc; ++i) {
379 if (strcmp(argv[i], "--") == 0)
380 break;
381 if (i == 0 && strcmp("serve", argv[i]) == 0)
382 state |= SERVE;
383 else if (strcmp("-d", argv[i]) == 0 ||
384 strcmp("--daemon", argv[i]) == 0)
385 state |= DAEMON;
386 }
387 return (state & SERVEDAEMON) == SERVEDAEMON;
388 }
389
390 static void execoriginalhg(const char *argv[])
391 {
392 debugmsg("execute original hg");
393 if (execvp(gethgcmd(), (char **)argv) < 0)
394 abortmsgerrno("failed to exec original hg");
395 }
396
397 int main(int argc, const char *argv[], const char *envp[])
398 {
399 if (getenv("CHGDEBUG"))
400 enabledebugmsg();
401
402 if (!getenv("HGPLAIN") && isatty(fileno(stderr)))
403 enablecolor();
404
405 if (getenv("CHGINTERNALMARK"))
406 abortmsg("chg started by chg detected.\n"
407 "Please make sure ${HG:-hg} is not a symlink or "
408 "wrapper to chg. Alternatively, set $CHGHG to the "
409 "path of real hg.");
410
411 if (isunsupported(argc - 1, argv + 1))
412 execoriginalhg(argv);
413
414 struct cmdserveropts opts;
415 initcmdserveropts(&opts);
416 setcmdserveropts(&opts);
417 setcmdserverargs(&opts, argc, argv);
418
419 if (argc == 2) {
420 if (strcmp(argv[1], "--kill-chg-daemon") == 0) {
421 killcmdserver(&opts);
422 return 0;
423 }
424 }
425
426 hgclient_t *hgc;
427 size_t retry = 0;
428 while (1) {
429 hgc = connectcmdserver(&opts);
430 if (!hgc)
431 abortmsg("cannot open hg client");
432 hgc_setenv(hgc, envp);
433 const char **insts = hgc_validate(hgc, argv + 1, argc - 1);
434 int needreconnect = runinstructions(&opts, insts);
435 free(insts);
436 if (!needreconnect)
437 break;
438 hgc_close(hgc);
439 if (++retry > 10)
440 abortmsg("too many redirections.\n"
441 "Please make sure %s is not a wrapper which "
442 "changes sensitive environment variables "
443 "before executing hg. If you have to use a "
444 "wrapper, wrap chg instead of hg.",
445 gethgcmd());
446 }
447
448 setupsignalhandler(hgc_peerpid(hgc), hgc_peerpgid(hgc));
449 atexit(waitpager);
450 int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
451 restoresignalhandler();
452 hgc_close(hgc);
453 freecmdserveropts(&opts);
454
455 return exitcode;
456 }
This diff has been collapsed as it changes many lines, (619 lines changed) Show them Hide them
@@ -0,0 +1,619 b''
1 /*
2 * A command server client that uses Unix domain socket
3 *
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 *
6 * This software may be used and distributed according to the terms of the
7 * GNU General Public License version 2 or any later version.
8 */
9
10 #include <arpa/inet.h> /* for ntohl(), htonl() */
11 #include <assert.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <signal.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/socket.h>
21 #include <sys/stat.h>
22 #include <sys/un.h>
23 #include <unistd.h>
24
25 #include "hgclient.h"
26 #include "procutil.h"
27 #include "util.h"
28
29 enum { CAP_GETENCODING = 0x0001,
30 CAP_RUNCOMMAND = 0x0002,
31 /* cHg extension: */
32 CAP_ATTACHIO = 0x0100,
33 CAP_CHDIR = 0x0200,
34 CAP_SETENV = 0x0800,
35 CAP_SETUMASK = 0x1000,
36 CAP_VALIDATE = 0x2000,
37 CAP_SETPROCNAME = 0x4000,
38 };
39
40 typedef struct {
41 const char *name;
42 unsigned int flag;
43 } cappair_t;
44
45 static const cappair_t captable[] = {
46 {"getencoding", CAP_GETENCODING},
47 {"runcommand", CAP_RUNCOMMAND},
48 {"attachio", CAP_ATTACHIO},
49 {"chdir", CAP_CHDIR},
50 {"setenv", CAP_SETENV},
51 {"setumask", CAP_SETUMASK},
52 {"validate", CAP_VALIDATE},
53 {"setprocname", CAP_SETPROCNAME},
54 {NULL, 0}, /* terminator */
55 };
56
57 typedef struct {
58 char ch;
59 char *data;
60 size_t maxdatasize;
61 size_t datasize;
62 } context_t;
63
64 struct hgclient_tag_ {
65 int sockfd;
66 pid_t pgid;
67 pid_t pid;
68 context_t ctx;
69 unsigned int capflags;
70 };
71
72 static const size_t defaultdatasize = 4096;
73
74 static void attachio(hgclient_t *hgc);
75
76 static void initcontext(context_t *ctx)
77 {
78 ctx->ch = '\0';
79 ctx->data = malloc(defaultdatasize);
80 ctx->maxdatasize = (ctx->data) ? defaultdatasize : 0;
81 ctx->datasize = 0;
82 debugmsg("initialize context buffer with size %zu", ctx->maxdatasize);
83 }
84
85 static void enlargecontext(context_t *ctx, size_t newsize)
86 {
87 if (newsize <= ctx->maxdatasize)
88 return;
89
90 newsize = defaultdatasize *
91 ((newsize + defaultdatasize - 1) / defaultdatasize);
92 ctx->data = reallocx(ctx->data, newsize);
93 ctx->maxdatasize = newsize;
94 debugmsg("enlarge context buffer to %zu", ctx->maxdatasize);
95 }
96
97 static void freecontext(context_t *ctx)
98 {
99 debugmsg("free context buffer");
100 free(ctx->data);
101 ctx->data = NULL;
102 ctx->maxdatasize = 0;
103 ctx->datasize = 0;
104 }
105
106 /* Read channeled response from cmdserver */
107 static void readchannel(hgclient_t *hgc)
108 {
109 assert(hgc);
110
111 ssize_t rsize = recv(hgc->sockfd, &hgc->ctx.ch, sizeof(hgc->ctx.ch), 0);
112 if (rsize != sizeof(hgc->ctx.ch)) {
113 /* server would have exception and traceback would be printed */
114 debugmsg("failed to read channel");
115 exit(255);
116 }
117
118 uint32_t datasize_n;
119 rsize = recv(hgc->sockfd, &datasize_n, sizeof(datasize_n), 0);
120 if (rsize != sizeof(datasize_n))
121 abortmsg("failed to read data size");
122
123 /* datasize denotes the maximum size to write if input request */
124 hgc->ctx.datasize = ntohl(datasize_n);
125 enlargecontext(&hgc->ctx, hgc->ctx.datasize);
126
127 if (isupper(hgc->ctx.ch) && hgc->ctx.ch != 'S')
128 return; /* assumes input request */
129
130 size_t cursize = 0;
131 while (cursize < hgc->ctx.datasize) {
132 rsize = recv(hgc->sockfd, hgc->ctx.data + cursize,
133 hgc->ctx.datasize - cursize, 0);
134 if (rsize < 1)
135 abortmsg("failed to read data block");
136 cursize += rsize;
137 }
138 }
139
140 static void sendall(int sockfd, const void *data, size_t datasize)
141 {
142 const char *p = data;
143 const char *const endp = p + datasize;
144 while (p < endp) {
145 ssize_t r = send(sockfd, p, endp - p, 0);
146 if (r < 0)
147 abortmsgerrno("cannot communicate");
148 p += r;
149 }
150 }
151
152 /* Write lengh-data block to cmdserver */
153 static void writeblock(const hgclient_t *hgc)
154 {
155 assert(hgc);
156
157 const uint32_t datasize_n = htonl(hgc->ctx.datasize);
158 sendall(hgc->sockfd, &datasize_n, sizeof(datasize_n));
159
160 sendall(hgc->sockfd, hgc->ctx.data, hgc->ctx.datasize);
161 }
162
163 static void writeblockrequest(const hgclient_t *hgc, const char *chcmd)
164 {
165 debugmsg("request %s, block size %zu", chcmd, hgc->ctx.datasize);
166
167 char buf[strlen(chcmd) + 1];
168 memcpy(buf, chcmd, sizeof(buf) - 1);
169 buf[sizeof(buf) - 1] = '\n';
170 sendall(hgc->sockfd, buf, sizeof(buf));
171
172 writeblock(hgc);
173 }
174
175 /* Build '\0'-separated list of args. argsize < 0 denotes that args are
176 * terminated by NULL. */
177 static void packcmdargs(context_t *ctx, const char *const args[],
178 ssize_t argsize)
179 {
180 ctx->datasize = 0;
181 const char *const *const end = (argsize >= 0) ? args + argsize : NULL;
182 for (const char *const *it = args; it != end && *it; ++it) {
183 const size_t n = strlen(*it) + 1; /* include '\0' */
184 enlargecontext(ctx, ctx->datasize + n);
185 memcpy(ctx->data + ctx->datasize, *it, n);
186 ctx->datasize += n;
187 }
188
189 if (ctx->datasize > 0)
190 --ctx->datasize; /* strip last '\0' */
191 }
192
193 /* Extract '\0'-separated list of args to new buffer, terminated by NULL */
194 static const char **unpackcmdargsnul(const context_t *ctx)
195 {
196 const char **args = NULL;
197 size_t nargs = 0, maxnargs = 0;
198 const char *s = ctx->data;
199 const char *e = ctx->data + ctx->datasize;
200 for (;;) {
201 if (nargs + 1 >= maxnargs) { /* including last NULL */
202 maxnargs += 256;
203 args = reallocx(args, maxnargs * sizeof(args[0]));
204 }
205 args[nargs] = s;
206 nargs++;
207 s = memchr(s, '\0', e - s);
208 if (!s)
209 break;
210 s++;
211 }
212 args[nargs] = NULL;
213 return args;
214 }
215
216 static void handlereadrequest(hgclient_t *hgc)
217 {
218 context_t *ctx = &hgc->ctx;
219 size_t r = fread(ctx->data, sizeof(ctx->data[0]), ctx->datasize, stdin);
220 ctx->datasize = r;
221 writeblock(hgc);
222 }
223
224 /* Read single-line */
225 static void handlereadlinerequest(hgclient_t *hgc)
226 {
227 context_t *ctx = &hgc->ctx;
228 if (!fgets(ctx->data, ctx->datasize, stdin))
229 ctx->data[0] = '\0';
230 ctx->datasize = strlen(ctx->data);
231 writeblock(hgc);
232 }
233
234 /* Execute the requested command and write exit code */
235 static void handlesystemrequest(hgclient_t *hgc)
236 {
237 context_t *ctx = &hgc->ctx;
238 enlargecontext(ctx, ctx->datasize + 1);
239 ctx->data[ctx->datasize] = '\0'; /* terminate last string */
240
241 const char **args = unpackcmdargsnul(ctx);
242 if (!args[0] || !args[1] || !args[2])
243 abortmsg("missing type or command or cwd in system request");
244 if (strcmp(args[0], "system") == 0) {
245 debugmsg("run '%s' at '%s'", args[1], args[2]);
246 int32_t r = runshellcmd(args[1], args + 3, args[2]);
247 free(args);
248
249 uint32_t r_n = htonl(r);
250 memcpy(ctx->data, &r_n, sizeof(r_n));
251 ctx->datasize = sizeof(r_n);
252 writeblock(hgc);
253 } else if (strcmp(args[0], "pager") == 0) {
254 setuppager(args[1], args + 3);
255 if (hgc->capflags & CAP_ATTACHIO)
256 attachio(hgc);
257 /* unblock the server */
258 static const char emptycmd[] = "\n";
259 sendall(hgc->sockfd, emptycmd, sizeof(emptycmd) - 1);
260 } else {
261 abortmsg("unknown type in system request: %s", args[0]);
262 }
263 }
264
265 /* Read response of command execution until receiving 'r'-esult */
266 static void handleresponse(hgclient_t *hgc)
267 {
268 for (;;) {
269 readchannel(hgc);
270 context_t *ctx = &hgc->ctx;
271 debugmsg("response read from channel %c, size %zu", ctx->ch,
272 ctx->datasize);
273 switch (ctx->ch) {
274 case 'o':
275 fwrite(ctx->data, sizeof(ctx->data[0]), ctx->datasize,
276 stdout);
277 break;
278 case 'e':
279 fwrite(ctx->data, sizeof(ctx->data[0]), ctx->datasize,
280 stderr);
281 break;
282 case 'd':
283 /* assumes last char is '\n' */
284 ctx->data[ctx->datasize - 1] = '\0';
285 debugmsg("server: %s", ctx->data);
286 break;
287 case 'r':
288 return;
289 case 'I':
290 handlereadrequest(hgc);
291 break;
292 case 'L':
293 handlereadlinerequest(hgc);
294 break;
295 case 'S':
296 handlesystemrequest(hgc);
297 break;
298 default:
299 if (isupper(ctx->ch))
300 abortmsg("cannot handle response (ch = %c)",
301 ctx->ch);
302 }
303 }
304 }
305
306 static unsigned int parsecapabilities(const char *s, const char *e)
307 {
308 unsigned int flags = 0;
309 while (s < e) {
310 const char *t = strchr(s, ' ');
311 if (!t || t > e)
312 t = e;
313 const cappair_t *cap;
314 for (cap = captable; cap->flag; ++cap) {
315 size_t n = t - s;
316 if (strncmp(s, cap->name, n) == 0 &&
317 strlen(cap->name) == n) {
318 flags |= cap->flag;
319 break;
320 }
321 }
322 s = t + 1;
323 }
324 return flags;
325 }
326
327 static void readhello(hgclient_t *hgc)
328 {
329 readchannel(hgc);
330 context_t *ctx = &hgc->ctx;
331 if (ctx->ch != 'o') {
332 char ch = ctx->ch;
333 if (ch == 'e') {
334 /* write early error and will exit */
335 fwrite(ctx->data, sizeof(ctx->data[0]), ctx->datasize,
336 stderr);
337 handleresponse(hgc);
338 }
339 abortmsg("unexpected channel of hello message (ch = %c)", ch);
340 }
341 enlargecontext(ctx, ctx->datasize + 1);
342 ctx->data[ctx->datasize] = '\0';
343 debugmsg("hello received: %s (size = %zu)", ctx->data, ctx->datasize);
344
345 const char *s = ctx->data;
346 const char *const dataend = ctx->data + ctx->datasize;
347 while (s < dataend) {
348 const char *t = strchr(s, ':');
349 if (!t || t[1] != ' ')
350 break;
351 const char *u = strchr(t + 2, '\n');
352 if (!u)
353 u = dataend;
354 if (strncmp(s, "capabilities:", t - s + 1) == 0) {
355 hgc->capflags = parsecapabilities(t + 2, u);
356 } else if (strncmp(s, "pgid:", t - s + 1) == 0) {
357 hgc->pgid = strtol(t + 2, NULL, 10);
358 } else if (strncmp(s, "pid:", t - s + 1) == 0) {
359 hgc->pid = strtol(t + 2, NULL, 10);
360 }
361 s = u + 1;
362 }
363 debugmsg("capflags=0x%04x, pid=%d", hgc->capflags, hgc->pid);
364 }
365
366 static void updateprocname(hgclient_t *hgc)
367 {
368 int r = snprintf(hgc->ctx.data, hgc->ctx.maxdatasize, "chg[worker/%d]",
369 (int)getpid());
370 if (r < 0 || (size_t)r >= hgc->ctx.maxdatasize)
371 abortmsg("insufficient buffer to write procname (r = %d)", r);
372 hgc->ctx.datasize = (size_t)r;
373 writeblockrequest(hgc, "setprocname");
374 }
375
376 static void attachio(hgclient_t *hgc)
377 {
378 debugmsg("request attachio");
379 static const char chcmd[] = "attachio\n";
380 sendall(hgc->sockfd, chcmd, sizeof(chcmd) - 1);
381 readchannel(hgc);
382 context_t *ctx = &hgc->ctx;
383 if (ctx->ch != 'I')
384 abortmsg("unexpected response for attachio (ch = %c)", ctx->ch);
385
386 static const int fds[3] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO};
387 struct msghdr msgh;
388 memset(&msgh, 0, sizeof(msgh));
389 struct iovec iov = {ctx->data, ctx->datasize}; /* dummy payload */
390 msgh.msg_iov = &iov;
391 msgh.msg_iovlen = 1;
392 char fdbuf[CMSG_SPACE(sizeof(fds))];
393 msgh.msg_control = fdbuf;
394 msgh.msg_controllen = sizeof(fdbuf);
395 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
396 cmsg->cmsg_level = SOL_SOCKET;
397 cmsg->cmsg_type = SCM_RIGHTS;
398 cmsg->cmsg_len = CMSG_LEN(sizeof(fds));
399 memcpy(CMSG_DATA(cmsg), fds, sizeof(fds));
400 msgh.msg_controllen = cmsg->cmsg_len;
401 ssize_t r = sendmsg(hgc->sockfd, &msgh, 0);
402 if (r < 0)
403 abortmsgerrno("sendmsg failed");
404
405 handleresponse(hgc);
406 int32_t n;
407 if (ctx->datasize != sizeof(n))
408 abortmsg("unexpected size of attachio result");
409 memcpy(&n, ctx->data, sizeof(n));
410 n = ntohl(n);
411 if (n != sizeof(fds) / sizeof(fds[0]))
412 abortmsg("failed to send fds (n = %d)", n);
413 }
414
415 static void chdirtocwd(hgclient_t *hgc)
416 {
417 if (!getcwd(hgc->ctx.data, hgc->ctx.maxdatasize))
418 abortmsgerrno("failed to getcwd");
419 hgc->ctx.datasize = strlen(hgc->ctx.data);
420 writeblockrequest(hgc, "chdir");
421 }
422
423 static void forwardumask(hgclient_t *hgc)
424 {
425 mode_t mask = umask(0);
426 umask(mask);
427
428 static const char command[] = "setumask\n";
429 sendall(hgc->sockfd, command, sizeof(command) - 1);
430 uint32_t data = htonl(mask);
431 sendall(hgc->sockfd, &data, sizeof(data));
432 }
433
434 /*!
435 * Open connection to per-user cmdserver
436 *
437 * If no background server running, returns NULL.
438 */
439 hgclient_t *hgc_open(const char *sockname)
440 {
441 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
442 if (fd < 0)
443 abortmsgerrno("cannot create socket");
444
445 /* don't keep fd on fork(), so that it can be closed when the parent
446 * process get terminated. */
447 fsetcloexec(fd);
448
449 struct sockaddr_un addr;
450 addr.sun_family = AF_UNIX;
451
452 /* use chdir to workaround small sizeof(sun_path) */
453 int bakfd = -1;
454 const char *basename = sockname;
455 {
456 const char *split = strrchr(sockname, '/');
457 if (split && split != sockname) {
458 if (split[1] == '\0')
459 abortmsg("sockname cannot end with a slash");
460 size_t len = split - sockname;
461 char sockdir[len + 1];
462 memcpy(sockdir, sockname, len);
463 sockdir[len] = '\0';
464
465 bakfd = open(".", O_DIRECTORY);
466 if (bakfd == -1)
467 abortmsgerrno("cannot open cwd");
468
469 int r = chdir(sockdir);
470 if (r != 0)
471 abortmsgerrno("cannot chdir %s", sockdir);
472
473 basename = split + 1;
474 }
475 }
476 if (strlen(basename) >= sizeof(addr.sun_path))
477 abortmsg("sockname is too long: %s", basename);
478 strncpy(addr.sun_path, basename, sizeof(addr.sun_path));
479 addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
480
481 /* real connect */
482 int r = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
483 if (r < 0) {
484 if (errno != ENOENT && errno != ECONNREFUSED)
485 abortmsgerrno("cannot connect to %s", sockname);
486 }
487 if (bakfd != -1) {
488 fchdirx(bakfd);
489 close(bakfd);
490 }
491 if (r < 0) {
492 close(fd);
493 return NULL;
494 }
495 debugmsg("connected to %s", addr.sun_path);
496
497 hgclient_t *hgc = mallocx(sizeof(hgclient_t));
498 memset(hgc, 0, sizeof(*hgc));
499 hgc->sockfd = fd;
500 initcontext(&hgc->ctx);
501
502 readhello(hgc);
503 if (!(hgc->capflags & CAP_RUNCOMMAND))
504 abortmsg("insufficient capability: runcommand");
505 if (hgc->capflags & CAP_SETPROCNAME)
506 updateprocname(hgc);
507 if (hgc->capflags & CAP_ATTACHIO)
508 attachio(hgc);
509 if (hgc->capflags & CAP_CHDIR)
510 chdirtocwd(hgc);
511 if (hgc->capflags & CAP_SETUMASK)
512 forwardumask(hgc);
513
514 return hgc;
515 }
516
517 /*!
518 * Close connection and free allocated memory
519 */
520 void hgc_close(hgclient_t *hgc)
521 {
522 assert(hgc);
523 freecontext(&hgc->ctx);
524 close(hgc->sockfd);
525 free(hgc);
526 }
527
528 pid_t hgc_peerpgid(const hgclient_t *hgc)
529 {
530 assert(hgc);
531 return hgc->pgid;
532 }
533
534 pid_t hgc_peerpid(const hgclient_t *hgc)
535 {
536 assert(hgc);
537 return hgc->pid;
538 }
539
540 /*!
541 * Send command line arguments to let the server load the repo config and check
542 * whether it can process our request directly or not.
543 * Make sure hgc_setenv is called before calling this.
544 *
545 * @return - NULL, the server believes it can handle our request, or does not
546 * support "validate" command.
547 * - a list of strings, the server probably cannot handle our request
548 * and it sent instructions telling us what to do next. See
549 * chgserver.py for possible instruction formats.
550 * the list should be freed by the caller.
551 * the last string is guaranteed to be NULL.
552 */
553 const char **hgc_validate(hgclient_t *hgc, const char *const args[],
554 size_t argsize)
555 {
556 assert(hgc);
557 if (!(hgc->capflags & CAP_VALIDATE))
558 return NULL;
559
560 packcmdargs(&hgc->ctx, args, argsize);
561 writeblockrequest(hgc, "validate");
562 handleresponse(hgc);
563
564 /* the server returns '\0' if it can handle our request */
565 if (hgc->ctx.datasize <= 1)
566 return NULL;
567
568 /* make sure the buffer is '\0' terminated */
569 enlargecontext(&hgc->ctx, hgc->ctx.datasize + 1);
570 hgc->ctx.data[hgc->ctx.datasize] = '\0';
571 return unpackcmdargsnul(&hgc->ctx);
572 }
573
574 /*!
575 * Execute the specified Mercurial command
576 *
577 * @return result code
578 */
579 int hgc_runcommand(hgclient_t *hgc, const char *const args[], size_t argsize)
580 {
581 assert(hgc);
582
583 packcmdargs(&hgc->ctx, args, argsize);
584 writeblockrequest(hgc, "runcommand");
585 handleresponse(hgc);
586
587 int32_t exitcode_n;
588 if (hgc->ctx.datasize != sizeof(exitcode_n)) {
589 abortmsg("unexpected size of exitcode");
590 }
591 memcpy(&exitcode_n, hgc->ctx.data, sizeof(exitcode_n));
592 return ntohl(exitcode_n);
593 }
594
595 /*!
596 * (Re-)send client's stdio channels so that the server can access to tty
597 */
598 void hgc_attachio(hgclient_t *hgc)
599 {
600 assert(hgc);
601 if (!(hgc->capflags & CAP_ATTACHIO))
602 return;
603 attachio(hgc);
604 }
605
606 /*!
607 * Update server's environment variables
608 *
609 * @param envp list of environment variables in "NAME=VALUE" format,
610 * terminated by NULL.
611 */
612 void hgc_setenv(hgclient_t *hgc, const char *const envp[])
613 {
614 assert(hgc && envp);
615 if (!(hgc->capflags & CAP_SETENV))
616 return;
617 packcmdargs(&hgc->ctx, envp, /*argsize*/ -1);
618 writeblockrequest(hgc, "setenv");
619 }
@@ -0,0 +1,30 b''
1 /*
2 * A command server client that uses Unix domain socket
3 *
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 *
6 * This software may be used and distributed according to the terms of the
7 * GNU General Public License version 2 or any later version.
8 */
9
10 #ifndef HGCLIENT_H_
11 #define HGCLIENT_H_
12
13 #include <sys/types.h>
14
15 struct hgclient_tag_;
16 typedef struct hgclient_tag_ hgclient_t;
17
18 hgclient_t *hgc_open(const char *sockname);
19 void hgc_close(hgclient_t *hgc);
20
21 pid_t hgc_peerpgid(const hgclient_t *hgc);
22 pid_t hgc_peerpid(const hgclient_t *hgc);
23
24 const char **hgc_validate(hgclient_t *hgc, const char *const args[],
25 size_t argsize);
26 int hgc_runcommand(hgclient_t *hgc, const char *const args[], size_t argsize);
27 void hgc_attachio(hgclient_t *hgc);
28 void hgc_setenv(hgclient_t *hgc, const char *const envp[]);
29
30 #endif /* HGCLIENT_H_ */
@@ -0,0 +1,237 b''
1 /*
2 * Utilities about process handling - signal and subprocess (ex. pager)
3 *
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 *
6 * This software may be used and distributed according to the terms of the
7 * GNU General Public License version 2 or any later version.
8 */
9
10 #include <assert.h>
11 #include <errno.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/wait.h>
16 #include <unistd.h>
17
18 #include "procutil.h"
19 #include "util.h"
20
21 static pid_t pagerpid = 0;
22 static pid_t peerpgid = 0;
23 static pid_t peerpid = 0;
24
25 static void forwardsignal(int sig)
26 {
27 assert(peerpid > 0);
28 if (kill(peerpid, sig) < 0)
29 abortmsgerrno("cannot kill %d", peerpid);
30 debugmsg("forward signal %d", sig);
31 }
32
33 static void forwardsignaltogroup(int sig)
34 {
35 /* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */
36 pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid;
37 if (kill(killpid, sig) < 0)
38 abortmsgerrno("cannot kill %d", killpid);
39 debugmsg("forward signal %d to %d", sig, killpid);
40 }
41
42 static void handlestopsignal(int sig)
43 {
44 sigset_t unblockset, oldset;
45 struct sigaction sa, oldsa;
46 if (sigemptyset(&unblockset) < 0)
47 goto error;
48 if (sigaddset(&unblockset, sig) < 0)
49 goto error;
50 memset(&sa, 0, sizeof(sa));
51 sa.sa_handler = SIG_DFL;
52 sa.sa_flags = SA_RESTART;
53 if (sigemptyset(&sa.sa_mask) < 0)
54 goto error;
55
56 forwardsignal(sig);
57 if (raise(sig) < 0) /* resend to self */
58 goto error;
59 if (sigaction(sig, &sa, &oldsa) < 0)
60 goto error;
61 if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0)
62 goto error;
63 /* resent signal will be handled before sigprocmask() returns */
64 if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
65 goto error;
66 if (sigaction(sig, &oldsa, NULL) < 0)
67 goto error;
68 return;
69
70 error:
71 abortmsgerrno("failed to handle stop signal");
72 }
73
74 static void handlechildsignal(int sig UNUSED_)
75 {
76 if (peerpid == 0 || pagerpid == 0)
77 return;
78 /* if pager exits, notify the server with SIGPIPE immediately.
79 * otherwise the server won't get SIGPIPE if it does not write
80 * anything. (issue5278) */
81 if (waitpid(pagerpid, NULL, WNOHANG) == pagerpid)
82 kill(peerpid, SIGPIPE);
83 }
84
85 void setupsignalhandler(pid_t pid, pid_t pgid)
86 {
87 if (pid <= 0)
88 return;
89 peerpid = pid;
90 peerpgid = (pgid <= 1 ? 0 : pgid);
91
92 struct sigaction sa;
93 memset(&sa, 0, sizeof(sa));
94
95 /* deadly signals meant to be sent to a process group:
96 * - SIGHUP: usually generated by the kernel, when termination of a
97 * process causes that process group to become orphaned
98 * - SIGINT: usually generated by the terminal */
99 sa.sa_handler = forwardsignaltogroup;
100 sa.sa_flags = SA_RESTART;
101 if (sigemptyset(&sa.sa_mask) < 0)
102 goto error;
103 if (sigaction(SIGHUP, &sa, NULL) < 0)
104 goto error;
105 if (sigaction(SIGINT, &sa, NULL) < 0)
106 goto error;
107
108 /* terminate frontend by double SIGTERM in case of server freeze */
109 sa.sa_handler = forwardsignal;
110 sa.sa_flags |= SA_RESETHAND;
111 if (sigaction(SIGTERM, &sa, NULL) < 0)
112 goto error;
113
114 /* notify the worker about window resize events */
115 sa.sa_flags = SA_RESTART;
116 if (sigaction(SIGWINCH, &sa, NULL) < 0)
117 goto error;
118 /* forward user-defined signals */
119 if (sigaction(SIGUSR1, &sa, NULL) < 0)
120 goto error;
121 if (sigaction(SIGUSR2, &sa, NULL) < 0)
122 goto error;
123 /* propagate job control requests to worker */
124 sa.sa_handler = forwardsignal;
125 sa.sa_flags = SA_RESTART;
126 if (sigaction(SIGCONT, &sa, NULL) < 0)
127 goto error;
128 sa.sa_handler = handlestopsignal;
129 sa.sa_flags = SA_RESTART;
130 if (sigaction(SIGTSTP, &sa, NULL) < 0)
131 goto error;
132 /* get notified when pager exits */
133 sa.sa_handler = handlechildsignal;
134 sa.sa_flags = SA_RESTART;
135 if (sigaction(SIGCHLD, &sa, NULL) < 0)
136 goto error;
137
138 return;
139
140 error:
141 abortmsgerrno("failed to set up signal handlers");
142 }
143
144 void restoresignalhandler(void)
145 {
146 struct sigaction sa;
147 memset(&sa, 0, sizeof(sa));
148 sa.sa_handler = SIG_DFL;
149 sa.sa_flags = SA_RESTART;
150 if (sigemptyset(&sa.sa_mask) < 0)
151 goto error;
152
153 if (sigaction(SIGHUP, &sa, NULL) < 0)
154 goto error;
155 if (sigaction(SIGTERM, &sa, NULL) < 0)
156 goto error;
157 if (sigaction(SIGWINCH, &sa, NULL) < 0)
158 goto error;
159 if (sigaction(SIGCONT, &sa, NULL) < 0)
160 goto error;
161 if (sigaction(SIGTSTP, &sa, NULL) < 0)
162 goto error;
163 if (sigaction(SIGCHLD, &sa, NULL) < 0)
164 goto error;
165
166 /* ignore Ctrl+C while shutting down to make pager exits cleanly */
167 sa.sa_handler = SIG_IGN;
168 if (sigaction(SIGINT, &sa, NULL) < 0)
169 goto error;
170
171 peerpid = 0;
172 return;
173
174 error:
175 abortmsgerrno("failed to restore signal handlers");
176 }
177
178 /* This implementation is based on hgext/pager.py (post 369741ef7253)
179 * Return 0 if pager is not started, or pid of the pager */
180 pid_t setuppager(const char *pagercmd, const char *envp[])
181 {
182 assert(pagerpid == 0);
183 if (!pagercmd)
184 return 0;
185
186 int pipefds[2];
187 if (pipe(pipefds) < 0)
188 return 0;
189 pid_t pid = fork();
190 if (pid < 0)
191 goto error;
192 if (pid > 0) {
193 close(pipefds[0]);
194 if (dup2(pipefds[1], fileno(stdout)) < 0)
195 goto error;
196 if (isatty(fileno(stderr))) {
197 if (dup2(pipefds[1], fileno(stderr)) < 0)
198 goto error;
199 }
200 close(pipefds[1]);
201 pagerpid = pid;
202 return pid;
203 } else {
204 dup2(pipefds[0], fileno(stdin));
205 close(pipefds[0]);
206 close(pipefds[1]);
207
208 int r =
209 execle("/bin/sh", "/bin/sh", "-c", pagercmd, NULL, envp);
210 if (r < 0) {
211 abortmsgerrno("cannot start pager '%s'", pagercmd);
212 }
213 return 0;
214 }
215
216 error:
217 close(pipefds[0]);
218 close(pipefds[1]);
219 abortmsgerrno("failed to prepare pager");
220 return 0;
221 }
222
223 void waitpager(void)
224 {
225 if (pagerpid == 0)
226 return;
227
228 /* close output streams to notify the pager its input ends */
229 fclose(stdout);
230 fclose(stderr);
231 while (1) {
232 pid_t ret = waitpid(pagerpid, NULL, 0);
233 if (ret == -1 && errno == EINTR)
234 continue;
235 break;
236 }
237 }
@@ -0,0 +1,21 b''
1 /*
2 * Utilities about process handling - signal and subprocess (ex. pager)
3 *
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 *
6 * This software may be used and distributed according to the terms of the
7 * GNU General Public License version 2 or any later version.
8 */
9
10 #ifndef PROCUTIL_H_
11 #define PROCUTIL_H_
12
13 #include <unistd.h>
14
15 void restoresignalhandler(void);
16 void setupsignalhandler(pid_t pid, pid_t pgid);
17
18 pid_t setuppager(const char *pagercmd, const char *envp[]);
19 void waitpager(void);
20
21 #endif /* PROCUTIL_H_ */
@@ -0,0 +1,200 b''
1 /*
2 * Utility functions
3 *
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 *
6 * This software may be used and distributed according to the terms of the
7 * GNU General Public License version 2 or any later version.
8 */
9
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <signal.h>
13 #include <stdarg.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/time.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <unistd.h>
21
22 #include "util.h"
23
24 static int colorenabled = 0;
25
26 static inline void fsetcolor(FILE *fp, const char *code)
27 {
28 if (!colorenabled)
29 return;
30 fprintf(fp, "\033[%sm", code);
31 }
32
33 static void vabortmsgerrno(int no, const char *fmt, va_list args)
34 {
35 fsetcolor(stderr, "1;31");
36 fputs("chg: abort: ", stderr);
37 vfprintf(stderr, fmt, args);
38 if (no != 0)
39 fprintf(stderr, " (errno = %d, %s)", no, strerror(no));
40 fsetcolor(stderr, "");
41 fputc('\n', stderr);
42 exit(255);
43 }
44
45 void abortmsg(const char *fmt, ...)
46 {
47 va_list args;
48 va_start(args, fmt);
49 vabortmsgerrno(0, fmt, args);
50 va_end(args);
51 }
52
53 void abortmsgerrno(const char *fmt, ...)
54 {
55 int no = errno;
56 va_list args;
57 va_start(args, fmt);
58 vabortmsgerrno(no, fmt, args);
59 va_end(args);
60 }
61
62 static int debugmsgenabled = 0;
63 static double debugstart = 0;
64
65 static double now()
66 {
67 struct timeval t;
68 gettimeofday(&t, NULL);
69 return t.tv_usec / 1e6 + t.tv_sec;
70 }
71
72 void enablecolor(void)
73 {
74 colorenabled = 1;
75 }
76
77 void enabledebugmsg(void)
78 {
79 debugmsgenabled = 1;
80 debugstart = now();
81 }
82
83 void debugmsg(const char *fmt, ...)
84 {
85 if (!debugmsgenabled)
86 return;
87
88 va_list args;
89 va_start(args, fmt);
90 fsetcolor(stderr, "1;30");
91 fprintf(stderr, "chg: debug: %4.6f ", now() - debugstart);
92 vfprintf(stderr, fmt, args);
93 fsetcolor(stderr, "");
94 fputc('\n', stderr);
95 va_end(args);
96 }
97
98 void fchdirx(int dirfd)
99 {
100 int r = fchdir(dirfd);
101 if (r == -1)
102 abortmsgerrno("failed to fchdir");
103 }
104
105 void fsetcloexec(int fd)
106 {
107 int flags = fcntl(fd, F_GETFD);
108 if (flags < 0)
109 abortmsgerrno("cannot get flags of fd %d", fd);
110 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
111 abortmsgerrno("cannot set flags of fd %d", fd);
112 }
113
114 void *mallocx(size_t size)
115 {
116 void *result = malloc(size);
117 if (!result)
118 abortmsg("failed to malloc");
119 return result;
120 }
121
122 void *reallocx(void *ptr, size_t size)
123 {
124 void *result = realloc(ptr, size);
125 if (!result)
126 abortmsg("failed to realloc");
127 return result;
128 }
129
130 /*
131 * Execute a shell command in mostly the same manner as system(), with the
132 * give environment variables, after chdir to the given cwd. Returns a status
133 * code compatible with the Python subprocess module.
134 */
135 int runshellcmd(const char *cmd, const char *envp[], const char *cwd)
136 {
137 enum { F_SIGINT = 1, F_SIGQUIT = 2, F_SIGMASK = 4, F_WAITPID = 8 };
138 unsigned int doneflags = 0;
139 int status = 0;
140 struct sigaction newsa, oldsaint, oldsaquit;
141 sigset_t oldmask;
142
143 /* block or mask signals just as system() does */
144 memset(&newsa, 0, sizeof(newsa));
145 newsa.sa_handler = SIG_IGN;
146 newsa.sa_flags = 0;
147 if (sigemptyset(&newsa.sa_mask) < 0)
148 goto done;
149 if (sigaction(SIGINT, &newsa, &oldsaint) < 0)
150 goto done;
151 doneflags |= F_SIGINT;
152 if (sigaction(SIGQUIT, &newsa, &oldsaquit) < 0)
153 goto done;
154 doneflags |= F_SIGQUIT;
155
156 if (sigaddset(&newsa.sa_mask, SIGCHLD) < 0)
157 goto done;
158 if (sigprocmask(SIG_BLOCK, &newsa.sa_mask, &oldmask) < 0)
159 goto done;
160 doneflags |= F_SIGMASK;
161
162 pid_t pid = fork();
163 if (pid < 0)
164 goto done;
165 if (pid == 0) {
166 sigaction(SIGINT, &oldsaint, NULL);
167 sigaction(SIGQUIT, &oldsaquit, NULL);
168 sigprocmask(SIG_SETMASK, &oldmask, NULL);
169 if (cwd && chdir(cwd) < 0)
170 _exit(127);
171 const char *argv[] = {"sh", "-c", cmd, NULL};
172 if (envp) {
173 execve("/bin/sh", (char **)argv, (char **)envp);
174 } else {
175 execv("/bin/sh", (char **)argv);
176 }
177 _exit(127);
178 } else {
179 if (waitpid(pid, &status, 0) < 0)
180 goto done;
181 doneflags |= F_WAITPID;
182 }
183
184 done:
185 if (doneflags & F_SIGINT)
186 sigaction(SIGINT, &oldsaint, NULL);
187 if (doneflags & F_SIGQUIT)
188 sigaction(SIGQUIT, &oldsaquit, NULL);
189 if (doneflags & F_SIGMASK)
190 sigprocmask(SIG_SETMASK, &oldmask, NULL);
191
192 /* no way to report other errors, use 127 (= shell termination) */
193 if (!(doneflags & F_WAITPID))
194 return 127;
195 if (WIFEXITED(status))
196 return WEXITSTATUS(status);
197 if (WIFSIGNALED(status))
198 return -WTERMSIG(status);
199 return 127;
200 }
@@ -0,0 +1,35 b''
1 /*
2 * Utility functions
3 *
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 *
6 * This software may be used and distributed according to the terms of the
7 * GNU General Public License version 2 or any later version.
8 */
9
10 #ifndef UTIL_H_
11 #define UTIL_H_
12
13 #ifdef __GNUC__
14 #define PRINTF_FORMAT_ __attribute__((format(printf, 1, 2)))
15 #define UNUSED_ __attribute__((unused))
16 #else
17 #define PRINTF_FORMAT_
18 #define UNUSED_
19 #endif
20
21 void abortmsg(const char *fmt, ...) PRINTF_FORMAT_;
22 void abortmsgerrno(const char *fmt, ...) PRINTF_FORMAT_;
23
24 void enablecolor(void);
25 void enabledebugmsg(void);
26 void debugmsg(const char *fmt, ...) PRINTF_FORMAT_;
27
28 void fchdirx(int dirfd);
29 void fsetcloexec(int fd);
30 void *mallocx(size_t size);
31 void *reallocx(void *ptr, size_t size);
32
33 int runshellcmd(const char *cmd, const char *envp[], const char *cwd);
34
35 #endif /* UTIL_H_ */
@@ -0,0 +1,88 b''
1 # Files that just need to be migrated to the formatter.
2 # Do not add new files here!
3 mercurial/cext/dirs.c
4 mercurial/cext/manifest.c
5 mercurial/cext/osutil.c
6 mercurial/cext/revlog.c
7 # Vendored code that we should never format:
8 contrib/python-zstandard/c-ext/bufferutil.c
9 contrib/python-zstandard/c-ext/compressiondict.c
10 contrib/python-zstandard/c-ext/compressionparams.c
11 contrib/python-zstandard/c-ext/compressionreader.c
12 contrib/python-zstandard/c-ext/compressionwriter.c
13 contrib/python-zstandard/c-ext/compressobj.c
14 contrib/python-zstandard/c-ext/compressor.c
15 contrib/python-zstandard/c-ext/compressoriterator.c
16 contrib/python-zstandard/c-ext/constants.c
17 contrib/python-zstandard/c-ext/decompressionreader.c
18 contrib/python-zstandard/c-ext/decompressionwriter.c
19 contrib/python-zstandard/c-ext/decompressobj.c
20 contrib/python-zstandard/c-ext/decompressor.c
21 contrib/python-zstandard/c-ext/decompressoriterator.c
22 contrib/python-zstandard/c-ext/frameparams.c
23 contrib/python-zstandard/c-ext/python-zstandard.h
24 contrib/python-zstandard/zstd.c
25 contrib/python-zstandard/zstd/common/bitstream.h
26 contrib/python-zstandard/zstd/common/compiler.h
27 contrib/python-zstandard/zstd/common/cpu.h
28 contrib/python-zstandard/zstd/common/entropy_common.c
29 contrib/python-zstandard/zstd/common/error_private.c
30 contrib/python-zstandard/zstd/common/error_private.h
31 contrib/python-zstandard/zstd/common/fse_decompress.c
32 contrib/python-zstandard/zstd/common/fse.h
33 contrib/python-zstandard/zstd/common/huf.h
34 contrib/python-zstandard/zstd/common/mem.h
35 contrib/python-zstandard/zstd/common/pool.c
36 contrib/python-zstandard/zstd/common/pool.h
37 contrib/python-zstandard/zstd/common/threading.c
38 contrib/python-zstandard/zstd/common/threading.h
39 contrib/python-zstandard/zstd/common/xxhash.c
40 contrib/python-zstandard/zstd/common/xxhash.h
41 contrib/python-zstandard/zstd/common/zstd_common.c
42 contrib/python-zstandard/zstd/common/zstd_errors.h
43 contrib/python-zstandard/zstd/common/zstd_internal.h
44 contrib/python-zstandard/zstd/compress/fse_compress.c
45 contrib/python-zstandard/zstd/compress/huf_compress.c
46 contrib/python-zstandard/zstd/compress/zstd_compress.c
47 contrib/python-zstandard/zstd/compress/zstd_compress_internal.h
48 contrib/python-zstandard/zstd/compress/zstd_double_fast.c
49 contrib/python-zstandard/zstd/compress/zstd_double_fast.h
50 contrib/python-zstandard/zstd/compress/zstd_fast.c
51 contrib/python-zstandard/zstd/compress/zstd_fast.h
52 contrib/python-zstandard/zstd/compress/zstd_lazy.c
53 contrib/python-zstandard/zstd/compress/zstd_lazy.h
54 contrib/python-zstandard/zstd/compress/zstd_ldm.c
55 contrib/python-zstandard/zstd/compress/zstd_ldm.h
56 contrib/python-zstandard/zstd/compress/zstdmt_compress.c
57 contrib/python-zstandard/zstd/compress/zstdmt_compress.h
58 contrib/python-zstandard/zstd/compress/zstd_opt.c
59 contrib/python-zstandard/zstd/compress/zstd_opt.h
60 contrib/python-zstandard/zstd/decompress/huf_decompress.c
61 contrib/python-zstandard/zstd/decompress/zstd_decompress.c
62 contrib/python-zstandard/zstd/deprecated/zbuff_common.c
63 contrib/python-zstandard/zstd/deprecated/zbuff_compress.c
64 contrib/python-zstandard/zstd/deprecated/zbuff_decompress.c
65 contrib/python-zstandard/zstd/deprecated/zbuff.h
66 contrib/python-zstandard/zstd/dictBuilder/cover.c
67 contrib/python-zstandard/zstd/dictBuilder/divsufsort.c
68 contrib/python-zstandard/zstd/dictBuilder/divsufsort.h
69 contrib/python-zstandard/zstd/dictBuilder/zdict.c
70 contrib/python-zstandard/zstd/dictBuilder/zdict.h
71 contrib/python-zstandard/zstd/zstd.h
72 hgext/fsmonitor/pywatchman/bser.c
73 mercurial/thirdparty/xdiff/xdiff.h
74 mercurial/thirdparty/xdiff/xdiffi.c
75 mercurial/thirdparty/xdiff/xdiffi.h
76 mercurial/thirdparty/xdiff/xemit.c
77 mercurial/thirdparty/xdiff/xemit.h
78 mercurial/thirdparty/xdiff/xhistogram.c
79 mercurial/thirdparty/xdiff/xinclude.h
80 mercurial/thirdparty/xdiff/xmacros.h
81 mercurial/thirdparty/xdiff/xmerge.c
82 mercurial/thirdparty/xdiff/xpatience.c
83 mercurial/thirdparty/xdiff/xprepare.c
84 mercurial/thirdparty/xdiff/xprepare.h
85 mercurial/thirdparty/xdiff/xtypes.h
86 mercurial/thirdparty/xdiff/xutils.c
87 mercurial/thirdparty/xdiff/xutils.h
88 mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c
@@ -0,0 +1,49 b''
1 #!/usr/bin/env python
2 #
3 # Dumps output generated by Mercurial's command server in a formatted style to a
4 # given file or stderr if '-' is specified. Output is also written in its raw
5 # format to stdout.
6 #
7 # $ ./hg serve --cmds pipe | ./contrib/debugcmdserver.py -
8 # o, 52 -> 'capabilities: getencoding runcommand\nencoding: UTF-8'
9
10 from __future__ import absolute_import, print_function
11 import struct
12 import sys
13
14 if len(sys.argv) != 2:
15 print('usage: debugcmdserver.py FILE')
16 sys.exit(1)
17
18 outputfmt = '>cI'
19 outputfmtsize = struct.calcsize(outputfmt)
20
21 if sys.argv[1] == '-':
22 log = sys.stderr
23 else:
24 log = open(sys.argv[1], 'a')
25
26 def read(size):
27 data = sys.stdin.read(size)
28 if not data:
29 raise EOFError
30 sys.stdout.write(data)
31 sys.stdout.flush()
32 return data
33
34 try:
35 while True:
36 header = read(outputfmtsize)
37 channel, length = struct.unpack(outputfmt, header)
38 log.write('%s, %-4d' % (channel, length))
39 if channel in 'IL':
40 log.write(' -> waiting for input\n')
41 else:
42 data = read(length)
43 log.write(' -> %r\n' % data)
44 log.flush()
45 except EOFError:
46 pass
47 finally:
48 if log != sys.stderr:
49 log.close()
@@ -0,0 +1,59 b''
1 # debugshell extension
2 """a python shell with repo, changelog & manifest objects"""
3
4 from __future__ import absolute_import
5 import code
6 import mercurial
7 import sys
8 from mercurial import (
9 demandimport,
10 registrar,
11 )
12
13 cmdtable = {}
14 command = registrar.command(cmdtable)
15
16 def pdb(ui, repo, msg, **opts):
17 objects = {
18 'mercurial': mercurial,
19 'repo': repo,
20 'cl': repo.changelog,
21 'mf': repo.manifestlog,
22 }
23
24 code.interact(msg, local=objects)
25
26 def ipdb(ui, repo, msg, **opts):
27 import IPython
28
29 cl = repo.changelog
30 mf = repo.manifestlog
31 cl, mf # use variables to appease pyflakes
32
33 IPython.embed()
34
35 @command('debugshell|dbsh', [])
36 def debugshell(ui, repo, **opts):
37 bannermsg = "loaded repo : %s\n" \
38 "using source: %s" % (repo.root,
39 mercurial.__path__[0])
40
41 pdbmap = {
42 'pdb' : 'code',
43 'ipdb' : 'IPython'
44 }
45
46 debugger = ui.config("ui", "debugger")
47 if not debugger:
48 debugger = 'pdb'
49
50 # if IPython doesn't exist, fallback to code.interact
51 try:
52 with demandimport.deactivated():
53 __import__(pdbmap[debugger])
54 except ImportError:
55 ui.warn(("%s debugger specified but %s module was not found\n")
56 % (debugger, pdbmap[debugger]))
57 debugger = 'pdb'
58
59 getattr(sys.modules[__name__], debugger)(ui, repo, bannermsg, **opts)
@@ -0,0 +1,59 b''
1 # dirstatenonnormalcheck.py - extension to check the consistency of the
2 # dirstate's non-normal map
3 #
4 # For most operations on dirstate, this extensions checks that the nonnormalset
5 # contains the right entries.
6 # It compares the nonnormal file to a nonnormalset built from the map of all
7 # the files in the dirstate to check that they contain the same files.
8
9 from __future__ import absolute_import
10
11 from mercurial import (
12 dirstate,
13 extensions,
14 )
15
16 def nonnormalentries(dmap):
17 """Compute nonnormal entries from dirstate's dmap"""
18 res = set()
19 for f, e in dmap.iteritems():
20 if e[0] != b'n' or e[3] == -1:
21 res.add(f)
22 return res
23
24 def checkconsistency(ui, orig, dmap, _nonnormalset, label):
25 """Compute nonnormalset from dmap, check that it matches _nonnormalset"""
26 nonnormalcomputedmap = nonnormalentries(dmap)
27 if _nonnormalset != nonnormalcomputedmap:
28 ui.develwarn(b"%s call to %s\n" % (label, orig), config=b'dirstate')
29 ui.develwarn(b"inconsistency in nonnormalset\n", config=b'dirstate')
30 ui.develwarn(b"[nonnormalset] %s\n" % _nonnormalset, config=b'dirstate')
31 ui.develwarn(b"[map] %s\n" % nonnormalcomputedmap, config=b'dirstate')
32
33 def _checkdirstate(orig, self, arg):
34 """Check nonnormal set consistency before and after the call to orig"""
35 checkconsistency(self._ui, orig, self._map, self._map.nonnormalset,
36 b"before")
37 r = orig(self, arg)
38 checkconsistency(self._ui, orig, self._map, self._map.nonnormalset,
39 b"after")
40 return r
41
42 def extsetup(ui):
43 """Wrap functions modifying dirstate to check nonnormalset consistency"""
44 dirstatecl = dirstate.dirstate
45 devel = ui.configbool(b'devel', b'all-warnings')
46 paranoid = ui.configbool(b'experimental', b'nonnormalparanoidcheck')
47 if devel:
48 extensions.wrapfunction(dirstatecl, '_writedirstate', _checkdirstate)
49 if paranoid:
50 # We don't do all these checks when paranoid is disable as it would
51 # make the extension run very slowly on large repos
52 extensions.wrapfunction(dirstatecl, 'normallookup', _checkdirstate)
53 extensions.wrapfunction(dirstatecl, 'otherparent', _checkdirstate)
54 extensions.wrapfunction(dirstatecl, 'normal', _checkdirstate)
55 extensions.wrapfunction(dirstatecl, 'write', _checkdirstate)
56 extensions.wrapfunction(dirstatecl, 'add', _checkdirstate)
57 extensions.wrapfunction(dirstatecl, 'remove', _checkdirstate)
58 extensions.wrapfunction(dirstatecl, 'merge', _checkdirstate)
59 extensions.wrapfunction(dirstatecl, 'drop', _checkdirstate)
@@ -0,0 +1,23 b''
1 FROM debian:wheezy
2
3 ENV DEBIAN_FRONTEND noninteractive
4 ENV WSGI_PROCESSES 4
5 ENV WSGI_THREADS 1
6 ENV WSGI_MAX_REQUESTS 100000
7
8 EXPOSE 80
9 VOLUME ["/var/hg/htdocs", "/var/hg/repos"]
10
11 RUN apt-get update && apt-get -y install libapache2-mod-wsgi python-dev vim
12
13 # Install our own Apache site.
14 RUN a2dissite 000-default
15 ADD vhost.conf /etc/apache2/sites-available/hg
16 RUN a2ensite hg
17
18 ADD hgwebconfig /defaulthgwebconfig
19
20 ADD entrypoint.sh /entrypoint.sh
21 ENTRYPOINT ["/entrypoint.sh"]
22
23 CMD ["/usr/sbin/apache2", "-DFOREGROUND"]
@@ -0,0 +1,144 b''
1 ====================
2 Apache Docker Server
3 ====================
4
5 This directory contains code for running a Mercurial hgweb server via
6 mod_wsgi with the Apache HTTP Server inside a Docker container.
7
8 .. important::
9
10 This container is intended for testing purposes only: it is
11 **not** meant to be suitable for production use.
12
13 Building Image
14 ==============
15
16 The first step is to build a Docker image containing Apache and mod_wsgi::
17
18 $ docker build -t hg-apache .
19
20 .. important::
21
22 You should rebuild the image whenever the content of this directory
23 changes. Rebuilding after pulling or when you haven't run the container
24 in a while is typically a good idea.
25
26 Running the Server
27 ==================
28
29 To run the container, you'll execute something like::
30
31 $ docker run --rm -it -v `pwd`/../../..:/var/hg/source -p 8000:80 hg-apache
32
33 If you aren't a Docker expert:
34
35 * ``--rm`` will remove the container when it stops (so it doesn't clutter
36 your system)
37 * ``-i`` will launch the container in interactive mode so stdin is attached
38 * ``-t`` will allocate a pseudo TTY
39 * ``-v src:dst`` will mount the host filesystem at ``src`` into ``dst``
40 in the container. In our example, we assume you are running from this
41 directory and use the source code a few directories up.
42 * ``-p 8000:80`` will publish port ``80`` on the container to port ``8000``
43 on the host, allowing you to access the HTTP server on the host interface.
44 * ``hg-apache`` is the container image to run. This should correspond to what
45 we build with ``docker build``.
46
47 .. important::
48
49 The container **requires** that ``/var/hg/source`` contain the Mercurial
50 source code.
51
52 Upon start, the container will attempt an install of the source in that
53 directory. If the architecture of the host machine doesn't match that of
54 the Docker host (e.g. when running Boot2Docker under OS X), Mercurial's
55 Python C extensions will fail to run. Be sure to ``make clean`` your
56 host's source tree before mounting it in the container to avoid this.
57
58 When starting the container, you should see some start-up actions (including
59 a Mercurial install) and some output saying Apache has started::
60
61 Now if you load ``http://localhost:8000/`` (or whatever interface Docker
62 is using), you should see hgweb running!
63
64 For your convenience, we've created an empty repository available at
65 ``/repo``. Feel free to populate it with ``hg push``.
66
67 Customizing the Server
68 ======================
69
70 By default, the Docker container installs a basic hgweb config and an
71 empty dummy repository. It also uses some reasonable defaults for
72 mod_wsgi.
73
74 Customizing the WSGI Dispatcher And Mercurial Config
75 ----------------------------------------------------
76
77 By default, the Docker environment installs a custom ``hgweb.wsgi``
78 file (based on the example in ``contrib/hgweb.wsgi``). The file
79 is installed into ``/var/hg/htdocs/hgweb.wsgi``.
80
81 A default hgweb configuration file is also installed. The ``hgwebconfig``
82 file from this directory is installed into ``/var/hg/htdocs/config``.
83
84 You have a few options for customizing these files.
85
86 The simplest is to hack up ``hgwebconfig`` and ``entrypoint.sh`` in
87 this directory and to rebuild the Docker image. This has the downside
88 that the Mercurial working copy is modified and you may accidentally
89 commit unwanted changes.
90
91 The next simplest is to copy this directory somewhere, make your changes,
92 then rebuild the image. No working copy changes involved.
93
94 The preferred solution is to mount a host file into the container and
95 overwrite the built-in defaults.
96
97 For example, say we create a custom hgweb config file in ``~/hgweb``. We
98 can start the container like so to install our custom config file::
99
100 $ docker run -v ~/hgweb:/var/hg/htdocs/config ...
101
102 You can do something similar to install a custom WSGI dispatcher::
103
104 $ docker run -v ~/hgweb.wsgi:/var/hg/htdocs/hgweb.wsgi ...
105
106 Managing Repositories
107 ---------------------
108
109 Repositories are served from ``/var/hg/repos`` by default. This directory
110 is configured as a Docker volume. This means you can mount an existing
111 data volume container in the container so repository data is persisted
112 across container invocations. See
113 https://docs.docker.com/userguide/dockervolumes/ for more.
114
115 Alternatively, if you just want to perform lightweight repository
116 manipulation, open a shell in the container::
117
118 $ docker exec -it <container> /bin/bash
119
120 Then run ``hg init``, etc to manipulate the repositories in ``/var/hg/repos``.
121
122 mod_wsgi Configuration Settings
123 -------------------------------
124
125 mod_wsgi settings can be controlled with the following environment
126 variables.
127
128 WSGI_PROCESSES
129 Number of WSGI processes to run.
130 WSGI_THREADS
131 Number of threads to run in each WSGI process
132 WSGI_MAX_REQUESTS
133 Maximum number of requests each WSGI process may serve before it is
134 reaped.
135
136 See https://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIDaemonProcess
137 for more on these settings.
138
139 .. note::
140
141 The default is to use 1 thread per process. The reason is that Mercurial
142 doesn't perform well in multi-threaded mode due to the GIL. Most people
143 run a single thread per process in production for this reason, so that's
144 what we default to.
@@ -0,0 +1,80 b''
1 #!/bin/bash
2
3 # This script gets executed on container start. Its job is to set up
4 # the Mercurial environment and invoke the server.
5
6 # Mercurial can be started in two modes.
7 # If the MERCURIAL_SOURCE environment variable is set and it points to a
8 # Mercurial source directory, we will install Mercurial from that directory.
9 # Otherwise, we download the Mercurial source and install it manually.
10
11 set -e
12
13 SOURCE_DIR=/var/hg/source
14 INSTALL_DIR=/var/hg/install
15 REPOS_DIR=/var/hg/repos
16 HTDOCS_DIR=/var/hg/htdocs
17
18 if [ ! -d ${SOURCE_DIR} ]; then
19 echo "Mercurial source not available at ${SOURCE_DIR}"
20 echo "You need to mount a volume containing the Mercurial source code"
21 echo "when running the container. For example:"
22 echo ""
23 echo " $ docker run -v ~/src/hg:/${SOURCE_DIR} hg-apache"
24 echo ""
25 echo "This container will now stop running."
26 exit 1
27 fi
28
29 echo "Installing Mercurial from ${SOURCE_DIR} into ${INSTALL_DIR}"
30 pushd ${SOURCE_DIR}
31 /usr/bin/python2.7 setup.py install --root=/ --prefix=${INSTALL_DIR} --force
32 popd
33
34 mkdir -p ${HTDOCS_DIR}
35
36 # Provide a default config if the user hasn't supplied one.
37 if [ ! -f ${HTDOCS_DIR}/config ]; then
38 cp /defaulthgwebconfig ${HTDOCS_DIR}/config
39 fi
40
41 if [ ! -f ${HTDOCS_DIR}/hgweb.wsgi ]; then
42 cat >> ${HTDOCS_DIR}/hgweb.wsgi << EOF
43 config = '${HTDOCS_DIR}/config'
44
45 import sys
46 sys.path.insert(0, '${INSTALL_DIR}/lib/python2.7/site-packages')
47
48 from mercurial import demandimport
49 demandimport.enable()
50
51 from mercurial.hgweb import hgweb
52 application = hgweb(config)
53 EOF
54 fi
55
56 mkdir -p ${REPOS_DIR}
57
58 if [ ! -d ${REPOS_DIR}/repo ]; then
59 ${INSTALL_DIR}/bin/hg init ${REPOS_DIR}/repo
60 chown -R www-data:www-data ${REPOS_DIR}/repo
61 fi
62
63 # This is necessary to make debuginstall happy.
64 if [ ! -f ~/.hgrc ]; then
65 cat >> ~/.hgrc << EOF
66 [ui]
67 username = Dummy User <nobody@example.com>
68 EOF
69 fi
70
71 echo "Verifying Mercurial installation looks happy"
72 ${INSTALL_DIR}/bin/hg debuginstall
73
74 . /etc/apache2/envvars
75
76 echo "Starting Apache HTTP Server on port 80"
77 echo "We hope you remembered to publish this port when running the container!"
78 echo "If this is an interactive container, simply CTRL^C to stop."
79
80 exec "$@"
@@ -0,0 +1,6 b''
1 [paths]
2 / = /var/hg/repos/*
3
4 [web]
5 allow_push = *
6 push_ssl = False
@@ -0,0 +1,24 b''
1 # Apache won't be able to resolve its own hostname, so we sneak this
2 # into the global context to silence a confusing-to-user warning on
3 # server start.
4 ServerName hg
5
6 <VirtualHost *:80>
7 DocumentRoot /var/hg/htdocs
8 <Directory />
9 Options FollowSymLinks
10 AllowOverride None
11 </Directory>
12
13 SetEnv HGENCODING UTF-8
14 SetEnv LC_TYPE UTF-8
15
16 WSGIDaemonProcess hg processes=${WSGI_PROCESSES} threads=${WSGI_THREADS} maximum-requests=${WSGI_MAX_REQUESTS} user=www-data group=www-data display-name=hg-wsgi
17 WSGIProcessGroup hg
18
19 WSGIScriptAliasMatch ^(.*) /var/hg/htdocs/hgweb.wsgi$1
20
21 ErrorLog ${APACHE_LOG_DIR}/error.log
22 LogLevel warn
23 CustomLog ${APACHE_LOG_DIR}/access.log combined
24 </VirtualHost>
@@ -0,0 +1,37 b''
1 #!/usr/bin/env python
2 # Dump revlogs as raw data stream
3 # $ find .hg/store/ -name "*.i" | xargs dumprevlog > repo.dump
4
5 from __future__ import absolute_import, print_function
6
7 import sys
8 from mercurial import (
9 node,
10 revlog,
11 )
12 from mercurial.utils import (
13 procutil,
14 )
15
16 for fp in (sys.stdin, sys.stdout, sys.stderr):
17 procutil.setbinary(fp)
18
19 def binopen(path, mode='rb'):
20 if 'b' not in mode:
21 mode = mode + 'b'
22 return open(path, mode)
23
24 for f in sys.argv[1:]:
25 r = revlog.revlog(binopen, f)
26 print("file:", f)
27 for i in r:
28 n = r.node(i)
29 p = r.parents(n)
30 d = r.revision(n)
31 print("node:", node.hex(n))
32 print("linkrev:", r.linkrev(i))
33 print("parents:", node.hex(p[0]), node.hex(p[1]))
34 print("length:", len(d))
35 print("-start-")
36 print(d)
37 print("-end-")
@@ -0,0 +1,58 b''
1 #!/usr/bin/env bash
2 # A simple script for opening merge conflicts in the editor.
3 # Use the following Mercurial settings to enable it.
4 #
5 # [ui]
6 # merge = editmerge
7 #
8 # [merge-tools]
9 # editmerge.args=$output
10 # editmerge.check=changed
11 # editmerge.premerge=keep
12
13 FILE="$1"
14
15 getlines() {
16 grep -n "^<<<<<<" "$FILE" | cut -f1 -d:
17 }
18
19 # editor preference loosely based on https://mercurial-scm.org/wiki/editor
20 # hg showconfig is at the bottom though, since it's slow to run (0.15 seconds)
21 ED="$HGEDITOR"
22 if [ "$ED" = "" ] ; then
23 ED="$VISUAL"
24 fi
25 if [ "$ED" = "" ] ; then
26 ED="$EDITOR"
27 fi
28 if [ "$ED" = "" ] ; then
29 ED="$(hg showconfig ui.editor)"
30 fi
31 if [ "$ED" = "" ] ; then
32 echo "merge failed - unable to find editor"
33 exit 1
34 fi
35
36 if [ "$ED" = "emacs" ] || [ "$ED" = "nano" ] || [ "$ED" = "vim" ] ; then
37 FIRSTLINE="$(getlines | head -n 1)"
38 PREVIOUSLINE=""
39
40 # open the editor to the first conflict until there are no more
41 # or the user stops editing the file
42 while [ ! "$FIRSTLINE" = "" ] && [ ! "$FIRSTLINE" = "$PREVIOUSLINE" ] ; do
43 $ED "+$FIRSTLINE" "$FILE"
44 PREVIOUSLINE="$FIRSTLINE"
45 FIRSTLINE="$(getlines | head -n 1)"
46 done
47 else
48 $ED "$FILE"
49 fi
50
51 # get the line numbers of the remaining conflicts
52 CONFLICTS="$(getlines | sed ':a;N;$!ba;s/\n/, /g')"
53 if [ ! "$CONFLICTS" = "" ] ; then
54 echo "merge failed - resolve the conflicts (line $CONFLICTS) then use 'hg resolve --mark'"
55 exit 1
56 fi
57
58 exit 0
@@ -0,0 +1,2 b''
1 @echo off
2 powershell -NoProfile -ExecutionPolicy unrestricted -Command "& '%~dp0\editmergeps.ps1' %*"
@@ -0,0 +1,78 b''
1 # A simple script for opening merge conflicts in editor
2 # A loose translation of contrib/editmerge to powershell
3 # Please make sure that both editmergeps.bat and editmerge.ps1 are available
4 # via %PATH% and use the following Mercurial settings to enable it
5 #
6 # [ui]
7 # editmergeps
8 # editmergeps.args=$output
9 # editmergeps.check=changed
10 # editmergeps.premerge=keep
11
12 $file=$args[0]
13
14 function Get-Lines
15 {
16 Select-String "^<<<<<<" $file | % {"$($_.LineNumber)"}
17 }
18
19 $ed = $Env:HGEDITOR;
20 if ($ed -eq $nil)
21 {
22 $ed = $Env:VISUAL;
23 }
24 if ($ed -eq $nil)
25 {
26 $ed = $Env:EDITOR;
27 }
28 if ($ed -eq $nil)
29 {
30 $ed = $(hg showconfig ui.editor);
31 }
32 if ($ed -eq $nil)
33 {
34 Write-Error "merge failed - unable to find editor"
35 exit 1
36 }
37
38 if (($ed -eq "vim") -or ($ed -eq "emacs") -or `
39 ($ed -eq "nano") -or ($ed -eq "notepad++"))
40 {
41 $lines = Get-Lines
42 $firstline = if ($lines.Length -gt 0) { $lines[0] } else { $nil }
43 $previousline = $nil;
44
45
46 # open the editor to the first conflict until there are no more
47 # or the user stops editing the file
48 while (($firstline -ne $nil) -and ($firstline -ne $previousline))
49 {
50 if ($ed -eq "notepad++")
51 {
52 $linearg = "-n$firstline"
53 }
54 else
55 {
56 $linearg = "+$firstline"
57 }
58
59 Start-Process -Wait -NoNewWindow $ed $linearg,$file
60 $previousline = $firstline
61 $lines = Get-Lines
62 $firstline = if ($lines.Length -gt 0) { $lines[0] } else { $nil }
63 }
64 }
65 else
66 {
67 & "$ed" $file
68 }
69
70 $conflicts=Get-Lines
71 if ($conflicts.Length -ne 0)
72 {
73 Write-Output "merge failed - resolve the conflicts (line $conflicts) then use 'hg resolve --mark'"
74 exit 1
75 }
76
77 exit 0
78
@@ -0,0 +1,81 b''
1 CC = clang
2 CXX = clang++
3
4 all: bdiff mpatch xdiff
5
6 fuzzutil.o: fuzzutil.cc fuzzutil.h
7 $(CXX) $(CXXFLAGS) -g -O1 -fsanitize=fuzzer-no-link,address \
8 -std=c++17 \
9 -I../../mercurial -c -o fuzzutil.o fuzzutil.cc
10
11 fuzzutil-oss-fuzz.o: fuzzutil.cc fuzzutil.h
12 $(CXX) $(CXXFLAGS) -std=c++17 \
13 -I../../mercurial -c -o fuzzutil-oss-fuzz.o fuzzutil.cc
14
15 bdiff.o: ../../mercurial/bdiff.c
16 $(CC) $(CFLAGS) -fsanitize=fuzzer-no-link,address -c -o bdiff.o \
17 ../../mercurial/bdiff.c
18
19 bdiff: bdiff.cc bdiff.o fuzzutil.o
20 $(CXX) $(CXXFLAGS) -DHG_FUZZER_INCLUDE_MAIN=1 -g -O1 -fsanitize=fuzzer-no-link,address \
21 -std=c++17 \
22 -I../../mercurial bdiff.cc bdiff.o fuzzutil.o -o bdiff
23
24 bdiff-oss-fuzz.o: ../../mercurial/bdiff.c
25 $(CC) $(CFLAGS) -c -o bdiff-oss-fuzz.o ../../mercurial/bdiff.c
26
27 bdiff_fuzzer: bdiff.cc bdiff-oss-fuzz.o fuzzutil-oss-fuzz.o
28 $(CXX) $(CXXFLAGS) -std=c++17 -I../../mercurial bdiff.cc \
29 bdiff-oss-fuzz.o fuzzutil-oss-fuzz.o -lFuzzingEngine -o \
30 $$OUT/bdiff_fuzzer
31
32 mpatch.o: ../../mercurial/mpatch.c
33 $(CC) -g -O1 -fsanitize=fuzzer-no-link,address -c -o mpatch.o \
34 ../../mercurial/mpatch.c
35
36 mpatch: CXXFLAGS += -std=c++17
37 mpatch: mpatch.cc mpatch.o fuzzutil.o
38 $(CXX) $(CXXFLAGS) -DHG_FUZZER_INCLUDE_MAIN=1 -g -O1 -fsanitize=fuzzer-no-link,address \
39 -I../../mercurial mpatch.cc mpatch.o fuzzutil.o -o mpatch
40
41 mpatch-oss-fuzz.o: ../../mercurial/mpatch.c
42 $(CC) $(CFLAGS) -c -o mpatch-oss-fuzz.o ../../mercurial/mpatch.c
43
44 mpatch_fuzzer: mpatch.cc mpatch-oss-fuzz.o fuzzutil-oss-fuzz.o
45 $(CXX) $(CXXFLAGS) -std=c++17 -I../../mercurial mpatch.cc \
46 mpatch-oss-fuzz.o fuzzutil-oss-fuzz.o -lFuzzingEngine -o \
47 $$OUT/mpatch_fuzzer
48
49 mpatch_corpus.zip:
50 python mpatch_corpus.py $$OUT/mpatch_fuzzer_seed_corpus.zip
51
52 x%.o: ../../mercurial/thirdparty/xdiff/x%.c ../../mercurial/thirdparty/xdiff/*.h
53 $(CC) -g -O1 -fsanitize=fuzzer-no-link,address -c \
54 -o $@ \
55 $<
56
57 xdiff: CXXFLAGS += -std=c++17
58 xdiff: xdiff.cc xdiffi.o xprepare.o xutils.o fuzzutil.o
59 $(CXX) $(CXXFLAGS) -DHG_FUZZER_INCLUDE_MAIN=1 -g -O1 -fsanitize=fuzzer-no-link,address \
60 -I../../mercurial xdiff.cc \
61 xdiffi.o xprepare.o xutils.o fuzzutil.o -o xdiff
62
63 fuzz-x%.o: ../../mercurial/thirdparty/xdiff/x%.c ../../mercurial/thirdparty/xdiff/*.h
64 $(CC) $(CFLAGS) -c \
65 -o $@ \
66 $<
67
68 xdiff_fuzzer: xdiff.cc fuzz-xdiffi.o fuzz-xprepare.o fuzz-xutils.o fuzzutil-oss-fuzz.o
69 $(CXX) $(CXXFLAGS) -std=c++17 -I../../mercurial xdiff.cc \
70 fuzz-xdiffi.o fuzz-xprepare.o fuzz-xutils.o fuzzutil-oss-fuzz.o \
71 -lFuzzingEngine -o $$OUT/xdiff_fuzzer
72
73 clean:
74 $(RM) *.o *_fuzzer \
75 bdiff \
76 mpatch \
77 xdiff
78
79 oss-fuzz: bdiff_fuzzer mpatch_fuzzer mpatch_corpus.zip xdiff_fuzzer
80
81 .PHONY: all clean oss-fuzz
@@ -0,0 +1,26 b''
1 How to add fuzzers (partially cribbed from oss-fuzz[0]):
2
3 1) git clone https://github.com/google/oss-fuzz
4 2) cd oss-fuzz
5 3) python infra/helper.py build_image mercurial
6 4) docker run --cap-add=SYS_PTRACE -it -v $HG_REPO_PATH:/hg-new \
7 gcr.io/oss-fuzz/mercurial bash
8 5) cd /src
9 6) rm -r mercurial
10 7) ln -s /hg-new mercurial
11 8) cd mercurial
12 9) compile
13 10) ls $OUT
14
15 Step 9 is literally running the command "compile", which is part of
16 the docker container. Once you have that working, you can build the
17 fuzzers like this (in the oss-fuzz repo):
18
19 python infra/helper.py build_fuzzers --sanitizer address mercurial $HG_REPO_PATH
20
21 (you can also say "memory", "undefined" or "coverage" for
22 sanitizer). Then run the built fuzzers like this:
23
24 python infra/helper.py run_fuzzer mercurial -- $FUZZER
25
26 0: https://github.com/google/oss-fuzz/blob/master/docs/new_project_guide.md
@@ -0,0 +1,44 b''
1 /*
2 * bdiff.cc - fuzzer harness for bdiff.c
3 *
4 * Copyright 2018, Google Inc.
5 *
6 * This software may be used and distributed according to the terms of
7 * the GNU General Public License, incorporated herein by reference.
8 */
9 #include <memory>
10 #include <stdlib.h>
11
12 #include "fuzzutil.h"
13
14 extern "C" {
15 #include "bdiff.h"
16
17 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
18 {
19 auto maybe_inputs = SplitInputs(Data, Size);
20 if (!maybe_inputs) {
21 return 0;
22 }
23 auto inputs = std::move(maybe_inputs.value());
24
25 struct bdiff_line *a, *b;
26 int an = bdiff_splitlines(inputs.left.get(), inputs.left_size, &a);
27 int bn = bdiff_splitlines(inputs.right.get(), inputs.right_size, &b);
28 struct bdiff_hunk l;
29 bdiff_diff(a, an, b, bn, &l);
30 free(a);
31 free(b);
32 bdiff_freehunks(l.next);
33 return 0; // Non-zero return values are reserved for future use.
34 }
35
36 #ifdef HG_FUZZER_INCLUDE_MAIN
37 int main(int argc, char **argv)
38 {
39 const char data[] = "asdf";
40 return LLVMFuzzerTestOneInput((const uint8_t *)data, 4);
41 }
42 #endif
43
44 } // extern "C"
@@ -0,0 +1,27 b''
1 #include "fuzzutil.h"
2
3 #include <cstring>
4 #include <utility>
5
6 contrib::optional<two_inputs> SplitInputs(const uint8_t *Data, size_t Size)
7 {
8 if (!Size) {
9 return contrib::nullopt;
10 }
11 // figure out a random point in [0, Size] to split our input.
12 size_t left_size = (Data[0] / 255.0) * (Size - 1);
13
14 // Copy inputs to new allocations so if bdiff over-reads
15 // AddressSanitizer can detect it.
16 std::unique_ptr<char[]> left(new char[left_size]);
17 std::memcpy(left.get(), Data + 1, left_size);
18 // right starts at the next byte after left ends
19 size_t right_size = Size - (left_size + 1);
20 std::unique_ptr<char[]> right(new char[right_size]);
21 std::memcpy(right.get(), Data + 1 + left_size, right_size);
22 LOG(2) << "inputs are " << left_size << " and " << right_size
23 << " bytes" << std::endl;
24 two_inputs result = {std::move(right), right_size, std::move(left),
25 left_size};
26 return result;
27 }
@@ -0,0 +1,47 b''
1 #ifndef CONTRIB_FUZZ_FUZZUTIL_H
2 #define CONTRIB_FUZZ_FUZZUTIL_H
3 #include <iostream>
4 #include <memory>
5 #include <stdint.h>
6
7 /* Try and use std::optional, but failing that assume we'll have a
8 * workable https://abseil.io/ install on the include path to get
9 * their backport of std::optional. */
10 #ifdef __has_include
11 #if __has_include(<optional>) && __cplusplus >= 201703L
12 #include <optional>
13 #define CONTRIB_FUZZ_HAVE_STD_OPTIONAL
14 #endif
15 #endif
16 #ifdef CONTRIB_FUZZ_HAVE_STD_OPTIONAL
17 namespace contrib
18 {
19 using std::nullopt;
20 using std::optional;
21 } /* namespace contrib */
22 #else
23 #include "third_party/absl/types/optional.h"
24 namespace contrib
25 {
26 using absl::nullopt;
27 using absl::optional;
28 } /* namespace contrib */
29 #endif
30
31 /* set DEBUG to 1 for a few debugging prints, or 2 for a lot */
32 #define DEBUG 0
33 #define LOG(level) \
34 if (level <= DEBUG) \
35 std::cout
36
37 struct two_inputs {
38 std::unique_ptr<char[]> right;
39 size_t right_size;
40 std::unique_ptr<char[]> left;
41 size_t left_size;
42 };
43
44 /* Split a non-zero-length input into two inputs. */
45 contrib::optional<two_inputs> SplitInputs(const uint8_t *Data, size_t Size);
46
47 #endif /* CONTRIB_FUZZ_FUZZUTIL_H */
@@ -0,0 +1,122 b''
1 /*
2 * mpatch.cc - fuzzer harness for mpatch.c
3 *
4 * Copyright 2018, Google Inc.
5 *
6 * This software may be used and distributed according to the terms of
7 * the GNU General Public License, incorporated herein by reference.
8 */
9 #include <iostream>
10 #include <memory>
11 #include <stdint.h>
12 #include <stdlib.h>
13 #include <vector>
14
15 #include "fuzzutil.h"
16
17 // To avoid having too many OOMs from the fuzzer infrastructure, we'll
18 // skip patch application if the resulting fulltext would be bigger
19 // than 10MiB.
20 #define MAX_OUTPUT_SIZE 10485760
21
22 extern "C" {
23 #include "bitmanipulation.h"
24 #include "mpatch.h"
25
26 struct mpatchbin {
27 std::unique_ptr<char[]> data;
28 size_t len;
29 };
30
31 static mpatch_flist *getitem(void *vbins, ssize_t pos)
32 {
33 std::vector<mpatchbin> *bins = (std::vector<mpatchbin> *)vbins;
34 const mpatchbin &bin = bins->at(pos + 1);
35 struct mpatch_flist *res;
36 LOG(2) << "mpatch_decode " << bin.len << std::endl;
37 if (mpatch_decode(bin.data.get(), bin.len, &res) < 0)
38 return NULL;
39 return res;
40 }
41
42 // input format:
43 // u8 number of inputs
44 // one u16 for each input, its length
45 // the inputs
46 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
47 {
48 if (!Size) {
49 return 0;
50 }
51 // First byte of data is how many texts we expect, first text
52 // being the base the rest being the deltas.
53 ssize_t numtexts = Data[0];
54 if (numtexts < 2) {
55 // No point if we don't have at least a base text and a delta...
56 return 0;
57 }
58 // Each text will be described by a byte for how long it
59 // should be, so give up if we don't have enough.
60 if ((Size - 1) < (numtexts * 2)) {
61 return 0;
62 }
63 size_t consumed = 1 + (numtexts * 2);
64 LOG(2) << "input contains " << Size << std::endl;
65 LOG(2) << numtexts << " texts, consuming " << consumed << std::endl;
66 std::vector<mpatchbin> bins;
67 bins.reserve(numtexts);
68 for (int i = 0; i < numtexts; ++i) {
69 mpatchbin bin;
70 size_t nthsize = getbeuint16((char *)Data + 1 + (2 * i));
71 LOG(2) << "text " << i << " is " << nthsize << std::endl;
72 char *start = (char *)Data + consumed;
73 consumed += nthsize;
74 if (consumed > Size) {
75 LOG(2) << "ran out of data, consumed " << consumed
76 << " of " << Size << std::endl;
77 return 0;
78 }
79 bin.len = nthsize;
80 bin.data.reset(new char[nthsize]);
81 memcpy(bin.data.get(), start, nthsize);
82 bins.push_back(std::move(bin));
83 }
84 LOG(2) << "mpatch_flist" << std::endl;
85 struct mpatch_flist *patch =
86 mpatch_fold(&bins, getitem, 0, numtexts - 1);
87 if (!patch) {
88 return 0;
89 }
90 LOG(2) << "mpatch_calcsize" << std::endl;
91 ssize_t outlen = mpatch_calcsize(bins[0].len, patch);
92 LOG(2) << "outlen " << outlen << std::endl;
93 if (outlen < 0 || outlen > MAX_OUTPUT_SIZE) {
94 goto cleanup;
95 }
96 {
97 char *dest = (char *)malloc(outlen);
98 LOG(2) << "expecting " << outlen << " total bytes at "
99 << (void *)dest << std::endl;
100 mpatch_apply(dest, bins[0].data.get(), bins[0].len, patch);
101 free(dest);
102 LOG(1) << "applied a complete patch" << std::endl;
103 }
104 cleanup:
105 mpatch_lfree(patch);
106 return 0;
107 }
108
109 #ifdef HG_FUZZER_INCLUDE_MAIN
110 int main(int argc, char **argv)
111 {
112 // One text, one patch.
113 const char data[] = "\x02\x00\0x1\x00\x0d"
114 // base text
115 "a"
116 // binary delta that will append a single b
117 "\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01b";
118 return LLVMFuzzerTestOneInput((const uint8_t *)data, 19);
119 }
120 #endif
121
122 } // extern "C"
@@ -0,0 +1,345 b''
1 from __future__ import absolute_import, print_function
2
3 import argparse
4 import struct
5 import zipfile
6
7 from mercurial import (
8 hg,
9 ui as uimod,
10 )
11
12 ap = argparse.ArgumentParser()
13 ap.add_argument("out", metavar="some.zip", type=str, nargs=1)
14 args = ap.parse_args()
15
16 class deltafrag(object):
17 def __init__(self, start, end, data):
18 self.start = start
19 self.end = end
20 self.data = data
21
22 def __str__(self):
23 return struct.pack(
24 ">lll", self.start, self.end, len(self.data)) + self.data
25
26 class delta(object):
27 def __init__(self, frags):
28 self.frags = frags
29
30 def __str__(self):
31 return ''.join(str(f) for f in self.frags)
32
33 class corpus(object):
34
35 def __init__(self, base, deltas):
36 self.base = base
37 self.deltas = deltas
38
39 def __str__(self):
40 deltas = [str(d) for d in self.deltas]
41 parts = (
42 [
43 struct.pack(">B", len(deltas) + 1),
44 struct.pack(">H", len(self.base)),
45 ]
46 + [struct.pack(">H", len(d)) for d in deltas]
47 + [self.base]
48 + deltas
49 )
50 return "".join(parts)
51
52 with zipfile.ZipFile(args.out[0], "w", zipfile.ZIP_STORED) as zf:
53 # Manually constructed entries
54 zf.writestr(
55 "one_delta_applies",
56 str(corpus('a', [delta([deltafrag(0, 1, 'b')])]))
57 )
58 zf.writestr(
59 "one_delta_starts_late",
60 str(corpus('a', [delta([deltafrag(3, 1, 'b')])]))
61 )
62 zf.writestr(
63 "one_delta_ends_late",
64 str(corpus('a', [delta([deltafrag(0, 20, 'b')])]))
65 )
66
67 try:
68 # Generated from repo data
69 r = hg.repository(uimod.ui(), '../..')
70 fl = r.file('mercurial/manifest.py')
71 rl = getattr(fl, '_revlog', fl)
72 bins = rl._chunks(rl._deltachain(10)[0])
73 zf.writestr('manifest_py_rev_10',
74 str(corpus(bins[0], bins[1:])))
75 except: # skip this, so no re-raises
76 print('skipping seed file from repo data')
77 # Automatically discovered by running the fuzzer
78 zf.writestr(
79 "mpatch_decode_old_overread", "\x02\x00\x00\x00\x02\x00\x00\x00"
80 )
81 # https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=8876
82 zf.writestr(
83 "mpatch_ossfuzz_getbe32_ubsan",
84 "\x02\x00\x00\x00\x0c \xff\xff\xff\xff ")
85 zf.writestr(
86 "mpatch_apply_over_memcpy",
87 '\x13\x01\x00\x05\xd0\x00\x00\x00\x00\x00\x00\x00\x00\n \x00\x00\x00'
88 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
89 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00'
90 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
91 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
92 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
93 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
94 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
95 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
96 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
97 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
98 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
99 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
100 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
101 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
102 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
103 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
104 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
105 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
106 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
107 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
108 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
109 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
110 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
111 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
112 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
113 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
114 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
115 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
116 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
117 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x00\x00\x00\x00'
118 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
119 '\x00\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00\x00\x00\x00\x00\x00'
120 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
121 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
122 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
123 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
124 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
125 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
126 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
127 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
128 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
129 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
130 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
131 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
132 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
133 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
134 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
135 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
136 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
137 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
138 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
139 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
140 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
141 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
142 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
143 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
144 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
145 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
146 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
147 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
148 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
149 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
150 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
151 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
152 '\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00A\x00\x00\x00\x00'
153 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
154 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
155 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
156 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
157 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
158 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
159 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
160 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
161 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
162 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
163 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
164 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
165 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
166 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
167 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
168 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
169 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
170 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
171 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
172 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
173 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
174 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
175 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
176 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
177 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94\x18'
178 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
179 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
180 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
181 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
182 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
183 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
184 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
185 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
186 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
187 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
188 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
189 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
190 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
191 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
192 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
193 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
194 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
195 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
196 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
197 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
198 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
199 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
200 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
201 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
202 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
203 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
204 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
205 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
206 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
207 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
208 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
209 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
210 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
211 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
212 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
213 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
214 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
215 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
216 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
217 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
218 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
219 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
220 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
221 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
222 '\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
223 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
224 '\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfa\x00\x00\x00\x00\x00\x00\x00'
225 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
226 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
227 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
228 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
229 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
230 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
231 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
232 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
233 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
234 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
235 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
236 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
237 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
238 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
239 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
240 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
241 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
242 '\x00\x00\x94\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
243 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
244 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
245 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
246 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
247 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
248 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
249 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
250 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
251 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
252 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
253 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
254 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
255 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
256 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
257 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
258 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
259 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
260 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
261 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
262 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
263 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
264 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
265 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
266 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
267 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
268 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
269 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
270 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
271 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
272 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
273 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
274 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
275 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
276 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
277 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
278 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
279 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
280 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
281 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
282 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
283 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
284 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
285 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
286 '\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
287 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
288 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfa\x00\x00\x00'
289 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
290 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
291 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
292 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
293 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
294 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
295 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
296 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
297 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
298 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
299 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
300 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
301 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
302 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
303 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
304 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
305 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
306 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
307 '\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00'
308 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
309 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
310 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
311 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
312 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
313 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
314 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
315 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
316 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
317 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
318 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
319 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
320 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
321 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
322 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00'
323 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
324 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
325 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
326 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
327 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00'
328 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
329 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
330 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
331 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
332 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
333 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
334 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
335 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
336 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
337 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
338 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
339 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
340 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
341 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
342 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
343 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00se\x00\x00'
344 '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
345 '\x00\x00\x00\x00')
@@ -0,0 +1,58 b''
1 /*
2 * xdiff.cc - fuzzer harness for thirdparty/xdiff
3 *
4 * Copyright 2018, Google Inc.
5 *
6 * This software may be used and distributed according to the terms of
7 * the GNU General Public License, incorporated herein by reference.
8 */
9 #include "thirdparty/xdiff/xdiff.h"
10 #include <inttypes.h>
11 #include <stdlib.h>
12
13 #include "fuzzutil.h"
14
15 extern "C" {
16
17 int hunk_consumer(long a1, long a2, long b1, long b2, void *priv)
18 {
19 // TODO: probably also test returning -1 from this when things break?
20 return 0;
21 }
22
23 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
24 {
25 auto maybe_inputs = SplitInputs(Data, Size);
26 if (!maybe_inputs) {
27 return 0;
28 }
29 auto inputs = std::move(maybe_inputs.value());
30 mmfile_t a, b;
31
32 a.ptr = inputs.left.get();
33 a.size = inputs.left_size;
34 b.ptr = inputs.right.get();
35 b.size = inputs.right_size;
36 xpparam_t xpp = {
37 XDF_INDENT_HEURISTIC, /* flags */
38 };
39 xdemitconf_t xecfg = {
40 XDL_EMIT_BDIFFHUNK, /* flags */
41 hunk_consumer, /* hunk_consume_func */
42 };
43 xdemitcb_t ecb = {
44 NULL, /* priv */
45 };
46 xdl_diff(&a, &b, &xpp, &xecfg, &ecb);
47 return 0; // Non-zero return values are reserved for future use.
48 }
49
50 #ifdef HG_FUZZER_INCLUDE_MAIN
51 int main(int argc, char **argv)
52 {
53 const char data[] = "asdf";
54 return LLVMFuzzerTestOneInput((const uint8_t *)data, 4);
55 }
56 #endif
57
58 } // extern "C"
@@ -0,0 +1,130 b''
1 #!/usr/bin/env python2
2 from __future__ import absolute_import, print_function
3
4 import argparse
5 import json
6 import os
7 import subprocess
8 import sys
9
10 # Always load hg libraries from the hg we can find on $PATH.
11 hglib = json.loads(subprocess.check_output(
12 ['hg', 'debuginstall', '-Tjson']))[0]['hgmodules']
13 sys.path.insert(0, os.path.dirname(hglib))
14
15 from mercurial import util
16
17 ap = argparse.ArgumentParser()
18 ap.add_argument('--paranoid',
19 action='store_true',
20 help=("Be paranoid about how version numbers compare and "
21 "produce something that's more likely to sort "
22 "reasonably."))
23 ap.add_argument('--selftest', action='store_true', help='Run self-tests.')
24 ap.add_argument('versionfile', help='Path to a valid mercurial __version__.py')
25
26 def paranoidver(ver):
27 """Given an hg version produce something that distutils can sort.
28
29 Some Mac package management systems use distutils code in order to
30 figure out upgrades, which makes life difficult. The test case is
31 a reduced version of code in the Munki tool used by some large
32 organizations to centrally manage OS X packages, which is what
33 inspired this kludge.
34
35 >>> paranoidver('3.4')
36 '3.4.0'
37 >>> paranoidver('3.4.2')
38 '3.4.2'
39 >>> paranoidver('3.0-rc+10')
40 '2.9.9999-rc+10'
41 >>> paranoidver('4.2+483-5d44d7d4076e')
42 '4.2.0+483-5d44d7d4076e'
43 >>> paranoidver('4.2.1+598-48d1e1214d8c')
44 '4.2.1+598-48d1e1214d8c'
45 >>> paranoidver('4.3-rc')
46 '4.2.9999-rc'
47 >>> paranoidver('4.3')
48 '4.3.0'
49 >>> from distutils import version
50 >>> class LossyPaddedVersion(version.LooseVersion):
51 ... '''Subclass version.LooseVersion to compare things like
52 ... "10.6" and "10.6.0" as equal'''
53 ... def __init__(self, s):
54 ... self.parse(s)
55 ...
56 ... def _pad(self, version_list, max_length):
57 ... 'Pad a version list by adding extra 0 components to the end'
58 ... # copy the version_list so we don't modify it
59 ... cmp_list = list(version_list)
60 ... while len(cmp_list) < max_length:
61 ... cmp_list.append(0)
62 ... return cmp_list
63 ...
64 ... def __cmp__(self, other):
65 ... if isinstance(other, str):
66 ... other = MunkiLooseVersion(other)
67 ... max_length = max(len(self.version), len(other.version))
68 ... self_cmp_version = self._pad(self.version, max_length)
69 ... other_cmp_version = self._pad(other.version, max_length)
70 ... return cmp(self_cmp_version, other_cmp_version)
71 >>> def testver(older, newer):
72 ... o = LossyPaddedVersion(paranoidver(older))
73 ... n = LossyPaddedVersion(paranoidver(newer))
74 ... return o < n
75 >>> testver('3.4', '3.5')
76 True
77 >>> testver('3.4.0', '3.5-rc')
78 True
79 >>> testver('3.4-rc', '3.5')
80 True
81 >>> testver('3.4-rc+10-deadbeef', '3.5')
82 True
83 >>> testver('3.4.2', '3.5-rc')
84 True
85 >>> testver('3.4.2', '3.5-rc+10-deadbeef')
86 True
87 >>> testver('4.2+483-5d44d7d4076e', '4.2.1+598-48d1e1214d8c')
88 True
89 >>> testver('4.3-rc', '4.3')
90 True
91 >>> testver('4.3', '4.3-rc')
92 False
93 """
94 major, minor, micro, extra = util.versiontuple(ver, n=4)
95 if micro is None:
96 micro = 0
97 if extra:
98 if extra.startswith('rc'):
99 if minor == 0:
100 major -= 1
101 minor = 9
102 else:
103 minor -= 1
104 micro = 9999
105 extra = '-' + extra
106 else:
107 extra = '+' + extra
108 else:
109 extra = ''
110 return '%d.%d.%d%s' % (major, minor, micro, extra)
111
112 def main(argv):
113 opts = ap.parse_args(argv[1:])
114 if opts.selftest:
115 import doctest
116 doctest.testmod()
117 return
118 with open(opts.versionfile) as f:
119 for l in f:
120 if l.startswith('version = b'):
121 # version number is entire line minus the quotes
122 ver = l[len('version = b') + 1:-2]
123 break
124 if opts.paranoid:
125 print(paranoidver(ver))
126 else:
127 print(ver)
128
129 if __name__ == '__main__':
130 main(sys.argv)
@@ -0,0 +1,97 b''
1 #!/usr/bin/env python
2 #
3 # Copyright 2005-2007 by Intevation GmbH <intevation@intevation.de>
4 #
5 # Author(s):
6 # Thomas Arendsen Hein <thomas@intevation.de>
7 #
8 # This software may be used and distributed according to the terms of the
9 # GNU General Public License version 2 or any later version.
10
11 """
12 hg-ssh - a wrapper for ssh access to a limited set of mercurial repos
13
14 To be used in ~/.ssh/authorized_keys with the "command" option, see sshd(8):
15 command="hg-ssh path/to/repo1 /path/to/repo2 ~/repo3 ~user/repo4" ssh-dss ...
16 (probably together with these other useful options:
17 no-port-forwarding,no-X11-forwarding,no-agent-forwarding)
18
19 This allows pull/push over ssh from/to the repositories given as arguments.
20
21 If all your repositories are subdirectories of a common directory, you can
22 allow shorter paths with:
23 command="cd path/to/my/repositories && hg-ssh repo1 subdir/repo2"
24
25 You can use pattern matching of your normal shell, e.g.:
26 command="cd repos && hg-ssh user/thomas/* projects/{mercurial,foo}"
27
28 You can also add a --read-only flag to allow read-only access to a key, e.g.:
29 command="hg-ssh --read-only repos/*"
30 """
31 from __future__ import absolute_import
32
33 import os
34 import shlex
35 import sys
36
37 # enable importing on demand to reduce startup time
38 import hgdemandimport ; hgdemandimport.enable()
39
40 from mercurial import (
41 dispatch,
42 pycompat,
43 ui as uimod,
44 )
45
46 def main():
47 # Prevent insertion/deletion of CRs
48 dispatch.initstdio()
49
50 cwd = os.getcwd()
51 readonly = False
52 args = sys.argv[1:]
53 while len(args):
54 if args[0] == '--read-only':
55 readonly = True
56 args.pop(0)
57 else:
58 break
59 allowed_paths = [os.path.normpath(os.path.join(cwd,
60 os.path.expanduser(path)))
61 for path in args]
62 orig_cmd = os.getenv('SSH_ORIGINAL_COMMAND', '?')
63 try:
64 cmdargv = shlex.split(orig_cmd)
65 except ValueError as e:
66 sys.stderr.write('Illegal command "%s": %s\n' % (orig_cmd, e))
67 sys.exit(255)
68
69 if cmdargv[:2] == ['hg', '-R'] and cmdargv[3:] == ['serve', '--stdio']:
70 path = cmdargv[2]
71 repo = os.path.normpath(os.path.join(cwd, os.path.expanduser(path)))
72 if repo in allowed_paths:
73 cmd = [b'-R', pycompat.fsencode(repo), b'serve', b'--stdio']
74 req = dispatch.request(cmd)
75 if readonly:
76 if not req.ui:
77 req.ui = uimod.ui.load()
78 req.ui.setconfig(b'hooks', b'pretxnopen.hg-ssh',
79 b'python:__main__.rejectpush', b'hg-ssh')
80 req.ui.setconfig(b'hooks', b'prepushkey.hg-ssh',
81 b'python:__main__.rejectpush', b'hg-ssh')
82 dispatch.dispatch(req)
83 else:
84 sys.stderr.write('Illegal repository "%s"\n' % repo)
85 sys.exit(255)
86 else:
87 sys.stderr.write('Illegal command "%s"\n' % orig_cmd)
88 sys.exit(255)
89
90 def rejectpush(ui, **kwargs):
91 ui.warn((b"Permission denied\n"))
92 # mercurial hooks use unix process conventions for hook return values
93 # so a truthy return means failure
94 return True
95
96 if __name__ == '__main__':
97 main()
@@ -0,0 +1,56 b''
1 ;; hg-test-mode.el - Major mode for editing Mercurial tests
2 ;;
3 ;; Copyright 2014 Matt Mackall <mpm@selenic.com>
4 ;; "I have no idea what I'm doing"
5 ;;
6 ;; This software may be used and distributed according to the terms of the
7 ;; GNU General Public License version 2 or any later version.
8 ;;
9 ;; To enable, add something like the following to your .emacs:
10 ;;
11 ;; (if (file-exists-p "~/hg/contrib/hg-test-mode.el")
12 ;; (load "~/hg/contrib/hg-test-mode.el"))
13
14 (defvar hg-test-mode-hook nil)
15
16 (defvar hg-test-mode-map
17 (let ((map (make-keymap)))
18 (define-key map "\C-j" 'newline-and-indent)
19 map)
20 "Keymap for hg test major mode")
21
22 (add-to-list 'auto-mode-alist '("\\.t\\'" . hg-test-mode))
23
24 (defconst hg-test-font-lock-keywords-1
25 (list
26 '("^ \\(\\$\\|>>>\\) " 1 font-lock-builtin-face)
27 '("^ \\(>\\|\\.\\.\\.\\) " 1 font-lock-constant-face)
28 '("^ \\([[][0-9]+[]]\\)$" 1 font-lock-warning-face)
29 '("^ \\(.*?\\)\\(\\( [(][-a-z]+[)]\\)*\\)$" 1 font-lock-string-face)
30 '("\\$?\\(HG\\|TEST\\)\\w+=?" . font-lock-variable-name-face)
31 '("^ \\(.*?\\)\\(\\( [(][-a-z]+[)]\\)+\\)$" 2 font-lock-type-face)
32 '("^#.*" . font-lock-preprocessor-face)
33 '("^\\([^ ].*\\)$" 1 font-lock-comment-face)
34 )
35 "Minimal highlighting expressions for hg-test mode")
36
37 (defvar hg-test-font-lock-keywords hg-test-font-lock-keywords-1
38 "Default highlighting expressions for hg-test mode")
39
40 (defvar hg-test-mode-syntax-table
41 (let ((st (make-syntax-table)))
42 (modify-syntax-entry ?\" "w" st) ;; disable standard quoting
43 st)
44 "Syntax table for hg-test mode")
45
46 (defun hg-test-mode ()
47 (interactive)
48 (kill-all-local-variables)
49 (use-local-map hg-test-mode-map)
50 (set-syntax-table hg-test-mode-syntax-table)
51 (set (make-local-variable 'font-lock-defaults) '(hg-test-font-lock-keywords))
52 (setq major-mode 'hg-test-mode)
53 (setq mode-name "hg-test")
54 (run-hooks 'hg-test-mode-hook))
55
56 (provide 'hg-test-mode)
@@ -0,0 +1,123 b''
1 # A minimal client for Mercurial's command server
2
3 from __future__ import absolute_import, print_function
4 import os
5 import signal
6 import socket
7 import struct
8 import subprocess
9 import sys
10 import time
11
12 try:
13 import cStringIO as io
14 stringio = io.StringIO
15 except ImportError:
16 import io
17 stringio = io.StringIO
18
19 def connectpipe(path=None):
20 cmdline = ['hg', 'serve', '--cmdserver', 'pipe']
21 if path:
22 cmdline += ['-R', path]
23
24 server = subprocess.Popen(cmdline, stdin=subprocess.PIPE,
25 stdout=subprocess.PIPE)
26
27 return server
28
29 class unixconnection(object):
30 def __init__(self, sockpath):
31 self.sock = sock = socket.socket(socket.AF_UNIX)
32 sock.connect(sockpath)
33 self.stdin = sock.makefile('wb')
34 self.stdout = sock.makefile('rb')
35
36 def wait(self):
37 self.stdin.close()
38 self.stdout.close()
39 self.sock.close()
40
41 class unixserver(object):
42 def __init__(self, sockpath, logpath=None, repopath=None):
43 self.sockpath = sockpath
44 cmdline = ['hg', 'serve', '--cmdserver', 'unix', '-a', sockpath]
45 if repopath:
46 cmdline += ['-R', repopath]
47 if logpath:
48 stdout = open(logpath, 'a')
49 stderr = subprocess.STDOUT
50 else:
51 stdout = stderr = None
52 self.server = subprocess.Popen(cmdline, stdout=stdout, stderr=stderr)
53 # wait for listen()
54 while self.server.poll() is None:
55 if os.path.exists(sockpath):
56 break
57 time.sleep(0.1)
58
59 def connect(self):
60 return unixconnection(self.sockpath)
61
62 def shutdown(self):
63 os.kill(self.server.pid, signal.SIGTERM)
64 self.server.wait()
65
66 def writeblock(server, data):
67 server.stdin.write(struct.pack('>I', len(data)))
68 server.stdin.write(data)
69 server.stdin.flush()
70
71 def readchannel(server):
72 data = server.stdout.read(5)
73 if not data:
74 raise EOFError
75 channel, length = struct.unpack('>cI', data)
76 if channel in 'IL':
77 return channel, length
78 else:
79 return channel, server.stdout.read(length)
80
81 def sep(text):
82 return text.replace('\\', '/')
83
84 def runcommand(server, args, output=sys.stdout, error=sys.stderr, input=None,
85 outfilter=lambda x: x):
86 print('*** runcommand', ' '.join(args))
87 sys.stdout.flush()
88 server.stdin.write('runcommand\n')
89 writeblock(server, '\0'.join(args))
90
91 if not input:
92 input = stringio()
93
94 while True:
95 ch, data = readchannel(server)
96 if ch == 'o':
97 output.write(outfilter(data))
98 output.flush()
99 elif ch == 'e':
100 error.write(data)
101 error.flush()
102 elif ch == 'I':
103 writeblock(server, input.read(data))
104 elif ch == 'L':
105 writeblock(server, input.readline(data))
106 elif ch == 'r':
107 ret, = struct.unpack('>i', data)
108 if ret != 0:
109 print(' [%d]' % ret)
110 return ret
111 else:
112 print("unexpected channel %c: %r" % (ch, data))
113 if ch.isupper():
114 return
115
116 def check(func, connect=connectpipe):
117 sys.stdout.flush()
118 server = connect()
119 try:
120 return func(server)
121 finally:
122 server.stdin.close()
123 server.wait()
This diff has been collapsed as it changes many lines, (4155 lines changed) Show them Hide them
@@ -0,0 +1,4155 b''
1 #!/usr/bin/env wish
2
3 # Copyright (C) 2005 Paul Mackerras. All rights reserved.
4 # This program is free software; it may be used, copied, modified
5 # and distributed under the terms of the GNU General Public Licence,
6 # either version 2, or (at your option) any later version.
7 #
8 # See hgk.py for extension usage and configuration.
9
10
11 # Modified version of Tip 171:
12 # http://www.tcl.tk/cgi-bin/tct/tip/171.html
13 #
14 # The in_mousewheel global was added to fix strange reentrancy issues.
15 # The whole snipped is activated only under windows, mouse wheel
16 # bindings working already under MacOSX and Linux.
17
18 if {[catch {package require Ttk}]} {
19 # use a shim
20 namespace eval ttk {
21 proc style args {}
22
23 proc entry args {
24 eval [linsert $args 0 ::entry] -relief flat
25 }
26 }
27
28 interp alias {} ttk::button {} button
29 interp alias {} ttk::frame {} frame
30 interp alias {} ttk::label {} label
31 interp alias {} ttk::scrollbar {} scrollbar
32 interp alias {} ttk::optionMenu {} tk_optionMenu
33
34 proc updatepalette {} {}
35 } else {
36 proc ::ttk::optionMenu {w varName firstValue args} {
37 upvar #0 $varName var
38
39 if {![info exists var]} {
40 set var $firstValue
41 }
42 ttk::menubutton $w -textvariable $varName -menu $w.menu \
43 -direction flush
44 menu $w.menu -tearoff 0
45 $w.menu add radiobutton -label $firstValue -variable $varName
46 foreach i $args {
47 $w.menu add radiobutton -label $i -variable $varName
48 }
49 return $w.menu
50 }
51 proc updatepalette {} {
52 catch {
53 tk_setPalette background [ttk::style lookup client -background]
54 }
55 }
56 }
57
58 if {[tk windowingsystem] eq "win32"} {
59
60 ttk::style theme use xpnative
61
62 set mw_classes [list Text Listbox Table TreeCtrl]
63 foreach class $mw_classes { bind $class <MouseWheel> {} }
64
65 set in_mousewheel 0
66
67 proc ::tk::MouseWheel {wFired X Y D {shifted 0}} {
68 global in_mousewheel
69 if { $in_mousewheel != 0 } { return }
70 # Set event to check based on call
71 set evt "<[expr {$shifted?{Shift-}:{}}]MouseWheel>"
72 # do not double-fire in case the class already has a binding
73 if {[bind [winfo class $wFired] $evt] ne ""} { return }
74 # obtain the window the mouse is over
75 set w [winfo containing $X $Y]
76 # if we are outside the app, try and scroll the focus widget
77 if {![winfo exists $w]} { catch {set w [focus]} }
78 if {[winfo exists $w]} {
79
80 if {[bind $w $evt] ne ""} {
81 # Awkward ... this widget has a MouseWheel binding, but to
82 # trigger successfully in it, we must give it focus.
83 catch {focus} old
84 if {$w ne $old} { focus $w }
85 set in_mousewheel 1
86 event generate $w $evt -rootx $X -rooty $Y -delta $D
87 set in_mousewheel 0
88 if {$w ne $old} { focus $old }
89 return
90 }
91
92 # aqua and x11/win32 have different delta handling
93 if {[tk windowingsystem] ne "aqua"} {
94 set delta [expr {- ($D / 30)}]
95 } else {
96 set delta [expr {- ($D)}]
97 }
98 # scrollbars have different call conventions
99 if {[string match "*Scrollbar" [winfo class $w]]} {
100 catch {tk::ScrollByUnits $w \
101 [string index [$w cget -orient] 0] $delta}
102 } else {
103 set cmd [list $w [expr {$shifted ? "xview" : "yview"}] \
104 scroll $delta units]
105 # Walking up to find the proper widget (handles cases like
106 # embedded widgets in a canvas)
107 while {[catch $cmd] && [winfo toplevel $w] ne $w} {
108 set w [winfo parent $w]
109 }
110 }
111 }
112 }
113
114 bind all <MouseWheel> [list ::tk::MouseWheel %W %X %Y %D 0]
115
116 # end of win32 section
117 } else {
118
119 if {[catch {
120 set theme [ttk::style theme use]
121 }]} {
122 set theme $::ttk::currentTheme
123 }
124 if {$theme eq "default"} {
125 ttk::style theme use clam
126 }
127
128 }
129
130 updatepalette
131
132 # Unify right mouse button handling.
133 # See "mouse buttons on macintosh" thread on comp.lang.tcl
134 if {[tk windowingsystem] eq "aqua"} {
135 event add <<B3>> <Control-ButtonPress-1>
136 event add <<B3>> <Button-2>
137 } else {
138 event add <<B3>> <Button-3>
139 }
140
141 proc gitdir {} {
142 global env
143 if {[info exists env(GIT_DIR)]} {
144 return $env(GIT_DIR)
145 } else {
146 return ".hg"
147 }
148 }
149
150 proc popupify {w} {
151 wm resizable $w 0 0
152 wm withdraw $w
153 update
154 set x [expr {([winfo screenwidth .]-[winfo reqwidth $w])/2}]
155 set y [expr {([winfo screenheight .]-[winfo reqheight $w])/2}]
156 wm geometry $w +$x+$y
157 wm transient $w .
158 wm deiconify $w
159 wm resizable $w 1 1
160 }
161
162 proc getcommits {rargs} {
163 global commits commfd phase canv mainfont env
164 global startmsecs nextupdate ncmupdate
165 global ctext maincursor textcursor leftover
166
167 # check that we can find a .git directory somewhere...
168 set gitdir [gitdir]
169 if {![file isdirectory $gitdir]} {
170 error_popup "Cannot find the git directory \"$gitdir\"."
171 exit 1
172 }
173 set commits {}
174 set phase getcommits
175 set startmsecs [clock clicks -milliseconds]
176 set nextupdate [expr $startmsecs + 100]
177 set ncmupdate 1
178 set limit 0
179 set revargs {}
180 set showhidden no
181 for {set i 0} {$i < [llength $rargs]} {incr i} {
182 set opt [lindex $rargs $i]
183 switch -- $opt --limit {
184 incr i
185 set limit [lindex $rargs $i]
186 } --hidden {
187 set showhidden yes
188 } default {
189 lappend revargs $opt
190 }
191 }
192 if [catch {
193 set parse_args [concat tip $revargs]
194 set parse_temp [eval exec {$env(HG)} --config ui.report_untrusted=false log --template '{node}\n' $parse_args]
195 regsub -all "\r\n" $parse_temp "\n" parse_temp
196 set parsed_args [split $parse_temp "\n"]
197 } err] {
198 # if git-rev-parse failed for some reason...
199 if {$rargs == {}} {
200 set revargs HEAD
201 }
202 set parsed_args $revargs
203 }
204 if {$limit > 0} {
205 set parsed_args [concat -n $limit $parsed_args]
206 }
207 if {$showhidden} {
208 append parsed_args --hidden
209 }
210 if [catch {
211 set commfd [open "|{$env(HG)} --config ui.report_untrusted=false debug-rev-list --header --topo-order --parents $parsed_args" r]
212 } err] {
213 puts stderr "Error executing hg debug-rev-list: $err"
214 exit 1
215 }
216 set leftover {}
217 fconfigure $commfd -blocking 0 -translation lf -eofchar {}
218 fileevent $commfd readable [list getcommitlines $commfd]
219 $canv delete all
220 $canv create text 3 3 -anchor nw -text "Reading commits..." \
221 -font $mainfont -tags textitems
222 . config -cursor watch
223 settextcursor watch
224 }
225
226 proc getcommitlines {commfd} {
227 global commits parents cdate children
228 global commitlisted phase commitinfo nextupdate
229 global stopped redisplaying leftover
230
231 set stuff [read $commfd]
232 if {$stuff == {}} {
233 if {![eof $commfd]} return
234 # set it blocking so we wait for the process to terminate
235 fconfigure $commfd -blocking 1
236 if {![catch {close $commfd} err]} {
237 after idle finishcommits
238 return
239 }
240 if {[string range $err 0 4] == "usage"} {
241 set err \
242 {Gitk: error reading commits: bad arguments to git-rev-list.
243 (Note: arguments to gitk are passed to git-rev-list
244 to allow selection of commits to be displayed.)}
245 } else {
246 set err "Error reading commits: $err"
247 }
248 error_popup $err
249 exit 1
250 }
251 set start 0
252 while 1 {
253 set i [string first "\0" $stuff $start]
254 if {$i < 0} {
255 append leftover [string range $stuff $start end]
256 return
257 }
258 set cmit [string range $stuff $start [expr {$i - 1}]]
259 if {$start == 0} {
260 set cmit "$leftover$cmit"
261 set leftover {}
262 }
263 set start [expr {$i + 1}]
264 regsub -all "\r\n" $cmit "\n" cmit
265 set j [string first "\n" $cmit]
266 set ok 0
267 if {$j >= 0} {
268 set ids [string range $cmit 0 [expr {$j - 1}]]
269 set ok 1
270 foreach id $ids {
271 if {![regexp {^[0-9a-f]{12}$} $id]} {
272 set ok 0
273 break
274 }
275 }
276 }
277 if {!$ok} {
278 set shortcmit $cmit
279 if {[string length $shortcmit] > 80} {
280 set shortcmit "[string range $shortcmit 0 80]..."
281 }
282 error_popup "Can't parse hg debug-rev-list output: {$shortcmit}"
283 exit 1
284 }
285 set id [lindex $ids 0]
286 set olds [lrange $ids 1 end]
287 set cmit [string range $cmit [expr {$j + 1}] end]
288 lappend commits $id
289 set commitlisted($id) 1
290 parsecommit $id $cmit 1 [lrange $ids 1 end]
291 drawcommit $id
292 if {[clock clicks -milliseconds] >= $nextupdate} {
293 doupdate 1
294 }
295 while {$redisplaying} {
296 set redisplaying 0
297 if {$stopped == 1} {
298 set stopped 0
299 set phase "getcommits"
300 foreach id $commits {
301 drawcommit $id
302 if {$stopped} break
303 if {[clock clicks -milliseconds] >= $nextupdate} {
304 doupdate 1
305 }
306 }
307 }
308 }
309 }
310 }
311
312 proc doupdate {reading} {
313 global commfd nextupdate numcommits ncmupdate
314
315 if {$reading} {
316 fileevent $commfd readable {}
317 }
318 update
319 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
320 if {$numcommits < 100} {
321 set ncmupdate [expr {$numcommits + 1}]
322 } elseif {$numcommits < 10000} {
323 set ncmupdate [expr {$numcommits + 10}]
324 } else {
325 set ncmupdate [expr {$numcommits + 100}]
326 }
327 if {$reading} {
328 fileevent $commfd readable [list getcommitlines $commfd]
329 }
330 }
331
332 proc readcommit {id} {
333 global env
334 if [catch {set contents [exec $env(HG) --config ui.report_untrusted=false debug-cat-file commit $id]}] return
335 parsecommit $id $contents 0 {}
336 }
337
338 proc parsecommit {id contents listed olds} {
339 global commitinfo children nchildren parents nparents cdate ncleft
340 global firstparents obsolete
341
342 set inhdr 1
343 set comment {}
344 set headline {}
345 set auname {}
346 set audate {}
347 set comname {}
348 set comdate {}
349 set rev {}
350 set branch {}
351 set bookmark {}
352 if {![info exists nchildren($id)]} {
353 set children($id) {}
354 set nchildren($id) 0
355 set ncleft($id) 0
356 }
357 set parents($id) $olds
358 set nparents($id) [llength $olds]
359 foreach p $olds {
360 if {![info exists nchildren($p)]} {
361 set children($p) [list $id]
362 set nchildren($p) 1
363 set ncleft($p) 1
364 } elseif {[lsearch -exact $children($p) $id] < 0} {
365 lappend children($p) $id
366 incr nchildren($p)
367 incr ncleft($p)
368 }
369 }
370 regsub -all "\r\n" $contents "\n" contents
371 foreach line [split $contents "\n"] {
372 if {$inhdr} {
373 set line [split $line]
374 if {$line == {}} {
375 set inhdr 0
376 } else {
377 set tag [lindex $line 0]
378 switch -- $tag "author" {
379 set x [expr {[llength $line] - 2}]
380 set audate [lindex $line $x]
381 set auname [join [lrange $line 1 [expr {$x - 1}]]]
382 } "committer" {
383 set x [expr {[llength $line] - 2}]
384 set comdate [lindex $line $x]
385 set comname [join [lrange $line 1 [expr {$x - 1}]]]
386 } "revision" {
387 set rev [lindex $line 1]
388 } "branch" {
389 set branch [join [lrange $line 1 end]]
390 } "bookmark" {
391 set bookmark [join [lrange $line 1 end]]
392 } "obsolete" {
393 set obsolete($id) ""
394 } "phase" {
395 set phase [lindex $line 1 end]
396 }
397 }
398 } else {
399 if {$comment == {}} {
400 set headline [string trim $line]
401 } else {
402 append comment "\n"
403 }
404 if {!$listed} {
405 # git-rev-list indents the comment by 4 spaces;
406 # if we got this via git-cat-file, add the indentation
407 append comment " "
408 }
409 append comment $line
410 }
411 }
412 if {$audate != {}} {
413 set audate [clock format $audate]
414 }
415 if {$comdate != {}} {
416 set cdate($id) $comdate
417 set comdate [clock format $comdate]
418 }
419 set commitinfo($id) [list $headline $auname $audate \
420 $comname $comdate $comment $rev $branch $bookmark $phase]
421
422 if {[info exists firstparents]} {
423 set i [lsearch $firstparents $id]
424 if {$i != -1} {
425 # remove the parent from firstparents, possible building
426 # an empty list
427 set firstparents [concat \
428 [lrange $firstparents 0 [expr $i - 1]] \
429 [lrange $firstparents [expr $i + 1] end]]
430 if {$firstparents eq {}} {
431 # we have found all parents of the first changeset
432 # which means that we can safely select the first line
433 after idle {
434 selectline 0 0
435 }
436 }
437 }
438 } else {
439 # this is the first changeset, save the parents
440 set firstparents $olds
441 if {$firstparents eq {}} {
442 # a repository with a single changeset
443 after idle {
444 selectline 0 0
445 }
446 }
447 }
448 }
449
450 proc readrefs {} {
451 global bookmarkcurrent bookmarkids tagids idtags idbookmarks headids idheads tagcontents env curid
452
453 set status [catch {exec $env(HG) --config ui.report_untrusted=false id} curid]
454 if { $status != 0 } {
455 puts $::errorInfo
456 if { ![string equal $::errorCode NONE] } {
457 exit 2
458 }
459 }
460 regexp -- {[[:xdigit:]]+} $curid curid
461
462 set status [catch {exec $env(HG) --config ui.report_untrusted=false tags} tags]
463 if { $status != 0 } {
464 puts $::errorInfo
465 if { ![string equal $::errorCode NONE] } {
466 exit 2
467 }
468 }
469
470 foreach {- tag rev id} [regexp -inline -all -line {^(.+\S)\s+(\d+):(\S+)} $tags] {
471 # we use foreach as Tcl8.4 doesn't support lassign
472 lappend tagids($tag) $id
473 lappend idtags($id) $tag
474 }
475
476 set status [catch {exec $env(HG) --config ui.report_untrusted=false heads} heads]
477 if { $status != 0 } {
478 puts $::errorInfo
479 if { ![string equal $::errorCode NONE] } {
480 exit 2
481 }
482 }
483
484 set lines [split $heads \r\n]
485 foreach f $lines {
486 set match ""
487 regexp {changeset:\s+(\S+):(\S+)$} $f match id sha
488 if {$match != ""} {
489 lappend idheads($sha) $id
490 }
491 }
492
493 set status [catch {exec $env(HG) --config ui.report_untrusted=false bookmarks} bookmarks]
494 if { $status != 0 } {
495 puts $::errorInfo
496 if { ![string equal $::errorCode NONE] } {
497 exit 2
498 }
499 }
500 set lines [split $bookmarks "\n"]
501 set bookmarkcurrent 0
502 foreach f $lines {
503 regexp {(\S+)$} $f full
504 regsub {\s+(\S+)$} $f "" direct
505 set sha [split $full ':']
506 set bookmark [lindex $sha 1]
507 set current [string first " * " $direct)]
508 regsub {^\s(\*|\s)\s} $direct "" direct
509 lappend bookmarkids($direct) $bookmark
510 lappend idbookmarks($bookmark) $direct
511 if {$current >= 0} {
512 set bookmarkcurrent $direct
513 }
514 }
515 }
516
517 proc readotherrefs {base dname excl} {
518 global otherrefids idotherrefs
519
520 set git [gitdir]
521 set files [glob -nocomplain -types f [file join $git $base *]]
522 foreach f $files {
523 catch {
524 set fd [open $f r]
525 set line [read $fd 40]
526 if {[regexp {^[0-9a-f]{12}} $line id]} {
527 set name "$dname[file tail $f]"
528 set otherrefids($name) $id
529 lappend idotherrefs($id) $name
530 }
531 close $fd
532 }
533 }
534 set dirs [glob -nocomplain -types d [file join $git $base *]]
535 foreach d $dirs {
536 set dir [file tail $d]
537 if {[lsearch -exact $excl $dir] >= 0} continue
538 readotherrefs [file join $base $dir] "$dname$dir/" {}
539 }
540 }
541
542 proc allcansmousewheel {delta} {
543 set delta [expr -5*(int($delta)/abs($delta))]
544 allcanvs yview scroll $delta units
545 }
546
547 proc error_popup msg {
548 set w .error
549 toplevel $w
550 wm transient $w .
551 message $w.m -text $msg -justify center -aspect 400
552 pack $w.m -side top -fill x -padx 20 -pady 20
553 ttk::button $w.ok -text OK -command "destroy $w"
554 pack $w.ok -side bottom -fill x
555 bind $w <Visibility> "grab $w; focus $w"
556 popupify $w
557 tkwait window $w
558 }
559
560 proc makewindow {} {
561 global canv canv2 canv3 linespc charspc ctext cflist textfont
562 global findtype findtypemenu findloc findstring fstring geometry
563 global entries sha1entry sha1string sha1but
564 global maincursor textcursor curtextcursor
565 global rowctxmenu gaudydiff mergemax
566 global hgvdiff bgcolor fgcolor diffremcolor diffaddcolor diffmerge1color
567 global diffmerge2color hunksepcolor
568 global posx posy
569
570 if {[info exists posx]} {
571 wm geometry . +$posx+$posy
572 }
573
574 menu .bar
575 .bar add cascade -label "File" -menu .bar.file
576 menu .bar.file
577 .bar.file add command -label "Reread references" -command rereadrefs
578 .bar.file add command -label "Quit" -command doquit
579 menu .bar.help
580 .bar add cascade -label "Help" -menu .bar.help
581 .bar.help add command -label "About hgk" -command about
582 . configure -menu .bar
583
584 if {![info exists geometry(canv1)]} {
585 set geometry(canv1) [expr 45 * $charspc]
586 set geometry(canv2) [expr 30 * $charspc]
587 set geometry(canv3) [expr 15 * $charspc]
588 set geometry(canvh) [expr 25 * $linespc + 4]
589 set geometry(ctextw) 80
590 set geometry(ctexth) 30
591 set geometry(cflistw) 30
592 }
593 panedwindow .ctop -orient vertical
594 if {[info exists geometry(width)]} {
595 .ctop conf -width $geometry(width) -height $geometry(height)
596 set texth [expr {$geometry(height) - $geometry(canvh) - 56}]
597 set geometry(ctexth) [expr {($texth - 8) /
598 [font metrics $textfont -linespace]}]
599 }
600 ttk::frame .ctop.top
601 ttk::frame .ctop.top.bar
602 pack .ctop.top.bar -side bottom -fill x
603 set cscroll .ctop.top.csb
604 ttk::scrollbar $cscroll -command {allcanvs yview}
605 pack $cscroll -side right -fill y
606 panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4
607 pack .ctop.top.clist -side top -fill both -expand 1
608 .ctop add .ctop.top
609 set canv .ctop.top.clist.canv
610 canvas $canv -height $geometry(canvh) -width $geometry(canv1) \
611 -bg $bgcolor -bd 0 \
612 -yscrollincr $linespc -yscrollcommand "$cscroll set" -selectbackground "#c0c0c0"
613 .ctop.top.clist add $canv
614 set canv2 .ctop.top.clist.canv2
615 canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \
616 -bg $bgcolor -bd 0 -yscrollincr $linespc -selectbackground "#c0c0c0"
617 .ctop.top.clist add $canv2
618 set canv3 .ctop.top.clist.canv3
619 canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \
620 -bg $bgcolor -bd 0 -yscrollincr $linespc -selectbackground "#c0c0c0"
621 .ctop.top.clist add $canv3
622 bind .ctop.top.clist <Configure> {resizeclistpanes %W %w}
623
624 set sha1entry .ctop.top.bar.sha1
625 set entries $sha1entry
626 set sha1but .ctop.top.bar.sha1label
627 button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
628 -command gotocommit -width 8
629 $sha1but conf -disabledforeground [$sha1but cget -foreground]
630 pack .ctop.top.bar.sha1label -side left
631 ttk::entry $sha1entry -width 40 -font $textfont -textvariable sha1string
632 trace add variable sha1string write sha1change
633 pack $sha1entry -side left -pady 2
634
635 image create bitmap bm-left -data {
636 #define left_width 16
637 #define left_height 16
638 static unsigned char left_bits[] = {
639 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
640 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
641 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
642 }
643 image create bitmap bm-right -data {
644 #define right_width 16
645 #define right_height 16
646 static unsigned char right_bits[] = {
647 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
648 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
649 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
650 }
651 ttk::button .ctop.top.bar.leftbut -image bm-left -command goback \
652 -state disabled -width 26
653 pack .ctop.top.bar.leftbut -side left -fill y
654 ttk::button .ctop.top.bar.rightbut -image bm-right -command goforw \
655 -state disabled -width 26
656 pack .ctop.top.bar.rightbut -side left -fill y
657
658 ttk::button .ctop.top.bar.findbut -text "Find" -command dofind
659 pack .ctop.top.bar.findbut -side left
660 set findstring {}
661 set fstring .ctop.top.bar.findstring
662 lappend entries $fstring
663 ttk::entry $fstring -width 30 -font $textfont -textvariable findstring
664 pack $fstring -side left -expand 1 -fill x
665 set findtype Exact
666 set findtypemenu [ttk::optionMenu .ctop.top.bar.findtype \
667 findtype Exact IgnCase Regexp]
668 set findloc "All fields"
669 ttk::optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
670 Comments Author Files Pickaxe
671 pack .ctop.top.bar.findloc -side right
672 pack .ctop.top.bar.findtype -side right
673 # for making sure type==Exact whenever loc==Pickaxe
674 trace add variable findloc write findlocchange
675
676 panedwindow .ctop.cdet -orient horizontal
677 .ctop add .ctop.cdet
678 ttk::frame .ctop.cdet.left
679 set ctext .ctop.cdet.left.ctext
680 text $ctext -fg $fgcolor -bg $bgcolor -state disabled -font $textfont \
681 -width $geometry(ctextw) -height $geometry(ctexth) \
682 -yscrollcommand ".ctop.cdet.left.sb set" \
683 -xscrollcommand ".ctop.cdet.left.hb set" -wrap none
684 ttk::scrollbar .ctop.cdet.left.sb -command "$ctext yview"
685 ttk::scrollbar .ctop.cdet.left.hb -orient horizontal -command "$ctext xview"
686 pack .ctop.cdet.left.sb -side right -fill y
687 pack .ctop.cdet.left.hb -side bottom -fill x
688 pack $ctext -side left -fill both -expand 1
689 .ctop.cdet add .ctop.cdet.left
690
691 $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
692 if {$gaudydiff} {
693 $ctext tag conf hunksep -back blue -fore white
694 $ctext tag conf d0 -back "#ff8080"
695 $ctext tag conf d1 -back green
696 } else {
697 $ctext tag conf hunksep -fore $hunksepcolor
698 $ctext tag conf d0 -fore $diffremcolor
699 $ctext tag conf d1 -fore $diffaddcolor
700
701 # The mX colours seem to be used in merge changesets, where m0
702 # is first parent, m1 is second parent and so on. Git can have
703 # several parents, Hg cannot, so I think the m2..mmax would be
704 # unused.
705 $ctext tag conf m0 -fore $diffmerge1color
706 $ctext tag conf m1 -fore $diffmerge2color
707 $ctext tag conf m2 -fore green
708 $ctext tag conf m3 -fore purple
709 $ctext tag conf m4 -fore brown
710 $ctext tag conf mmax -fore darkgrey
711 set mergemax 5
712 $ctext tag conf mresult -font [concat $textfont bold]
713 $ctext tag conf msep -font [concat $textfont bold]
714 $ctext tag conf found -back yellow
715 }
716
717 ttk::frame .ctop.cdet.right
718 set cflist .ctop.cdet.right.cfiles
719 listbox $cflist -fg $fgcolor -bg $bgcolor \
720 -selectmode extended -width $geometry(cflistw) \
721 -yscrollcommand ".ctop.cdet.right.sb set"
722 ttk::scrollbar .ctop.cdet.right.sb -command "$cflist yview"
723 pack .ctop.cdet.right.sb -side right -fill y
724 pack $cflist -side left -fill both -expand 1
725 .ctop.cdet add .ctop.cdet.right
726 bind .ctop.cdet <Configure> {resizecdetpanes %W %w}
727
728 pack .ctop -side top -fill both -expand 1
729
730 bindall <1> {selcanvline %W %x %y}
731 #bindall <B1-Motion> {selcanvline %W %x %y}
732 bindall <MouseWheel> "allcansmousewheel %D"
733 bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
734 bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
735 bindall <2> "allcanvs scan mark 0 %y"
736 bindall <B2-Motion> "allcanvs scan dragto 0 %y"
737 bind . <Key-Up> "selnextline -1"
738 bind . <Key-Down> "selnextline 1"
739 bind . <Key-Prior> "allcanvs yview scroll -1 pages"
740 bind . <Key-Next> "allcanvs yview scroll 1 pages"
741 bindkey <Key-Delete> "$ctext yview scroll -1 pages"
742 bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
743 bindkey <Key-space> "$ctext yview scroll 1 pages"
744 bindkey p "selnextline -1"
745 bindkey n "selnextline 1"
746 bindkey b "$ctext yview scroll -1 pages"
747 bindkey d "$ctext yview scroll 18 units"
748 bindkey u "$ctext yview scroll -18 units"
749 bindkey / {findnext 1}
750 bindkey <Key-Return> {findnext 0}
751 bindkey ? findprev
752 bindkey f nextfile
753 bind . <Control-q> doquit
754 bind . <Control-w> doquit
755 bind . <Control-f> dofind
756 bind . <Control-g> {findnext 0}
757 bind . <Control-r> findprev
758 bind . <Control-equal> {incrfont 1}
759 bind . <Control-KP_Add> {incrfont 1}
760 bind . <Control-minus> {incrfont -1}
761 bind . <Control-KP_Subtract> {incrfont -1}
762 bind $cflist <<ListboxSelect>> listboxsel
763 bind . <Destroy> {savestuff %W}
764 bind . <Button-1> "click %W"
765 bind $fstring <Key-Return> dofind
766 bind $sha1entry <Key-Return> gotocommit
767 bind $sha1entry <<PasteSelection>> clearsha1
768
769 set maincursor [. cget -cursor]
770 set textcursor [$ctext cget -cursor]
771 set curtextcursor $textcursor
772
773 set rowctxmenu .rowctxmenu
774 menu $rowctxmenu -tearoff 0
775 $rowctxmenu add command -label "Diff this -> selected" \
776 -command {diffvssel 0}
777 $rowctxmenu add command -label "Diff selected -> this" \
778 -command {diffvssel 1}
779 $rowctxmenu add command -label "Make patch" -command mkpatch
780 $rowctxmenu add command -label "Create tag" -command mktag
781 $rowctxmenu add command -label "Write commit to file" -command writecommit
782 if { $hgvdiff ne "" } {
783 $rowctxmenu add command -label "Visual diff with parent" \
784 -command {vdiff 1}
785 $rowctxmenu add command -label "Visual diff with selected" \
786 -command {vdiff 0}
787 }
788 }
789
790 # when we make a key binding for the toplevel, make sure
791 # it doesn't get triggered when that key is pressed in the
792 # find string entry widget.
793 proc bindkey {ev script} {
794 global entries
795 bind . $ev $script
796 set escript [bind Entry $ev]
797 if {$escript == {}} {
798 set escript [bind Entry <Key>]
799 }
800 foreach e $entries {
801 bind $e $ev "$escript; break"
802 }
803 }
804
805 # set the focus back to the toplevel for any click outside
806 # the entry widgets
807 proc click {w} {
808 global ctext entries
809 foreach e [concat $entries $ctext] {
810 if {$w == $e} return
811 }
812 focus .
813 }
814
815 proc savestuff {w} {
816 global canv canv2 canv3 ctext cflist mainfont textfont
817 global stuffsaved findmergefiles gaudydiff maxgraphpct
818 global maxwidth authorcolors curidfont bgcolor fgcolor
819 global diffremcolor diffaddcolor hunksepcolor
820 global diffmerge1color diffmerge2color
821
822 if {$stuffsaved} return
823 if {![winfo viewable .]} return
824 catch {
825 set f [open "~/.hgk-new" w]
826 puts $f [list set mainfont $mainfont]
827 puts $f [list set curidfont $curidfont]
828 puts $f [list set textfont $textfont]
829 puts $f [list set findmergefiles $findmergefiles]
830 puts $f [list set gaudydiff $gaudydiff]
831 puts $f [list set maxgraphpct $maxgraphpct]
832 puts $f [list set maxwidth $maxwidth]
833 puts $f "set geometry(width) [winfo width .ctop]"
834 puts $f "set geometry(height) [winfo height .ctop]"
835 puts $f "set geometry(canv1) [expr [winfo width $canv]-2]"
836 puts $f "set geometry(canv2) [expr [winfo width $canv2]-2]"
837 puts $f "set geometry(canv3) [expr [winfo width $canv3]-2]"
838 puts $f "set geometry(canvh) [expr [winfo height $canv]-2]"
839 set wid [expr {([winfo width $ctext] - 8) \
840 / [font measure $textfont "0"]}]
841 puts $f "set geometry(ctextw) $wid"
842 set wid [expr {([winfo width $cflist] - 11) \
843 / [font measure [$cflist cget -font] "0"]}]
844 puts $f "set geometry(cflistw) $wid"
845 puts $f "#"
846 puts $f "# main window position:"
847 puts $f "set posx [winfo x .]"
848 puts $f "set posy [winfo y .]"
849 puts $f "#"
850 puts $f "# authorcolors format:"
851 puts $f "#"
852 puts $f "# zero or more sublists of"
853 puts $f "#"
854 puts $f "# { regex color }"
855 puts $f "#"
856 puts $f "# followed by a list of colors"
857 puts $f "#"
858 puts $f "# If the commit author matches a regex in a sublist,"
859 puts $f "# the commit will be colored by that color"
860 puts $f "# otherwise the next unused entry from the list of colors"
861 puts $f "# will be assigned to this commit and also all other commits"
862 puts $f "# of the same author. When the list of colors is exhausted,"
863 puts $f "# the last entry will be reused."
864 puts $f "#"
865 puts $f "set authorcolors {$authorcolors}"
866 puts $f "#"
867 puts $f "# The background color in the text windows"
868 puts $f "set bgcolor $bgcolor"
869 puts $f "#"
870 puts $f "# The text color used in the diff and file list view"
871 puts $f "set fgcolor $fgcolor"
872 puts $f "#"
873 puts $f "# Color to display + lines in diffs"
874 puts $f "set diffaddcolor $diffaddcolor"
875 puts $f "#"
876 puts $f "# Color to display - lines in diffs"
877 puts $f "set diffremcolor $diffremcolor"
878 puts $f "#"
879 puts $f "# Merge diffs: Color to signal lines from first parent"
880 puts $f "set diffmerge1color $diffmerge1color"
881 puts $f "#"
882 puts $f "# Merge diffs: Color to signal lines from second parent"
883 puts $f "set diffmerge2color $diffmerge2color"
884 puts $f "#"
885 puts $f "# Hunkseparator (@@ -lineno,lines +lineno,lines @@) color"
886 puts $f "set hunksepcolor $hunksepcolor"
887 close $f
888 file rename -force "~/.hgk-new" "~/.hgk"
889 }
890 set stuffsaved 1
891 }
892
893 proc resizeclistpanes {win w} {
894 global oldwidth
895 if [info exists oldwidth($win)] {
896 set s0 [$win sash coord 0]
897 set s1 [$win sash coord 1]
898 if {$w < 60} {
899 set sash0 [expr {int($w/2 - 2)}]
900 set sash1 [expr {int($w*5/6 - 2)}]
901 } else {
902 set factor [expr {1.0 * $w / $oldwidth($win)}]
903 set sash0 [expr {int($factor * [lindex $s0 0])}]
904 set sash1 [expr {int($factor * [lindex $s1 0])}]
905 if {$sash0 < 30} {
906 set sash0 30
907 }
908 if {$sash1 < $sash0 + 20} {
909 set sash1 [expr $sash0 + 20]
910 }
911 if {$sash1 > $w - 10} {
912 set sash1 [expr $w - 10]
913 if {$sash0 > $sash1 - 20} {
914 set sash0 [expr $sash1 - 20]
915 }
916 }
917 }
918 $win sash place 0 $sash0 [lindex $s0 1]
919 $win sash place 1 $sash1 [lindex $s1 1]
920 }
921 set oldwidth($win) $w
922 }
923
924 proc resizecdetpanes {win w} {
925 global oldwidth
926 if [info exists oldwidth($win)] {
927 set s0 [$win sash coord 0]
928 if {$w < 60} {
929 set sash0 [expr {int($w*3/4 - 2)}]
930 } else {
931 set factor [expr {1.0 * $w / $oldwidth($win)}]
932 set sash0 [expr {int($factor * [lindex $s0 0])}]
933 if {$sash0 < 45} {
934 set sash0 45
935 }
936 if {$sash0 > $w - 15} {
937 set sash0 [expr $w - 15]
938 }
939 }
940 $win sash place 0 $sash0 [lindex $s0 1]
941 }
942 set oldwidth($win) $w
943 }
944
945 proc allcanvs args {
946 global canv canv2 canv3
947 eval $canv $args
948 eval $canv2 $args
949 eval $canv3 $args
950 }
951
952 proc bindall {event action} {
953 global canv canv2 canv3
954 bind $canv $event $action
955 bind $canv2 $event $action
956 bind $canv3 $event $action
957 }
958
959 proc about {} {
960 set w .about
961 if {[winfo exists $w]} {
962 raise $w
963 return
964 }
965 toplevel $w
966 wm title $w "About hgk"
967 message $w.m -text {
968 Hgk version 1.2
969
970 Copyright � 2005 Paul Mackerras
971
972 Use and redistribute under the terms of the GNU General Public License} \
973 -justify center -aspect 400
974 pack $w.m -side top -fill x -padx 20 -pady 20
975 ttk::button $w.ok -text Close -command "destroy $w"
976 pack $w.ok -side bottom
977 popupify $w
978 }
979
980 set aunextcolor 0
981 proc assignauthorcolor {name} {
982 global authorcolors aucolormap aunextcolor
983 if [info exists aucolormap($name)] return
984
985 set randomcolors {black}
986 for {set i 0} {$i < [llength $authorcolors]} {incr i} {
987 set col [lindex $authorcolors $i]
988 if {[llength $col] > 1} {
989 set re [lindex $col 0]
990 set c [lindex $col 1]
991 if {[regexp -- $re $name]} {
992 set aucolormap($name) $c
993 return
994 }
995 } else {
996 set randomcolors [lrange $authorcolors $i end]
997 break
998 }
999 }
1000
1001 set ncolors [llength $randomcolors]
1002 set c [lindex $randomcolors $aunextcolor]
1003 if {[incr aunextcolor] >= $ncolors} {
1004 incr aunextcolor -1
1005 }
1006 set aucolormap($name) $c
1007 }
1008
1009 proc assigncolor {id} {
1010 global commitinfo colormap commcolors colors nextcolor
1011 global parents nparents children nchildren
1012 global cornercrossings crossings
1013
1014 if [info exists colormap($id)] return
1015 set ncolors [llength $colors]
1016 if {$nparents($id) <= 1 && $nchildren($id) == 1} {
1017 set child [lindex $children($id) 0]
1018 if {[info exists colormap($child)]
1019 && $nparents($child) == 1} {
1020 set colormap($id) $colormap($child)
1021 return
1022 }
1023 }
1024 set badcolors {}
1025 if {[info exists cornercrossings($id)]} {
1026 foreach x $cornercrossings($id) {
1027 if {[info exists colormap($x)]
1028 && [lsearch -exact $badcolors $colormap($x)] < 0} {
1029 lappend badcolors $colormap($x)
1030 }
1031 }
1032 if {[llength $badcolors] >= $ncolors} {
1033 set badcolors {}
1034 }
1035 }
1036 set origbad $badcolors
1037 if {[llength $badcolors] < $ncolors - 1} {
1038 if {[info exists crossings($id)]} {
1039 foreach x $crossings($id) {
1040 if {[info exists colormap($x)]
1041 && [lsearch -exact $badcolors $colormap($x)] < 0} {
1042 lappend badcolors $colormap($x)
1043 }
1044 }
1045 if {[llength $badcolors] >= $ncolors} {
1046 set badcolors $origbad
1047 }
1048 }
1049 set origbad $badcolors
1050 }
1051 if {[llength $badcolors] < $ncolors - 1} {
1052 foreach child $children($id) {
1053 if {[info exists colormap($child)]
1054 && [lsearch -exact $badcolors $colormap($child)] < 0} {
1055 lappend badcolors $colormap($child)
1056 }
1057 if {[info exists parents($child)]} {
1058 foreach p $parents($child) {
1059 if {[info exists colormap($p)]
1060 && [lsearch -exact $badcolors $colormap($p)] < 0} {
1061 lappend badcolors $colormap($p)
1062 }
1063 }
1064 }
1065 }
1066 if {[llength $badcolors] >= $ncolors} {
1067 set badcolors $origbad
1068 }
1069 }
1070 for {set i 0} {$i <= $ncolors} {incr i} {
1071 set c [lindex $colors $nextcolor]
1072 if {[incr nextcolor] >= $ncolors} {
1073 set nextcolor 0
1074 }
1075 if {[lsearch -exact $badcolors $c]} break
1076 }
1077 set colormap($id) $c
1078 }
1079
1080 proc initgraph {} {
1081 global canvy canvy0 lineno numcommits nextcolor linespc
1082 global mainline mainlinearrow sidelines
1083 global nchildren ncleft
1084 global displist nhyperspace
1085
1086 allcanvs delete all
1087 set nextcolor 0
1088 set canvy $canvy0
1089 set lineno -1
1090 set numcommits 0
1091 catch {unset mainline}
1092 catch {unset mainlinearrow}
1093 catch {unset sidelines}
1094 foreach id [array names nchildren] {
1095 set ncleft($id) $nchildren($id)
1096 }
1097 set displist {}
1098 set nhyperspace 0
1099 }
1100
1101 proc bindline {t id} {
1102 global canv
1103
1104 $canv bind $t <Enter> "lineenter %x %y $id"
1105 $canv bind $t <Motion> "linemotion %x %y $id"
1106 $canv bind $t <Leave> "lineleave $id"
1107 $canv bind $t <Button-1> "lineclick %x %y $id 1"
1108 }
1109
1110 proc drawlines {id xtra} {
1111 global mainline mainlinearrow sidelines lthickness colormap canv
1112
1113 $canv delete lines.$id
1114 if {[info exists mainline($id)]} {
1115 set t [$canv create line $mainline($id) \
1116 -width [expr {($xtra + 1) * $lthickness}] \
1117 -fill $colormap($id) -tags lines.$id \
1118 -arrow $mainlinearrow($id)]
1119 $canv lower $t
1120 bindline $t $id
1121 }
1122 if {[info exists sidelines($id)]} {
1123 foreach ls $sidelines($id) {
1124 set coords [lindex $ls 0]
1125 set thick [lindex $ls 1]
1126 set arrow [lindex $ls 2]
1127 set t [$canv create line $coords -fill $colormap($id) \
1128 -width [expr {($thick + $xtra) * $lthickness}] \
1129 -arrow $arrow -tags lines.$id]
1130 $canv lower $t
1131 bindline $t $id
1132 }
1133 }
1134 }
1135
1136 # level here is an index in displist
1137 proc drawcommitline {level} {
1138 global parents children nparents displist
1139 global canv canv2 canv3 mainfont namefont canvy linespc
1140 global lineid linehtag linentag linedtag commitinfo
1141 global colormap numcommits currentparents dupparents
1142 global idtags idline idheads idotherrefs idbookmarks
1143 global lineno lthickness mainline mainlinearrow sidelines
1144 global commitlisted rowtextx idpos lastuse displist
1145 global oldnlines olddlevel olddisplist
1146 global aucolormap curid curidfont obsolete
1147
1148 incr numcommits
1149 incr lineno
1150 set id [lindex $displist $level]
1151 set lastuse($id) $lineno
1152 set lineid($lineno) $id
1153 set idline($id) $lineno
1154 set shape oval
1155 set outline #000080
1156 set ofill [expr {[info exists commitlisted($id)]? "#7f7fff": "white"}]
1157 if {![info exists commitinfo($id)]} {
1158 readcommit $id
1159 if {![info exists commitinfo($id)]} {
1160 set commitinfo($id) {"No commit information available"}
1161 set nparents($id) 0
1162 }
1163 } else {
1164 switch [lindex $commitinfo($id) 9] secret {
1165 set shape rect
1166 } public {
1167 set outline black
1168 set ofill blue
1169 }
1170 }
1171 if {[info exists obsolete($id)]} {
1172 set outline darkgrey
1173 set ofill lightgrey
1174 }
1175 assigncolor $id
1176 set currentparents {}
1177 set dupparents {}
1178 if {[info exists commitlisted($id)] && [info exists parents($id)]} {
1179 foreach p $parents($id) {
1180 if {[lsearch -exact $currentparents $p] < 0} {
1181 lappend currentparents $p
1182 } else {
1183 # remember that this parent was listed twice
1184 lappend dupparents $p
1185 }
1186 }
1187 }
1188 set x [xcoord $level $level $lineno]
1189 set y1 $canvy
1190 set canvy [expr $canvy + $linespc]
1191 allcanvs conf -scrollregion \
1192 [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]]
1193 if {[info exists mainline($id)]} {
1194 lappend mainline($id) $x $y1
1195 if {$mainlinearrow($id) ne "none"} {
1196 set mainline($id) [trimdiagstart $mainline($id)]
1197 }
1198 }
1199 drawlines $id 0
1200 set orad [expr {$linespc / 3}]
1201 set t [$canv create $shape [expr $x - $orad] [expr $y1 - $orad] \
1202 [expr $x + $orad - 1] [expr $y1 + $orad - 1] \
1203 -fill $ofill -outline $outline -width 1]
1204 $canv raise $t
1205 $canv bind $t <1> {selcanvline {} %x %y}
1206 set xt [xcoord [llength $displist] $level $lineno]
1207 if {[llength $currentparents] > 2} {
1208 set xt [expr {$xt + ([llength $currentparents] - 2) * $linespc}]
1209 }
1210 set rowtextx($lineno) $xt
1211 set idpos($id) [list $x $xt $y1]
1212 if {[info exists idtags($id)] || [info exists idheads($id)]
1213 || [info exists idotherrefs($id)] || [info exists idbookmarks($id)]} {
1214 set xt [drawtags $id $x $xt $y1]
1215 }
1216 set headline [lindex $commitinfo($id) 0]
1217 set name [lindex $commitinfo($id) 1]
1218 assignauthorcolor $name
1219 set fg $aucolormap($name)
1220 if {$id == $curid} {
1221 set fn $curidfont
1222 } else {
1223 set fn $mainfont
1224 }
1225
1226 set date [lindex $commitinfo($id) 2]
1227 set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
1228 -text $headline -font $fn \
1229 -fill $fg]
1230 $canv bind $linehtag($lineno) <<B3>> "rowmenu %X %Y $id"
1231 set linentag($lineno) [$canv2 create text 3 $y1 -anchor w \
1232 -text $name -font $namefont \
1233 -fill $fg]
1234 set linedtag($lineno) [$canv3 create text 3 $y1 -anchor w \
1235 -text $date -font $mainfont \
1236 -fill $fg]
1237
1238 set olddlevel $level
1239 set olddisplist $displist
1240 set oldnlines [llength $displist]
1241 }
1242
1243 proc drawtags {id x xt y1} {
1244 global bookmarkcurrent idtags idbookmarks idheads idotherrefs commitinfo
1245 global linespc lthickness
1246 global canv mainfont idline rowtextx
1247
1248 set marks {}
1249 set nbookmarks 0
1250 set ntags 0
1251 set nheads 0
1252 if {[info exists idtags($id)]} {
1253 set marks $idtags($id)
1254 set ntags [llength $marks]
1255 }
1256 if {[info exists idbookmarks($id)]} {
1257 set marks [concat $marks $idbookmarks($id)]
1258 set nbookmarks [llength $idbookmarks($id)]
1259 }
1260 if {[info exists idheads($id)]} {
1261 set headmark [lindex $commitinfo($id) 7]
1262 if {$headmark ne "default"} {
1263 lappend marks $headmark
1264 set nheads 1
1265 }
1266 }
1267 if {$marks eq {}} {
1268 return $xt
1269 }
1270
1271 set delta [expr {int(0.5 * ($linespc - $lthickness))}]
1272 set yt [expr $y1 - 0.5 * $linespc]
1273 set yb [expr $yt + $linespc - 1]
1274 set xvals {}
1275 set wvals {}
1276 foreach tag $marks {
1277 set wid [font measure $mainfont $tag]
1278 lappend xvals $xt
1279 lappend wvals $wid
1280 set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
1281 }
1282 set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
1283 -width $lthickness -fill black -tags tag.$id]
1284 $canv lower $t
1285 foreach tag $marks x $xvals wid $wvals {
1286 set xl [expr $x + $delta]
1287 set xr [expr $x + $delta + $wid + $lthickness]
1288 if {[incr ntags -1] >= 0} {
1289 # draw a tag
1290 set t [$canv create polygon $x [expr $yt + $delta] $xl $yt \
1291 $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \
1292 -width 1 -outline black -fill yellow -tags tag.$id]
1293 $canv bind $t <1> [list showtag $tag 1]
1294 set rowtextx($idline($id)) [expr {$xr + $linespc}]
1295 } elseif {[incr nbookmarks -1] >= 0} {
1296 # draw a tag
1297 set col "#7f7f7f"
1298 if {[string compare $bookmarkcurrent $tag] == 0} {
1299 set col "#bebebe"
1300 }
1301 set xl [expr $xl - $delta/2]
1302 $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
1303 -width 1 -outline black -fill $col -tags tag.$id
1304 } else {
1305 # draw a head or other ref
1306 if {[incr nheads -1] >= 0} {
1307 set col "#00ff00"
1308 } else {
1309 set col "#ddddff"
1310 }
1311 set xl [expr $xl - $delta/2]
1312 $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
1313 -width 1 -outline black -fill $col -tags tag.$id
1314 }
1315 set t [$canv create text $xl $y1 -anchor w -text $tag \
1316 -font $mainfont -tags tag.$id]
1317 if {$ntags >= 0} {
1318 $canv bind $t <1> [list showtag $tag 1]
1319 }
1320 }
1321 return $xt
1322 }
1323
1324 proc notecrossings {id lo hi corner} {
1325 global olddisplist crossings cornercrossings
1326
1327 for {set i $lo} {[incr i] < $hi} {} {
1328 set p [lindex $olddisplist $i]
1329 if {$p == {}} continue
1330 if {$i == $corner} {
1331 if {![info exists cornercrossings($id)]
1332 || [lsearch -exact $cornercrossings($id) $p] < 0} {
1333 lappend cornercrossings($id) $p
1334 }
1335 if {![info exists cornercrossings($p)]
1336 || [lsearch -exact $cornercrossings($p) $id] < 0} {
1337 lappend cornercrossings($p) $id
1338 }
1339 } else {
1340 if {![info exists crossings($id)]
1341 || [lsearch -exact $crossings($id) $p] < 0} {
1342 lappend crossings($id) $p
1343 }
1344 if {![info exists crossings($p)]
1345 || [lsearch -exact $crossings($p) $id] < 0} {
1346 lappend crossings($p) $id
1347 }
1348 }
1349 }
1350 }
1351
1352 proc xcoord {i level ln} {
1353 global canvx0 xspc1 xspc2
1354
1355 set x [expr {$canvx0 + $i * $xspc1($ln)}]
1356 if {$i > 0 && $i == $level} {
1357 set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}]
1358 } elseif {$i > $level} {
1359 set x [expr {$x + $xspc2 - $xspc1($ln)}]
1360 }
1361 return $x
1362 }
1363
1364 # it seems Tk can't draw arrows on the end of diagonal line segments...
1365 proc trimdiagend {line} {
1366 while {[llength $line] > 4} {
1367 set x1 [lindex $line end-3]
1368 set y1 [lindex $line end-2]
1369 set x2 [lindex $line end-1]
1370 set y2 [lindex $line end]
1371 if {($x1 == $x2) != ($y1 == $y2)} break
1372 set line [lreplace $line end-1 end]
1373 }
1374 return $line
1375 }
1376
1377 proc trimdiagstart {line} {
1378 while {[llength $line] > 4} {
1379 set x1 [lindex $line 0]
1380 set y1 [lindex $line 1]
1381 set x2 [lindex $line 2]
1382 set y2 [lindex $line 3]
1383 if {($x1 == $x2) != ($y1 == $y2)} break
1384 set line [lreplace $line 0 1]
1385 }
1386 return $line
1387 }
1388
1389 proc drawslants {id needonscreen nohs} {
1390 global canv mainline mainlinearrow sidelines
1391 global canvx0 canvy xspc1 xspc2 lthickness
1392 global currentparents dupparents
1393 global lthickness linespc canvy colormap lineno geometry
1394 global maxgraphpct maxwidth
1395 global displist onscreen lastuse
1396 global parents commitlisted
1397 global oldnlines olddlevel olddisplist
1398 global nhyperspace numcommits nnewparents
1399
1400 if {$lineno < 0} {
1401 lappend displist $id
1402 set onscreen($id) 1
1403 return 0
1404 }
1405
1406 set y1 [expr {$canvy - $linespc}]
1407 set y2 $canvy
1408
1409 # work out what we need to get back on screen
1410 set reins {}
1411 if {$onscreen($id) < 0} {
1412 # next to do isn't displayed, better get it on screen...
1413 lappend reins [list $id 0]
1414 }
1415 # make sure all the previous commits's parents are on the screen
1416 foreach p $currentparents {
1417 if {$onscreen($p) < 0} {
1418 lappend reins [list $p 0]
1419 }
1420 }
1421 # bring back anything requested by caller
1422 if {$needonscreen ne {}} {
1423 lappend reins $needonscreen
1424 }
1425
1426 # try the shortcut
1427 if {$currentparents == $id && $onscreen($id) == 0 && $reins eq {}} {
1428 set dlevel $olddlevel
1429 set x [xcoord $dlevel $dlevel $lineno]
1430 set mainline($id) [list $x $y1]
1431 set mainlinearrow($id) none
1432 set lastuse($id) $lineno
1433 set displist [lreplace $displist $dlevel $dlevel $id]
1434 set onscreen($id) 1
1435 set xspc1([expr {$lineno + 1}]) $xspc1($lineno)
1436 return $dlevel
1437 }
1438
1439 # update displist
1440 set displist [lreplace $displist $olddlevel $olddlevel]
1441 set j $olddlevel
1442 foreach p $currentparents {
1443 set lastuse($p) $lineno
1444 if {$onscreen($p) == 0} {
1445 set displist [linsert $displist $j $p]
1446 set onscreen($p) 1
1447 incr j
1448 }
1449 }
1450 if {$onscreen($id) == 0} {
1451 lappend displist $id
1452 set onscreen($id) 1
1453 }
1454
1455 # remove the null entry if present
1456 set nullentry [lsearch -exact $displist {}]
1457 if {$nullentry >= 0} {
1458 set displist [lreplace $displist $nullentry $nullentry]
1459 }
1460
1461 # bring back the ones we need now (if we did it earlier
1462 # it would change displist and invalidate olddlevel)
1463 foreach pi $reins {
1464 # test again in case of duplicates in reins
1465 set p [lindex $pi 0]
1466 if {$onscreen($p) < 0} {
1467 set onscreen($p) 1
1468 set lastuse($p) $lineno
1469 set displist [linsert $displist [lindex $pi 1] $p]
1470 incr nhyperspace -1
1471 }
1472 }
1473
1474 set lastuse($id) $lineno
1475
1476 # see if we need to make any lines jump off into hyperspace
1477 set displ [llength $displist]
1478 if {$displ > $maxwidth} {
1479 set ages {}
1480 foreach x $displist {
1481 lappend ages [list $lastuse($x) $x]
1482 }
1483 set ages [lsort -integer -index 0 $ages]
1484 set k 0
1485 while {$displ > $maxwidth} {
1486 set use [lindex $ages $k 0]
1487 set victim [lindex $ages $k 1]
1488 if {$use >= $lineno - 5} break
1489 incr k
1490 if {[lsearch -exact $nohs $victim] >= 0} continue
1491 set i [lsearch -exact $displist $victim]
1492 set displist [lreplace $displist $i $i]
1493 set onscreen($victim) -1
1494 incr nhyperspace
1495 incr displ -1
1496 if {$i < $nullentry} {
1497 incr nullentry -1
1498 }
1499 set x [lindex $mainline($victim) end-1]
1500 lappend mainline($victim) $x $y1
1501 set line [trimdiagend $mainline($victim)]
1502 set arrow "last"
1503 if {$mainlinearrow($victim) ne "none"} {
1504 set line [trimdiagstart $line]
1505 set arrow "both"
1506 }
1507 lappend sidelines($victim) [list $line 1 $arrow]
1508 unset mainline($victim)
1509 }
1510 }
1511
1512 set dlevel [lsearch -exact $displist $id]
1513
1514 # If we are reducing, put in a null entry
1515 if {$displ < $oldnlines} {
1516 # does the next line look like a merge?
1517 # i.e. does it have > 1 new parent?
1518 if {$nnewparents($id) > 1} {
1519 set i [expr {$dlevel + 1}]
1520 } elseif {$nnewparents([lindex $olddisplist $olddlevel]) == 0} {
1521 set i $olddlevel
1522 if {$nullentry >= 0 && $nullentry < $i} {
1523 incr i -1
1524 }
1525 } elseif {$nullentry >= 0} {
1526 set i $nullentry
1527 while {$i < $displ
1528 && [lindex $olddisplist $i] == [lindex $displist $i]} {
1529 incr i
1530 }
1531 } else {
1532 set i $olddlevel
1533 if {$dlevel >= $i} {
1534 incr i
1535 }
1536 }
1537 if {$i < $displ} {
1538 set displist [linsert $displist $i {}]
1539 incr displ
1540 if {$dlevel >= $i} {
1541 incr dlevel
1542 }
1543 }
1544 }
1545
1546 # decide on the line spacing for the next line
1547 set lj [expr {$lineno + 1}]
1548 set maxw [expr {$maxgraphpct * $geometry(canv1) / 100}]
1549 if {$displ <= 1 || $canvx0 + $displ * $xspc2 <= $maxw} {
1550 set xspc1($lj) $xspc2
1551 } else {
1552 set xspc1($lj) [expr {($maxw - $canvx0 - $xspc2) / ($displ - 1)}]
1553 if {$xspc1($lj) < $lthickness} {
1554 set xspc1($lj) $lthickness
1555 }
1556 }
1557
1558 foreach idi $reins {
1559 set id [lindex $idi 0]
1560 set j [lsearch -exact $displist $id]
1561 set xj [xcoord $j $dlevel $lj]
1562 set mainline($id) [list $xj $y2]
1563 set mainlinearrow($id) first
1564 }
1565
1566 set i -1
1567 foreach id $olddisplist {
1568 incr i
1569 if {$id == {}} continue
1570 if {$onscreen($id) <= 0} continue
1571 set xi [xcoord $i $olddlevel $lineno]
1572 if {$i == $olddlevel} {
1573 foreach p $currentparents {
1574 set j [lsearch -exact $displist $p]
1575 set coords [list $xi $y1]
1576 set xj [xcoord $j $dlevel $lj]
1577 if {$xj < $xi - $linespc} {
1578 lappend coords [expr {$xj + $linespc}] $y1
1579 notecrossings $p $j $i [expr {$j + 1}]
1580 } elseif {$xj > $xi + $linespc} {
1581 lappend coords [expr {$xj - $linespc}] $y1
1582 notecrossings $p $i $j [expr {$j - 1}]
1583 }
1584 if {[lsearch -exact $dupparents $p] >= 0} {
1585 # draw a double-width line to indicate the doubled parent
1586 lappend coords $xj $y2
1587 lappend sidelines($p) [list $coords 2 none]
1588 if {![info exists mainline($p)]} {
1589 set mainline($p) [list $xj $y2]
1590 set mainlinearrow($p) none
1591 }
1592 } else {
1593 # normal case, no parent duplicated
1594 set yb $y2
1595 set dx [expr {abs($xi - $xj)}]
1596 if {0 && $dx < $linespc} {
1597 set yb [expr {$y1 + $dx}]
1598 }
1599 if {![info exists mainline($p)]} {
1600 if {$xi != $xj} {
1601 lappend coords $xj $yb
1602 }
1603 set mainline($p) $coords
1604 set mainlinearrow($p) none
1605 } else {
1606 lappend coords $xj $yb
1607 if {$yb < $y2} {
1608 lappend coords $xj $y2
1609 }
1610 lappend sidelines($p) [list $coords 1 none]
1611 }
1612 }
1613 }
1614 } else {
1615 set j $i
1616 if {[lindex $displist $i] != $id} {
1617 set j [lsearch -exact $displist $id]
1618 }
1619 if {$j != $i || $xspc1($lineno) != $xspc1($lj)
1620 || ($olddlevel < $i && $i < $dlevel)
1621 || ($dlevel < $i && $i < $olddlevel)} {
1622 set xj [xcoord $j $dlevel $lj]
1623 lappend mainline($id) $xi $y1 $xj $y2
1624 }
1625 }
1626 }
1627 return $dlevel
1628 }
1629
1630 # search for x in a list of lists
1631 proc llsearch {llist x} {
1632 set i 0
1633 foreach l $llist {
1634 if {$l == $x || [lsearch -exact $l $x] >= 0} {
1635 return $i
1636 }
1637 incr i
1638 }
1639 return -1
1640 }
1641
1642 proc drawmore {reading} {
1643 global displayorder numcommits ncmupdate nextupdate
1644 global stopped nhyperspace parents commitlisted
1645 global maxwidth onscreen displist currentparents olddlevel
1646
1647 set n [llength $displayorder]
1648 while {$numcommits < $n} {
1649 set id [lindex $displayorder $numcommits]
1650 set ctxend [expr {$numcommits + 10}]
1651 if {!$reading && $ctxend > $n} {
1652 set ctxend $n
1653 }
1654 set dlist {}
1655 if {$numcommits > 0} {
1656 set dlist [lreplace $displist $olddlevel $olddlevel]
1657 set i $olddlevel
1658 foreach p $currentparents {
1659 if {$onscreen($p) == 0} {
1660 set dlist [linsert $dlist $i $p]
1661 incr i
1662 }
1663 }
1664 }
1665 set nohs {}
1666 set reins {}
1667 set isfat [expr {[llength $dlist] > $maxwidth}]
1668 if {$nhyperspace > 0 || $isfat} {
1669 if {$ctxend > $n} break
1670 # work out what to bring back and
1671 # what we want to don't want to send into hyperspace
1672 set room 1
1673 for {set k $numcommits} {$k < $ctxend} {incr k} {
1674 set x [lindex $displayorder $k]
1675 set i [llsearch $dlist $x]
1676 if {$i < 0} {
1677 set i [llength $dlist]
1678 lappend dlist $x
1679 }
1680 if {[lsearch -exact $nohs $x] < 0} {
1681 lappend nohs $x
1682 }
1683 if {$reins eq {} && $onscreen($x) < 0 && $room} {
1684 set reins [list $x $i]
1685 }
1686 set newp {}
1687 if {[info exists commitlisted($x)]} {
1688 set right 0
1689 foreach p $parents($x) {
1690 if {[llsearch $dlist $p] < 0} {
1691 lappend newp $p
1692 if {[lsearch -exact $nohs $p] < 0} {
1693 lappend nohs $p
1694 }
1695 if {$reins eq {} && $onscreen($p) < 0 && $room} {
1696 set reins [list $p [expr {$i + $right}]]
1697 }
1698 }
1699 set right 1
1700 }
1701 }
1702 set l [lindex $dlist $i]
1703 if {[llength $l] == 1} {
1704 set l $newp
1705 } else {
1706 set j [lsearch -exact $l $x]
1707 set l [concat [lreplace $l $j $j] $newp]
1708 }
1709 set dlist [lreplace $dlist $i $i $l]
1710 if {$room && $isfat && [llength $newp] <= 1} {
1711 set room 0
1712 }
1713 }
1714 }
1715
1716 set dlevel [drawslants $id $reins $nohs]
1717 drawcommitline $dlevel
1718 if {[clock clicks -milliseconds] >= $nextupdate
1719 && $numcommits >= $ncmupdate} {
1720 doupdate $reading
1721 if {$stopped} break
1722 }
1723 }
1724 }
1725
1726 # level here is an index in todo
1727 proc updatetodo {level noshortcut} {
1728 global ncleft todo nnewparents
1729 global commitlisted parents onscreen
1730
1731 set id [lindex $todo $level]
1732 set olds {}
1733 if {[info exists commitlisted($id)]} {
1734 foreach p $parents($id) {
1735 if {[lsearch -exact $olds $p] < 0} {
1736 lappend olds $p
1737 }
1738 }
1739 }
1740 if {!$noshortcut && [llength $olds] == 1} {
1741 set p [lindex $olds 0]
1742 if {$ncleft($p) == 1 && [lsearch -exact $todo $p] < 0} {
1743 set ncleft($p) 0
1744 set todo [lreplace $todo $level $level $p]
1745 set onscreen($p) 0
1746 set nnewparents($id) 1
1747 return 0
1748 }
1749 }
1750
1751 set todo [lreplace $todo $level $level]
1752 set i $level
1753 set n 0
1754 foreach p $olds {
1755 incr ncleft($p) -1
1756 set k [lsearch -exact $todo $p]
1757 if {$k < 0} {
1758 set todo [linsert $todo $i $p]
1759 set onscreen($p) 0
1760 incr i
1761 incr n
1762 }
1763 }
1764 set nnewparents($id) $n
1765
1766 return 1
1767 }
1768
1769 proc decidenext {{noread 0}} {
1770 global ncleft todo
1771 global datemode cdate
1772 global commitinfo
1773
1774 # choose which one to do next time around
1775 set todol [llength $todo]
1776 set level -1
1777 set latest {}
1778 for {set k $todol} {[incr k -1] >= 0} {} {
1779 set p [lindex $todo $k]
1780 if {$ncleft($p) == 0} {
1781 if {$datemode} {
1782 if {![info exists commitinfo($p)]} {
1783 if {$noread} {
1784 return {}
1785 }
1786 readcommit $p
1787 }
1788 if {$latest == {} || $cdate($p) > $latest} {
1789 set level $k
1790 set latest $cdate($p)
1791 }
1792 } else {
1793 set level $k
1794 break
1795 }
1796 }
1797 }
1798 if {$level < 0} {
1799 if {$todo != {}} {
1800 puts "ERROR: none of the pending commits can be done yet:"
1801 foreach p $todo {
1802 puts " $p ($ncleft($p))"
1803 }
1804 }
1805 return -1
1806 }
1807
1808 return $level
1809 }
1810
1811 proc drawcommit {id} {
1812 global phase todo nchildren datemode nextupdate
1813 global numcommits ncmupdate displayorder todo onscreen
1814
1815 if {$phase != "incrdraw"} {
1816 set phase incrdraw
1817 set displayorder {}
1818 set todo {}
1819 initgraph
1820 }
1821 if {$nchildren($id) == 0} {
1822 lappend todo $id
1823 set onscreen($id) 0
1824 }
1825 set level [decidenext 1]
1826 if {$level == {} || $id != [lindex $todo $level]} {
1827 return
1828 }
1829 while 1 {
1830 lappend displayorder [lindex $todo $level]
1831 if {[updatetodo $level $datemode]} {
1832 set level [decidenext 1]
1833 if {$level == {}} break
1834 }
1835 set id [lindex $todo $level]
1836 if {![info exists commitlisted($id)]} {
1837 break
1838 }
1839 }
1840 drawmore 1
1841 }
1842
1843 proc finishcommits {} {
1844 global phase
1845 global canv mainfont ctext maincursor textcursor
1846
1847 if {$phase != "incrdraw"} {
1848 $canv delete all
1849 $canv create text 3 3 -anchor nw -text "No commits selected" \
1850 -font $mainfont -tags textitems
1851 set phase {}
1852 } else {
1853 drawrest
1854 }
1855 . config -cursor $maincursor
1856 settextcursor $textcursor
1857 }
1858
1859 # Don't change the text pane cursor if it is currently the hand cursor,
1860 # showing that we are over a sha1 ID link.
1861 proc settextcursor {c} {
1862 global ctext curtextcursor
1863
1864 if {[$ctext cget -cursor] == $curtextcursor} {
1865 $ctext config -cursor $c
1866 }
1867 set curtextcursor $c
1868 }
1869
1870 proc drawgraph {} {
1871 global nextupdate startmsecs ncmupdate
1872 global displayorder onscreen
1873
1874 if {$displayorder == {}} return
1875 set startmsecs [clock clicks -milliseconds]
1876 set nextupdate [expr $startmsecs + 100]
1877 set ncmupdate 1
1878 initgraph
1879 foreach id $displayorder {
1880 set onscreen($id) 0
1881 }
1882 drawmore 0
1883 }
1884
1885 proc drawrest {} {
1886 global phase stopped redisplaying selectedline
1887 global datemode todo displayorder
1888 global numcommits ncmupdate
1889 global nextupdate startmsecs
1890
1891 set level [decidenext]
1892 if {$level >= 0} {
1893 set phase drawgraph
1894 while 1 {
1895 lappend displayorder [lindex $todo $level]
1896 set hard [updatetodo $level $datemode]
1897 if {$hard} {
1898 set level [decidenext]
1899 if {$level < 0} break
1900 }
1901 }
1902 drawmore 0
1903 }
1904 set phase {}
1905 set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs]
1906 #puts "overall $drawmsecs ms for $numcommits commits"
1907 if {$redisplaying} {
1908 if {$stopped == 0 && [info exists selectedline]} {
1909 selectline $selectedline 0
1910 }
1911 if {$stopped == 1} {
1912 set stopped 0
1913 after idle drawgraph
1914 } else {
1915 set redisplaying 0
1916 }
1917 }
1918 }
1919
1920 proc findmatches {f} {
1921 global findtype foundstring foundstrlen
1922 if {$findtype == "Regexp"} {
1923 set matches [regexp -indices -all -inline $foundstring $f]
1924 } else {
1925 if {$findtype == "IgnCase"} {
1926 set str [string tolower $f]
1927 } else {
1928 set str $f
1929 }
1930 set matches {}
1931 set i 0
1932 while {[set j [string first $foundstring $str $i]] >= 0} {
1933 lappend matches [list $j [expr $j+$foundstrlen-1]]
1934 set i [expr $j + $foundstrlen]
1935 }
1936 }
1937 return $matches
1938 }
1939
1940 proc dofind {} {
1941 global findtype findloc findstring markedmatches commitinfo
1942 global numcommits lineid linehtag linentag linedtag
1943 global mainfont namefont canv canv2 canv3 selectedline
1944 global matchinglines foundstring foundstrlen
1945
1946 stopfindproc
1947 unmarkmatches
1948 focus .
1949 set matchinglines {}
1950 if {$findloc == "Pickaxe"} {
1951 findpatches
1952 return
1953 }
1954 if {$findtype == "IgnCase"} {
1955 set foundstring [string tolower $findstring]
1956 } else {
1957 set foundstring $findstring
1958 }
1959 set foundstrlen [string length $findstring]
1960 if {$foundstrlen == 0} return
1961 if {$findloc == "Files"} {
1962 findfiles
1963 return
1964 }
1965 if {![info exists selectedline]} {
1966 set oldsel -1
1967 } else {
1968 set oldsel $selectedline
1969 }
1970 set didsel 0
1971 set fldtypes {Headline Author Date CDate Comment}
1972 for {set l 0} {$l < $numcommits} {incr l} {
1973 set id $lineid($l)
1974 set info $commitinfo($id)
1975 set doesmatch 0
1976 foreach f $info ty $fldtypes {
1977 if {$findloc != "All fields" && $findloc != $ty} {
1978 continue
1979 }
1980 set matches [findmatches $f]
1981 if {$matches == {}} continue
1982 set doesmatch 1
1983 if {$ty == "Headline"} {
1984 markmatches $canv $l $f $linehtag($l) $matches $mainfont
1985 } elseif {$ty == "Author"} {
1986 markmatches $canv2 $l $f $linentag($l) $matches $namefont
1987 } elseif {$ty == "Date"} {
1988 markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
1989 }
1990 }
1991 if {$doesmatch} {
1992 lappend matchinglines $l
1993 if {!$didsel && $l > $oldsel} {
1994 findselectline $l
1995 set didsel 1
1996 }
1997 }
1998 }
1999 if {$matchinglines == {}} {
2000 bell
2001 } elseif {!$didsel} {
2002 findselectline [lindex $matchinglines 0]
2003 }
2004 }
2005
2006 proc findselectline {l} {
2007 global findloc commentend ctext
2008 selectline $l 1
2009 if {$findloc == "All fields" || $findloc == "Comments"} {
2010 # highlight the matches in the comments
2011 set f [$ctext get 1.0 $commentend]
2012 set matches [findmatches $f]
2013 foreach match $matches {
2014 set start [lindex $match 0]
2015 set end [expr [lindex $match 1] + 1]
2016 $ctext tag add found "1.0 + $start c" "1.0 + $end c"
2017 }
2018 }
2019 }
2020
2021 proc findnext {restart} {
2022 global matchinglines selectedline
2023 if {![info exists matchinglines]} {
2024 if {$restart} {
2025 dofind
2026 }
2027 return
2028 }
2029 if {![info exists selectedline]} return
2030 foreach l $matchinglines {
2031 if {$l > $selectedline} {
2032 findselectline $l
2033 return
2034 }
2035 }
2036 bell
2037 }
2038
2039 proc findprev {} {
2040 global matchinglines selectedline
2041 if {![info exists matchinglines]} {
2042 dofind
2043 return
2044 }
2045 if {![info exists selectedline]} return
2046 set prev {}
2047 foreach l $matchinglines {
2048 if {$l >= $selectedline} break
2049 set prev $l
2050 }
2051 if {$prev != {}} {
2052 findselectline $prev
2053 } else {
2054 bell
2055 }
2056 }
2057
2058 proc findlocchange {name ix op} {
2059 global findloc findtype findtypemenu
2060 if {$findloc == "Pickaxe"} {
2061 set findtype Exact
2062 set state disabled
2063 } else {
2064 set state normal
2065 }
2066 $findtypemenu entryconf 1 -state $state
2067 $findtypemenu entryconf 2 -state $state
2068 }
2069
2070 proc stopfindproc {{done 0}} {
2071 global findprocpid findprocfile findids
2072 global ctext findoldcursor phase maincursor textcursor
2073 global findinprogress
2074
2075 catch {unset findids}
2076 if {[info exists findprocpid]} {
2077 if {!$done} {
2078 catch {exec kill $findprocpid}
2079 }
2080 catch {close $findprocfile}
2081 unset findprocpid
2082 }
2083 if {[info exists findinprogress]} {
2084 unset findinprogress
2085 if {$phase != "incrdraw"} {
2086 . config -cursor $maincursor
2087 settextcursor $textcursor
2088 }
2089 }
2090 }
2091
2092 proc findpatches {} {
2093 global findstring selectedline numcommits
2094 global findprocpid findprocfile
2095 global finddidsel ctext lineid findinprogress
2096 global findinsertpos
2097 global env
2098
2099 if {$numcommits == 0} return
2100
2101 # make a list of all the ids to search, starting at the one
2102 # after the selected line (if any)
2103 if {[info exists selectedline]} {
2104 set l $selectedline
2105 } else {
2106 set l -1
2107 }
2108 set inputids {}
2109 for {set i 0} {$i < $numcommits} {incr i} {
2110 if {[incr l] >= $numcommits} {
2111 set l 0
2112 }
2113 append inputids $lineid($l) "\n"
2114 }
2115
2116 if {[catch {
2117 set f [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree --stdin -s -r -S$findstring << $inputids] r]
2118 } err]} {
2119 error_popup "Error starting search process: $err"
2120 return
2121 }
2122
2123 set findinsertpos end
2124 set findprocfile $f
2125 set findprocpid [pid $f]
2126 fconfigure $f -blocking 0
2127 fileevent $f readable readfindproc
2128 set finddidsel 0
2129 . config -cursor watch
2130 settextcursor watch
2131 set findinprogress 1
2132 }
2133
2134 proc readfindproc {} {
2135 global findprocfile finddidsel
2136 global idline matchinglines findinsertpos
2137
2138 set n [gets $findprocfile line]
2139 if {$n < 0} {
2140 if {[eof $findprocfile]} {
2141 stopfindproc 1
2142 if {!$finddidsel} {
2143 bell
2144 }
2145 }
2146 return
2147 }
2148 if {![regexp {^[0-9a-f]{12}} $line id]} {
2149 error_popup "Can't parse git-diff-tree output: $line"
2150 stopfindproc
2151 return
2152 }
2153 if {![info exists idline($id)]} {
2154 puts stderr "spurious id: $id"
2155 return
2156 }
2157 set l $idline($id)
2158 insertmatch $l $id
2159 }
2160
2161 proc insertmatch {l id} {
2162 global matchinglines findinsertpos finddidsel
2163
2164 if {$findinsertpos == "end"} {
2165 if {$matchinglines != {} && $l < [lindex $matchinglines 0]} {
2166 set matchinglines [linsert $matchinglines 0 $l]
2167 set findinsertpos 1
2168 } else {
2169 lappend matchinglines $l
2170 }
2171 } else {
2172 set matchinglines [linsert $matchinglines $findinsertpos $l]
2173 incr findinsertpos
2174 }
2175 markheadline $l $id
2176 if {!$finddidsel} {
2177 findselectline $l
2178 set finddidsel 1
2179 }
2180 }
2181
2182 proc findfiles {} {
2183 global selectedline numcommits lineid ctext
2184 global ffileline finddidsel parents nparents
2185 global findinprogress findstartline findinsertpos
2186 global treediffs fdiffids fdiffsneeded fdiffpos
2187 global findmergefiles
2188 global env
2189
2190 if {$numcommits == 0} return
2191
2192 if {[info exists selectedline]} {
2193 set l [expr {$selectedline + 1}]
2194 } else {
2195 set l 0
2196 }
2197 set ffileline $l
2198 set findstartline $l
2199 set diffsneeded {}
2200 set fdiffsneeded {}
2201 while 1 {
2202 set id $lineid($l)
2203 if {$findmergefiles || $nparents($id) == 1} {
2204 foreach p $parents($id) {
2205 if {![info exists treediffs([list $id $p])]} {
2206 append diffsneeded "$id $p\n"
2207 lappend fdiffsneeded [list $id $p]
2208 }
2209 }
2210 }
2211 if {[incr l] >= $numcommits} {
2212 set l 0
2213 }
2214 if {$l == $findstartline} break
2215 }
2216
2217 # start off a git-diff-tree process if needed
2218 if {$diffsneeded ne {}} {
2219 if {[catch {
2220 set df [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r --stdin << $diffsneeded] r]
2221 } err ]} {
2222 error_popup "Error starting search process: $err"
2223 return
2224 }
2225 catch {unset fdiffids}
2226 set fdiffpos 0
2227 fconfigure $df -blocking 0
2228 fileevent $df readable [list readfilediffs $df]
2229 }
2230
2231 set finddidsel 0
2232 set findinsertpos end
2233 set id $lineid($l)
2234 set p [lindex $parents($id) 0]
2235 . config -cursor watch
2236 settextcursor watch
2237 set findinprogress 1
2238 findcont [list $id $p]
2239 update
2240 }
2241
2242 proc readfilediffs {df} {
2243 global findids fdiffids fdiffs
2244
2245 set n [gets $df line]
2246 if {$n < 0} {
2247 if {[eof $df]} {
2248 donefilediff
2249 if {[catch {close $df} err]} {
2250 stopfindproc
2251 bell
2252 error_popup "Error in hg debug-diff-tree: $err"
2253 } elseif {[info exists findids]} {
2254 set ids $findids
2255 stopfindproc
2256 bell
2257 error_popup "Couldn't find diffs for {$ids}"
2258 }
2259 }
2260 return
2261 }
2262 if {[regexp {^([0-9a-f]{12}) \(from ([0-9a-f]{12})\)} $line match id p]} {
2263 # start of a new string of diffs
2264 donefilediff
2265 set fdiffids [list $id $p]
2266 set fdiffs {}
2267 } elseif {[string match ":*" $line]} {
2268 lappend fdiffs [lindex $line 5]
2269 }
2270 }
2271
2272 proc donefilediff {} {
2273 global fdiffids fdiffs treediffs findids
2274 global fdiffsneeded fdiffpos
2275
2276 if {[info exists fdiffids]} {
2277 while {[lindex $fdiffsneeded $fdiffpos] ne $fdiffids
2278 && $fdiffpos < [llength $fdiffsneeded]} {
2279 # git-diff-tree doesn't output anything for a commit
2280 # which doesn't change anything
2281 set nullids [lindex $fdiffsneeded $fdiffpos]
2282 set treediffs($nullids) {}
2283 if {[info exists findids] && $nullids eq $findids} {
2284 unset findids
2285 findcont $nullids
2286 }
2287 incr fdiffpos
2288 }
2289 incr fdiffpos
2290
2291 if {![info exists treediffs($fdiffids)]} {
2292 set treediffs($fdiffids) $fdiffs
2293 }
2294 if {[info exists findids] && $fdiffids eq $findids} {
2295 unset findids
2296 findcont $fdiffids
2297 }
2298 }
2299 }
2300
2301 proc findcont {ids} {
2302 global findids treediffs parents nparents
2303 global ffileline findstartline finddidsel
2304 global lineid numcommits matchinglines findinprogress
2305 global findmergefiles
2306
2307 set id [lindex $ids 0]
2308 set p [lindex $ids 1]
2309 set pi [lsearch -exact $parents($id) $p]
2310 set l $ffileline
2311 while 1 {
2312 if {$findmergefiles || $nparents($id) == 1} {
2313 if {![info exists treediffs($ids)]} {
2314 set findids $ids
2315 set ffileline $l
2316 return
2317 }
2318 set doesmatch 0
2319 foreach f $treediffs($ids) {
2320 set x [findmatches $f]
2321 if {$x != {}} {
2322 set doesmatch 1
2323 break
2324 }
2325 }
2326 if {$doesmatch} {
2327 insertmatch $l $id
2328 set pi $nparents($id)
2329 }
2330 } else {
2331 set pi $nparents($id)
2332 }
2333 if {[incr pi] >= $nparents($id)} {
2334 set pi 0
2335 if {[incr l] >= $numcommits} {
2336 set l 0
2337 }
2338 if {$l == $findstartline} break
2339 set id $lineid($l)
2340 }
2341 set p [lindex $parents($id) $pi]
2342 set ids [list $id $p]
2343 }
2344 stopfindproc
2345 if {!$finddidsel} {
2346 bell
2347 }
2348 }
2349
2350 # mark a commit as matching by putting a yellow background
2351 # behind the headline
2352 proc markheadline {l id} {
2353 global canv mainfont linehtag commitinfo
2354
2355 set bbox [$canv bbox $linehtag($l)]
2356 set t [$canv create rect $bbox -outline {} -tags matches -fill yellow]
2357 $canv lower $t
2358 }
2359
2360 # mark the bits of a headline, author or date that match a find string
2361 proc markmatches {canv l str tag matches font} {
2362 set bbox [$canv bbox $tag]
2363 set x0 [lindex $bbox 0]
2364 set y0 [lindex $bbox 1]
2365 set y1 [lindex $bbox 3]
2366 foreach match $matches {
2367 set start [lindex $match 0]
2368 set end [lindex $match 1]
2369 if {$start > $end} continue
2370 set xoff [font measure $font [string range $str 0 [expr $start-1]]]
2371 set xlen [font measure $font [string range $str 0 [expr $end]]]
2372 set t [$canv create rect [expr $x0+$xoff] $y0 [expr $x0+$xlen+2] $y1 \
2373 -outline {} -tags matches -fill yellow]
2374 $canv lower $t
2375 }
2376 }
2377
2378 proc unmarkmatches {} {
2379 global matchinglines findids
2380 allcanvs delete matches
2381 catch {unset matchinglines}
2382 catch {unset findids}
2383 }
2384
2385 proc selcanvline {w x y} {
2386 global canv canvy0 ctext linespc
2387 global lineid linehtag linentag linedtag rowtextx
2388 set ymax [lindex [$canv cget -scrollregion] 3]
2389 if {$ymax == {}} return
2390 set yfrac [lindex [$canv yview] 0]
2391 set y [expr {$y + $yfrac * $ymax}]
2392 set l [expr {int(($y - $canvy0) / $linespc + 0.5)}]
2393 if {$l < 0} {
2394 set l 0
2395 }
2396 if {$w eq $canv} {
2397 if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return
2398 }
2399 unmarkmatches
2400 selectline $l 1
2401 }
2402
2403 proc commit_descriptor {p} {
2404 global commitinfo
2405 set l "..."
2406 if {[info exists commitinfo($p)]} {
2407 set l [lindex $commitinfo($p) 0]
2408 set r [lindex $commitinfo($p) 6]
2409 }
2410 return "$r:$p ($l)"
2411 }
2412
2413 # append some text to the ctext widget, and make any SHA1 ID
2414 # that we know about be a clickable link.
2415 proc appendwithlinks {text} {
2416 global ctext idline linknum
2417
2418 set start [$ctext index "end - 1c"]
2419 $ctext insert end $text
2420 $ctext insert end "\n"
2421 set links [regexp -indices -all -inline {[0-9a-f]{12}} $text]
2422 foreach l $links {
2423 set s [lindex $l 0]
2424 set e [lindex $l 1]
2425 set linkid [string range $text $s $e]
2426 if {![info exists idline($linkid)]} continue
2427 incr e
2428 $ctext tag add link "$start + $s c" "$start + $e c"
2429 $ctext tag add link$linknum "$start + $s c" "$start + $e c"
2430 $ctext tag bind link$linknum <1> [list selectline $idline($linkid) 1]
2431 incr linknum
2432 }
2433 $ctext tag conf link -foreground blue -underline 1
2434 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
2435 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
2436 }
2437
2438 proc selectline {l isnew} {
2439 global canv canv2 canv3 ctext commitinfo selectedline
2440 global lineid linehtag linentag linedtag
2441 global canvy0 linespc parents nparents children
2442 global cflist currentid sha1entry
2443 global commentend idtags idbookmarks idline linknum
2444
2445 $canv delete hover
2446 normalline
2447 if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
2448 $canv delete secsel
2449 set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
2450 -tags secsel -fill [$canv cget -selectbackground]]
2451 $canv lower $t
2452 $canv2 delete secsel
2453 set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \
2454 -tags secsel -fill [$canv2 cget -selectbackground]]
2455 $canv2 lower $t
2456 $canv3 delete secsel
2457 set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \
2458 -tags secsel -fill [$canv3 cget -selectbackground]]
2459 $canv3 lower $t
2460 set y [expr {$canvy0 + $l * $linespc}]
2461 set ymax [lindex [$canv cget -scrollregion] 3]
2462 set ytop [expr {$y - $linespc - 1}]
2463 set ybot [expr {$y + $linespc + 1}]
2464 set wnow [$canv yview]
2465 set wtop [expr [lindex $wnow 0] * $ymax]
2466 set wbot [expr [lindex $wnow 1] * $ymax]
2467 set wh [expr {$wbot - $wtop}]
2468 set newtop $wtop
2469 if {$ytop < $wtop} {
2470 if {$ybot < $wtop} {
2471 set newtop [expr {$y - $wh / 2.0}]
2472 } else {
2473 set newtop $ytop
2474 if {$newtop > $wtop - $linespc} {
2475 set newtop [expr {$wtop - $linespc}]
2476 }
2477 }
2478 } elseif {$ybot > $wbot} {
2479 if {$ytop > $wbot} {
2480 set newtop [expr {$y - $wh / 2.0}]
2481 } else {
2482 set newtop [expr {$ybot - $wh}]
2483 if {$newtop < $wtop + $linespc} {
2484 set newtop [expr {$wtop + $linespc}]
2485 }
2486 }
2487 }
2488 if {$newtop != $wtop} {
2489 if {$newtop < 0} {
2490 set newtop 0
2491 }
2492 allcanvs yview moveto [expr $newtop * 1.0 / $ymax]
2493 }
2494
2495 if {$isnew} {
2496 addtohistory [list selectline $l 0]
2497 }
2498
2499 set selectedline $l
2500
2501 set id $lineid($l)
2502 set currentid $id
2503 $sha1entry delete 0 end
2504 $sha1entry insert 0 $id
2505 $sha1entry selection range 0 end
2506
2507 $ctext conf -state normal
2508 $ctext delete 0.0 end
2509 set linknum 0
2510 $ctext mark set fmark.0 0.0
2511 $ctext mark gravity fmark.0 left
2512 set info $commitinfo($id)
2513 $ctext insert end "Changeset: [lindex $info 6]\n"
2514 if {[llength [lindex $info 7]] > 0} {
2515 $ctext insert end "Branch: [lindex $info 7]\n"
2516 }
2517 $ctext insert end "User: [lindex $info 1]\n"
2518 $ctext insert end "Date: [lindex $info 2]\n"
2519 if {[lindex $info 3] ne ""} {
2520 $ctext insert end "Committer: [lindex $info 3]\n"
2521 }
2522 if {[info exists idbookmarks($id)]} {
2523 $ctext insert end "Bookmarks:"
2524 foreach bookmark $idbookmarks($id) {
2525 $ctext insert end " $bookmark"
2526 }
2527 $ctext insert end "\n"
2528 }
2529
2530 if {[info exists idtags($id)]} {
2531 $ctext insert end "Tags:"
2532 foreach tag $idtags($id) {
2533 $ctext insert end " $tag"
2534 }
2535 $ctext insert end "\n"
2536 }
2537
2538 set comment {}
2539 if {[info exists parents($id)]} {
2540 foreach p $parents($id) {
2541 append comment "Parent: [commit_descriptor $p]\n"
2542 }
2543 }
2544 if {[info exists children($id)]} {
2545 foreach c $children($id) {
2546 append comment "Child: [commit_descriptor $c]\n"
2547 }
2548 }
2549
2550 if {[lindex $info 9] eq "secret"} {
2551 # for now, display phase for secret changesets only
2552 append comment "Phase: [lindex $info 9]\n"
2553 }
2554
2555 append comment "\n"
2556 append comment [lindex $info 5]
2557
2558 # make anything that looks like a SHA1 ID be a clickable link
2559 appendwithlinks $comment
2560
2561 $ctext tag delete Comments
2562 $ctext tag remove found 1.0 end
2563 $ctext conf -state disabled
2564 set commentend [$ctext index "end - 1c"]
2565
2566 $cflist delete 0 end
2567 $cflist insert end "Comments"
2568 if {$nparents($id) <= 1} {
2569 set parent "null"
2570 if {$nparents($id) == 1} {
2571 set parent $parents($id)
2572 }
2573 startdiff [concat $id $parent]
2574 } elseif {$nparents($id) > 1} {
2575 mergediff $id
2576 }
2577 }
2578
2579 proc selnextline {dir} {
2580 global selectedline
2581 focus .
2582 if {![info exists selectedline]} return
2583 set l [expr $selectedline + $dir]
2584 unmarkmatches
2585 selectline $l 1
2586 }
2587
2588 proc unselectline {} {
2589 global selectedline
2590
2591 catch {unset selectedline}
2592 allcanvs delete secsel
2593 }
2594
2595 proc addtohistory {cmd} {
2596 global history historyindex
2597
2598 if {$historyindex > 0
2599 && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
2600 return
2601 }
2602
2603 if {$historyindex < [llength $history]} {
2604 set history [lreplace $history $historyindex end $cmd]
2605 } else {
2606 lappend history $cmd
2607 }
2608 incr historyindex
2609 if {$historyindex > 1} {
2610 .ctop.top.bar.leftbut conf -state normal
2611 } else {
2612 .ctop.top.bar.leftbut conf -state disabled
2613 }
2614 .ctop.top.bar.rightbut conf -state disabled
2615 }
2616
2617 proc goback {} {
2618 global history historyindex
2619 focus .
2620
2621 if {$historyindex > 1} {
2622 incr historyindex -1
2623 set cmd [lindex $history [expr {$historyindex - 1}]]
2624 eval $cmd
2625 .ctop.top.bar.rightbut conf -state normal
2626 }
2627 if {$historyindex <= 1} {
2628 .ctop.top.bar.leftbut conf -state disabled
2629 }
2630 }
2631
2632 proc goforw {} {
2633 global history historyindex
2634 focus .
2635
2636 if {$historyindex < [llength $history]} {
2637 set cmd [lindex $history $historyindex]
2638 incr historyindex
2639 eval $cmd
2640 .ctop.top.bar.leftbut conf -state normal
2641 }
2642 if {$historyindex >= [llength $history]} {
2643 .ctop.top.bar.rightbut conf -state disabled
2644 }
2645 }
2646
2647 proc mergediff {id} {
2648 global parents diffmergeid diffmergegca mergefilelist diffpindex
2649
2650 set diffmergeid $id
2651 set diffpindex -1
2652 set diffmergegca [findgca $parents($id)]
2653 if {[info exists mergefilelist($id)]} {
2654 if {$mergefilelist($id) ne {}} {
2655 showmergediff
2656 }
2657 } else {
2658 contmergediff {}
2659 }
2660 }
2661
2662 proc findgca {ids} {
2663 global env
2664 set gca {}
2665 foreach id $ids {
2666 if {$gca eq {}} {
2667 set gca $id
2668 } else {
2669 if {[catch {
2670 set gca [exec $env(HG) --config ui.report_untrusted=false debug-merge-base $gca $id]
2671 } err]} {
2672 return {}
2673 }
2674 }
2675 }
2676 return $gca
2677 }
2678
2679 proc contmergediff {ids} {
2680 global diffmergeid diffpindex parents nparents diffmergegca
2681 global treediffs mergefilelist diffids treepending
2682
2683 # diff the child against each of the parents, and diff
2684 # each of the parents against the GCA.
2685 while 1 {
2686 if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} {
2687 set ids [list [lindex $ids 1] $diffmergegca]
2688 } else {
2689 if {[incr diffpindex] >= $nparents($diffmergeid)} break
2690 set p [lindex $parents($diffmergeid) $diffpindex]
2691 set ids [list $diffmergeid $p]
2692 }
2693 if {![info exists treediffs($ids)]} {
2694 set diffids $ids
2695 if {![info exists treepending]} {
2696 gettreediffs $ids
2697 }
2698 return
2699 }
2700 }
2701
2702 # If a file in some parent is different from the child and also
2703 # different from the GCA, then it's interesting.
2704 # If we don't have a GCA, then a file is interesting if it is
2705 # different from the child in all the parents.
2706 if {$diffmergegca ne {}} {
2707 set files {}
2708 foreach p $parents($diffmergeid) {
2709 set gcadiffs $treediffs([list $p $diffmergegca])
2710 foreach f $treediffs([list $diffmergeid $p]) {
2711 if {[lsearch -exact $files $f] < 0
2712 && [lsearch -exact $gcadiffs $f] >= 0} {
2713 lappend files $f
2714 }
2715 }
2716 }
2717 set files [lsort $files]
2718 } else {
2719 set p [lindex $parents($diffmergeid) 0]
2720 set files $treediffs([list $diffmergeid $p])
2721 for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
2722 set p [lindex $parents($diffmergeid) $i]
2723 set df $treediffs([list $diffmergeid $p])
2724 set nf {}
2725 foreach f $files {
2726 if {[lsearch -exact $df $f] >= 0} {
2727 lappend nf $f
2728 }
2729 }
2730 set files $nf
2731 }
2732 }
2733
2734 set mergefilelist($diffmergeid) $files
2735 if {$files ne {}} {
2736 showmergediff
2737 }
2738 }
2739
2740 proc showmergediff {} {
2741 global cflist diffmergeid mergefilelist parents
2742 global diffopts diffinhunk currentfile currenthunk filelines
2743 global diffblocked groupfilelast mergefds groupfilenum grouphunks
2744 global env
2745
2746 set files $mergefilelist($diffmergeid)
2747 foreach f $files {
2748 $cflist insert end $f
2749 }
2750 set env(GIT_DIFF_OPTS) $diffopts
2751 set flist {}
2752 catch {unset currentfile}
2753 catch {unset currenthunk}
2754 catch {unset filelines}
2755 catch {unset groupfilenum}
2756 catch {unset grouphunks}
2757 set groupfilelast -1
2758 foreach p $parents($diffmergeid) {
2759 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $p $diffmergeid]
2760 set cmd [concat $cmd $mergefilelist($diffmergeid)]
2761 if {[catch {set f [open $cmd r]} err]} {
2762 error_popup "Error getting diffs: $err"
2763 foreach f $flist {
2764 catch {close $f}
2765 }
2766 return
2767 }
2768 lappend flist $f
2769 set ids [list $diffmergeid $p]
2770 set mergefds($ids) $f
2771 set diffinhunk($ids) 0
2772 set diffblocked($ids) 0
2773 fconfigure $f -blocking 0
2774 fileevent $f readable [list getmergediffline $f $ids $diffmergeid]
2775 }
2776 }
2777
2778 proc getmergediffline {f ids id} {
2779 global diffmergeid diffinhunk diffoldlines diffnewlines
2780 global currentfile currenthunk
2781 global diffoldstart diffnewstart diffoldlno diffnewlno
2782 global diffblocked mergefilelist
2783 global noldlines nnewlines difflcounts filelines
2784
2785 set n [gets $f line]
2786 if {$n < 0} {
2787 if {![eof $f]} return
2788 }
2789
2790 if {!([info exists diffmergeid] && $diffmergeid == $id)} {
2791 if {$n < 0} {
2792 close $f
2793 }
2794 return
2795 }
2796
2797 if {$diffinhunk($ids) != 0} {
2798 set fi $currentfile($ids)
2799 if {$n > 0 && [regexp {^[-+ \\]} $line match]} {
2800 # continuing an existing hunk
2801 set line [string range $line 1 end]
2802 set p [lindex $ids 1]
2803 if {$match eq "-" || $match eq " "} {
2804 set filelines($p,$fi,$diffoldlno($ids)) $line
2805 incr diffoldlno($ids)
2806 }
2807 if {$match eq "+" || $match eq " "} {
2808 set filelines($id,$fi,$diffnewlno($ids)) $line
2809 incr diffnewlno($ids)
2810 }
2811 if {$match eq " "} {
2812 if {$diffinhunk($ids) == 2} {
2813 lappend difflcounts($ids) \
2814 [list $noldlines($ids) $nnewlines($ids)]
2815 set noldlines($ids) 0
2816 set diffinhunk($ids) 1
2817 }
2818 incr noldlines($ids)
2819 } elseif {$match eq "-" || $match eq "+"} {
2820 if {$diffinhunk($ids) == 1} {
2821 lappend difflcounts($ids) [list $noldlines($ids)]
2822 set noldlines($ids) 0
2823 set nnewlines($ids) 0
2824 set diffinhunk($ids) 2
2825 }
2826 if {$match eq "-"} {
2827 incr noldlines($ids)
2828 } else {
2829 incr nnewlines($ids)
2830 }
2831 }
2832 # and if it's \ No newline at end of line, then what?
2833 return
2834 }
2835 # end of a hunk
2836 if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} {
2837 lappend difflcounts($ids) [list $noldlines($ids)]
2838 } elseif {$diffinhunk($ids) == 2
2839 && ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} {
2840 lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)]
2841 }
2842 set currenthunk($ids) [list $currentfile($ids) \
2843 $diffoldstart($ids) $diffnewstart($ids) \
2844 $diffoldlno($ids) $diffnewlno($ids) \
2845 $difflcounts($ids)]
2846 set diffinhunk($ids) 0
2847 # -1 = need to block, 0 = unblocked, 1 = is blocked
2848 set diffblocked($ids) -1
2849 processhunks
2850 if {$diffblocked($ids) == -1} {
2851 fileevent $f readable {}
2852 set diffblocked($ids) 1
2853 }
2854 }
2855
2856 if {$n < 0} {
2857 # eof
2858 if {!$diffblocked($ids)} {
2859 close $f
2860 set currentfile($ids) [llength $mergefilelist($diffmergeid)]
2861 set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}]
2862 processhunks
2863 }
2864 } elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} {
2865 # start of a new file
2866 set currentfile($ids) \
2867 [lsearch -exact $mergefilelist($diffmergeid) $fname]
2868 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2869 $line match f1l f1c f2l f2c rest]} {
2870 if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} {
2871 # start of a new hunk
2872 if {$f1l == 0 && $f1c == 0} {
2873 set f1l 1
2874 }
2875 if {$f2l == 0 && $f2c == 0} {
2876 set f2l 1
2877 }
2878 set diffinhunk($ids) 1
2879 set diffoldstart($ids) $f1l
2880 set diffnewstart($ids) $f2l
2881 set diffoldlno($ids) $f1l
2882 set diffnewlno($ids) $f2l
2883 set difflcounts($ids) {}
2884 set noldlines($ids) 0
2885 set nnewlines($ids) 0
2886 }
2887 }
2888 }
2889
2890 proc processhunks {} {
2891 global diffmergeid parents nparents currenthunk
2892 global mergefilelist diffblocked mergefds
2893 global grouphunks grouplinestart grouplineend groupfilenum
2894
2895 set nfiles [llength $mergefilelist($diffmergeid)]
2896 while 1 {
2897 set fi $nfiles
2898 set lno 0
2899 # look for the earliest hunk
2900 foreach p $parents($diffmergeid) {
2901 set ids [list $diffmergeid $p]
2902 if {![info exists currenthunk($ids)]} return
2903 set i [lindex $currenthunk($ids) 0]
2904 set l [lindex $currenthunk($ids) 2]
2905 if {$i < $fi || ($i == $fi && $l < $lno)} {
2906 set fi $i
2907 set lno $l
2908 set pi $p
2909 }
2910 }
2911
2912 if {$fi < $nfiles} {
2913 set ids [list $diffmergeid $pi]
2914 set hunk $currenthunk($ids)
2915 unset currenthunk($ids)
2916 if {$diffblocked($ids) > 0} {
2917 fileevent $mergefds($ids) readable \
2918 [list getmergediffline $mergefds($ids) $ids $diffmergeid]
2919 }
2920 set diffblocked($ids) 0
2921
2922 if {[info exists groupfilenum] && $groupfilenum == $fi
2923 && $lno <= $grouplineend} {
2924 # add this hunk to the pending group
2925 lappend grouphunks($pi) $hunk
2926 set endln [lindex $hunk 4]
2927 if {$endln > $grouplineend} {
2928 set grouplineend $endln
2929 }
2930 continue
2931 }
2932 }
2933
2934 # succeeding stuff doesn't belong in this group, so
2935 # process the group now
2936 if {[info exists groupfilenum]} {
2937 processgroup
2938 unset groupfilenum
2939 unset grouphunks
2940 }
2941
2942 if {$fi >= $nfiles} break
2943
2944 # start a new group
2945 set groupfilenum $fi
2946 set grouphunks($pi) [list $hunk]
2947 set grouplinestart $lno
2948 set grouplineend [lindex $hunk 4]
2949 }
2950 }
2951
2952 proc processgroup {} {
2953 global groupfilelast groupfilenum difffilestart
2954 global mergefilelist diffmergeid ctext filelines
2955 global parents diffmergeid diffoffset
2956 global grouphunks grouplinestart grouplineend nparents
2957 global mergemax
2958
2959 $ctext conf -state normal
2960 set id $diffmergeid
2961 set f $groupfilenum
2962 if {$groupfilelast != $f} {
2963 $ctext insert end "\n"
2964 set here [$ctext index "end - 1c"]
2965 set difffilestart($f) $here
2966 set mark fmark.[expr {$f + 1}]
2967 $ctext mark set $mark $here
2968 $ctext mark gravity $mark left
2969 set header [lindex $mergefilelist($id) $f]
2970 set l [expr {(78 - [string length $header]) / 2}]
2971 set pad [string range "----------------------------------------" 1 $l]
2972 $ctext insert end "$pad $header $pad\n" filesep
2973 set groupfilelast $f
2974 foreach p $parents($id) {
2975 set diffoffset($p) 0
2976 }
2977 }
2978
2979 $ctext insert end "@@" msep
2980 set nlines [expr {$grouplineend - $grouplinestart}]
2981 set events {}
2982 set pnum 0
2983 foreach p $parents($id) {
2984 set startline [expr {$grouplinestart + $diffoffset($p)}]
2985 set ol $startline
2986 set nl $grouplinestart
2987 if {[info exists grouphunks($p)]} {
2988 foreach h $grouphunks($p) {
2989 set l [lindex $h 2]
2990 if {$nl < $l} {
2991 for {} {$nl < $l} {incr nl} {
2992 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2993 incr ol
2994 }
2995 }
2996 foreach chunk [lindex $h 5] {
2997 if {[llength $chunk] == 2} {
2998 set olc [lindex $chunk 0]
2999 set nlc [lindex $chunk 1]
3000 set nnl [expr {$nl + $nlc}]
3001 lappend events [list $nl $nnl $pnum $olc $nlc]
3002 incr ol $olc
3003 set nl $nnl
3004 } else {
3005 incr ol [lindex $chunk 0]
3006 incr nl [lindex $chunk 0]
3007 }
3008 }
3009 }
3010 }
3011 if {$nl < $grouplineend} {
3012 for {} {$nl < $grouplineend} {incr nl} {
3013 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
3014 incr ol
3015 }
3016 }
3017 set nlines [expr {$ol - $startline}]
3018 $ctext insert end " -$startline,$nlines" msep
3019 incr pnum
3020 }
3021
3022 set nlines [expr {$grouplineend - $grouplinestart}]
3023 $ctext insert end " +$grouplinestart,$nlines @@\n" msep
3024
3025 set events [lsort -integer -index 0 $events]
3026 set nevents [llength $events]
3027 set nmerge $nparents($diffmergeid)
3028 set l $grouplinestart
3029 for {set i 0} {$i < $nevents} {set i $j} {
3030 set nl [lindex $events $i 0]
3031 while {$l < $nl} {
3032 $ctext insert end " $filelines($id,$f,$l)\n"
3033 incr l
3034 }
3035 set e [lindex $events $i]
3036 set enl [lindex $e 1]
3037 set j $i
3038 set active {}
3039 while 1 {
3040 set pnum [lindex $e 2]
3041 set olc [lindex $e 3]
3042 set nlc [lindex $e 4]
3043 if {![info exists delta($pnum)]} {
3044 set delta($pnum) [expr {$olc - $nlc}]
3045 lappend active $pnum
3046 } else {
3047 incr delta($pnum) [expr {$olc - $nlc}]
3048 }
3049 if {[incr j] >= $nevents} break
3050 set e [lindex $events $j]
3051 if {[lindex $e 0] >= $enl} break
3052 if {[lindex $e 1] > $enl} {
3053 set enl [lindex $e 1]
3054 }
3055 }
3056 set nlc [expr {$enl - $l}]
3057 set ncol mresult
3058 set bestpn -1
3059 if {[llength $active] == $nmerge - 1} {
3060 # no diff for one of the parents, i.e. it's identical
3061 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
3062 if {![info exists delta($pnum)]} {
3063 if {$pnum < $mergemax} {
3064 lappend ncol m$pnum
3065 } else {
3066 lappend ncol mmax
3067 }
3068 break
3069 }
3070 }
3071 } elseif {[llength $active] == $nmerge} {
3072 # all parents are different, see if one is very similar
3073 set bestsim 30
3074 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
3075 set sim [similarity $pnum $l $nlc $f \
3076 [lrange $events $i [expr {$j-1}]]]
3077 if {$sim > $bestsim} {
3078 set bestsim $sim
3079 set bestpn $pnum
3080 }
3081 }
3082 if {$bestpn >= 0} {
3083 lappend ncol m$bestpn
3084 }
3085 }
3086 set pnum -1
3087 foreach p $parents($id) {
3088 incr pnum
3089 if {![info exists delta($pnum)] || $pnum == $bestpn} continue
3090 set olc [expr {$nlc + $delta($pnum)}]
3091 set ol [expr {$l + $diffoffset($p)}]
3092 incr diffoffset($p) $delta($pnum)
3093 unset delta($pnum)
3094 for {} {$olc > 0} {incr olc -1} {
3095 $ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum
3096 incr ol
3097 }
3098 }
3099 set endl [expr {$l + $nlc}]
3100 if {$bestpn >= 0} {
3101 # show this pretty much as a normal diff
3102 set p [lindex $parents($id) $bestpn]
3103 set ol [expr {$l + $diffoffset($p)}]
3104 incr diffoffset($p) $delta($bestpn)
3105 unset delta($bestpn)
3106 for {set k $i} {$k < $j} {incr k} {
3107 set e [lindex $events $k]
3108 if {[lindex $e 2] != $bestpn} continue
3109 set nl [lindex $e 0]
3110 set ol [expr {$ol + $nl - $l}]
3111 for {} {$l < $nl} {incr l} {
3112 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
3113 }
3114 set c [lindex $e 3]
3115 for {} {$c > 0} {incr c -1} {
3116 $ctext insert end "-$filelines($p,$f,$ol)\n" m$bestpn
3117 incr ol
3118 }
3119 set nl [lindex $e 1]
3120 for {} {$l < $nl} {incr l} {
3121 $ctext insert end "+$filelines($id,$f,$l)\n" mresult
3122 }
3123 }
3124 }
3125 for {} {$l < $endl} {incr l} {
3126 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
3127 }
3128 }
3129 while {$l < $grouplineend} {
3130 $ctext insert end " $filelines($id,$f,$l)\n"
3131 incr l
3132 }
3133 $ctext conf -state disabled
3134 }
3135
3136 proc similarity {pnum l nlc f events} {
3137 global diffmergeid parents diffoffset filelines
3138
3139 set id $diffmergeid
3140 set p [lindex $parents($id) $pnum]
3141 set ol [expr {$l + $diffoffset($p)}]
3142 set endl [expr {$l + $nlc}]
3143 set same 0
3144 set diff 0
3145 foreach e $events {
3146 if {[lindex $e 2] != $pnum} continue
3147 set nl [lindex $e 0]
3148 set ol [expr {$ol + $nl - $l}]
3149 for {} {$l < $nl} {incr l} {
3150 incr same [string length $filelines($id,$f,$l)]
3151 incr same
3152 }
3153 set oc [lindex $e 3]
3154 for {} {$oc > 0} {incr oc -1} {
3155 incr diff [string length $filelines($p,$f,$ol)]
3156 incr diff
3157 incr ol
3158 }
3159 set nl [lindex $e 1]
3160 for {} {$l < $nl} {incr l} {
3161 incr diff [string length $filelines($id,$f,$l)]
3162 incr diff
3163 }
3164 }
3165 for {} {$l < $endl} {incr l} {
3166 incr same [string length $filelines($id,$f,$l)]
3167 incr same
3168 }
3169 if {$same == 0} {
3170 return 0
3171 }
3172 return [expr {200 * $same / (2 * $same + $diff)}]
3173 }
3174
3175 proc startdiff {ids} {
3176 global treediffs diffids treepending diffmergeid
3177
3178 set diffids $ids
3179 catch {unset diffmergeid}
3180 if {![info exists treediffs($ids)]} {
3181 if {![info exists treepending]} {
3182 gettreediffs $ids
3183 }
3184 } else {
3185 addtocflist $ids
3186 }
3187 }
3188
3189 proc addtocflist {ids} {
3190 global treediffs cflist
3191 foreach f $treediffs($ids) {
3192 $cflist insert end $f
3193 }
3194 getblobdiffs $ids
3195 }
3196
3197 proc gettreediffs {ids} {
3198 global treediff parents treepending env
3199 set treepending $ids
3200 set treediff {}
3201 set id [lindex $ids 0]
3202 set p [lindex $ids 1]
3203 if [catch {set gdtf [open "|{$env(HG)} --config ui.report_untrusted=false debug-diff-tree -r $p $id" r]}] return
3204 fconfigure $gdtf -blocking 0
3205 fileevent $gdtf readable [list gettreediffline $gdtf $ids]
3206 }
3207
3208 proc gettreediffline {gdtf ids} {
3209 global treediff treediffs treepending diffids diffmergeid
3210
3211 set n [gets $gdtf line]
3212 if {$n < 0} {
3213 if {![eof $gdtf]} return
3214 close $gdtf
3215 set treediffs($ids) $treediff
3216 unset treepending
3217 if {$ids != $diffids} {
3218 gettreediffs $diffids
3219 } else {
3220 if {[info exists diffmergeid]} {
3221 contmergediff $ids
3222 } else {
3223 addtocflist $ids
3224 }
3225 }
3226 return
3227 }
3228 set tab1 [expr [string first "\t" $line] + 1]
3229 set tab2 [expr [string first "\t" $line $tab1] - 1]
3230 set file [string range $line $tab1 $tab2]
3231 lappend treediff $file
3232 }
3233
3234 proc getblobdiffs {ids} {
3235 global diffopts blobdifffd diffids env curdifftag curtagstart
3236 global difffilestart nextupdate diffinhdr treediffs
3237
3238 set id [lindex $ids 0]
3239 set p [lindex $ids 1]
3240 set env(GIT_DIFF_OPTS) $diffopts
3241 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r -p -C $p $id]
3242 if {[catch {set bdf [open $cmd r]} err]} {
3243 puts "error getting diffs: $err"
3244 return
3245 }
3246 set diffinhdr 0
3247 fconfigure $bdf -blocking 0
3248 set blobdifffd($ids) $bdf
3249 set curdifftag Comments
3250 set curtagstart 0.0
3251 catch {unset difffilestart}
3252 fileevent $bdf readable [list getblobdiffline $bdf $diffids]
3253 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
3254 }
3255
3256 proc getblobdiffline {bdf ids} {
3257 global diffids blobdifffd ctext curdifftag curtagstart
3258 global diffnexthead diffnextnote difffilestart
3259 global nextupdate diffinhdr treediffs
3260 global gaudydiff
3261
3262 set n [gets $bdf line]
3263 if {$n < 0} {
3264 if {[eof $bdf]} {
3265 close $bdf
3266 if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
3267 $ctext tag add $curdifftag $curtagstart end
3268 }
3269 }
3270 return
3271 }
3272 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
3273 return
3274 }
3275 regsub -all "\r" $line "" line
3276 $ctext conf -state normal
3277 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
3278 # start of a new file
3279 $ctext insert end "\n"
3280 $ctext tag add $curdifftag $curtagstart end
3281 set curtagstart [$ctext index "end - 1c"]
3282 set header $newname
3283 set here [$ctext index "end - 1c"]
3284 set i [lsearch -exact $treediffs($diffids) $fname]
3285 if {$i >= 0} {
3286 set difffilestart($i) $here
3287 incr i
3288 $ctext mark set fmark.$i $here
3289 $ctext mark gravity fmark.$i left
3290 }
3291 if {$newname != $fname} {
3292 set i [lsearch -exact $treediffs($diffids) $newname]
3293 if {$i >= 0} {
3294 set difffilestart($i) $here
3295 incr i
3296 $ctext mark set fmark.$i $here
3297 $ctext mark gravity fmark.$i left
3298 }
3299 }
3300 set curdifftag "f:$fname"
3301 $ctext tag delete $curdifftag
3302 set l [expr {(78 - [string length $header]) / 2}]
3303 set pad [string range "----------------------------------------" 1 $l]
3304 $ctext insert end "$pad $header $pad\n" filesep
3305 set diffinhdr 1
3306 } elseif {[regexp {^(---|\+\+\+) } $line] && $diffinhdr} {
3307 set diffinhdr 1
3308 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
3309 $line match f1l f1c f2l f2c rest]} {
3310 if {$gaudydiff} {
3311 $ctext insert end "\t" hunksep
3312 $ctext insert end " $f1l " d0 " $f2l " d1
3313 $ctext insert end " $rest \n" hunksep
3314 } else {
3315 $ctext insert end "$line\n" hunksep
3316 }
3317 set diffinhdr 0
3318 } else {
3319 set x [string range $line 0 0]
3320 if {$x == "-" || $x == "+"} {
3321 set tag [expr {$x == "+"}]
3322 if {$gaudydiff} {
3323 set line [string range $line 1 end]
3324 }
3325 $ctext insert end "$line\n" d$tag
3326 } elseif {$x == " "} {
3327 if {$gaudydiff} {
3328 set line [string range $line 1 end]
3329 }
3330 $ctext insert end "$line\n"
3331 } elseif {$diffinhdr || $x == "\\"} {
3332 # e.g. "\ No newline at end of file"
3333 $ctext insert end "$line\n" filesep
3334 } elseif {$line != ""} {
3335 # Something else we don't recognize
3336 if {$curdifftag != "Comments"} {
3337 $ctext insert end "\n"
3338 $ctext tag add $curdifftag $curtagstart end
3339 set curtagstart [$ctext index "end - 1c"]
3340 set curdifftag Comments
3341 }
3342 $ctext insert end "$line\n" filesep
3343 }
3344 }
3345 $ctext conf -state disabled
3346 if {[clock clicks -milliseconds] >= $nextupdate} {
3347 incr nextupdate 100
3348 fileevent $bdf readable {}
3349 update
3350 fileevent $bdf readable "getblobdiffline $bdf {$ids}"
3351 }
3352 }
3353
3354 proc nextfile {} {
3355 global difffilestart ctext
3356 set here [$ctext index @0,0]
3357 for {set i 0} {[info exists difffilestart($i)]} {incr i} {
3358 if {[$ctext compare $difffilestart($i) > $here]} {
3359 if {![info exists pos]
3360 || [$ctext compare $difffilestart($i) < $pos]} {
3361 set pos $difffilestart($i)
3362 }
3363 }
3364 }
3365 if {[info exists pos]} {
3366 $ctext yview $pos
3367 }
3368 }
3369
3370 proc listboxsel {} {
3371 global ctext cflist currentid
3372 if {![info exists currentid]} return
3373 set sel [lsort [$cflist curselection]]
3374 if {$sel eq {}} return
3375 set first [lindex $sel 0]
3376 catch {$ctext yview fmark.$first}
3377 }
3378
3379 proc setcoords {} {
3380 global linespc charspc canvx0 canvy0 mainfont
3381 global xspc1 xspc2 lthickness
3382
3383 set linespc [font metrics $mainfont -linespace]
3384 set charspc [font measure $mainfont "m"]
3385 set canvy0 [expr 3 + 0.5 * $linespc]
3386 set canvx0 [expr 3 + 0.5 * $linespc]
3387 set lthickness [expr {int($linespc / 9) + 1}]
3388 set xspc1(0) $linespc
3389 set xspc2 $linespc
3390 }
3391
3392 proc redisplay {} {
3393 global stopped redisplaying phase
3394 if {$stopped > 1} return
3395 if {$phase == "getcommits"} return
3396 set redisplaying 1
3397 if {$phase == "drawgraph" || $phase == "incrdraw"} {
3398 set stopped 1
3399 } else {
3400 drawgraph
3401 }
3402 }
3403
3404 proc incrfont {inc} {
3405 global mainfont namefont textfont ctext canv phase
3406 global stopped entries curidfont
3407 unmarkmatches
3408 set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
3409 set curidfont [lreplace $curidfont 1 1 [expr {[lindex $curidfont 1] + $inc}]]
3410 set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]]
3411 set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
3412 setcoords
3413 $ctext conf -font $textfont
3414 $ctext tag conf filesep -font [concat $textfont bold]
3415 foreach e $entries {
3416 $e conf -font $mainfont
3417 }
3418 if {$phase == "getcommits"} {
3419 $canv itemconf textitems -font $mainfont
3420 }
3421 redisplay
3422 }
3423
3424 proc clearsha1 {} {
3425 global sha1entry sha1string
3426 if {[string length $sha1string] == 40} {
3427 $sha1entry delete 0 end
3428 }
3429 }
3430
3431 proc sha1change {n1 n2 op} {
3432 global sha1string currentid sha1but
3433 if {$sha1string == {}
3434 || ([info exists currentid] && $sha1string == $currentid)} {
3435 set state disabled
3436 } else {
3437 set state normal
3438 }
3439 if {[$sha1but cget -state] == $state} return
3440 if {$state == "normal"} {
3441 $sha1but conf -state normal -relief raised -text "Goto: "
3442 } else {
3443 $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
3444 }
3445 }
3446
3447 proc gotocommit {} {
3448 global sha1string currentid idline tagids
3449 global lineid numcommits
3450
3451 if {$sha1string == {}
3452 || ([info exists currentid] && $sha1string == $currentid)} return
3453 if {[info exists tagids($sha1string)]} {
3454 set id $tagids($sha1string)
3455 } else {
3456 set id [string tolower $sha1string]
3457 if {[regexp {^[0-9a-f]{4,39}$} $id]} {
3458 set matches {}
3459 for {set l 0} {$l < $numcommits} {incr l} {
3460 if {[string match $id* $lineid($l)]} {
3461 lappend matches $lineid($l)
3462 }
3463 }
3464 if {$matches ne {}} {
3465 if {[llength $matches] > 1} {
3466 error_popup "Short SHA1 id $id is ambiguous"
3467 return
3468 }
3469 set id [lindex $matches 0]
3470 }
3471 }
3472 }
3473 if {[info exists idline($id)]} {
3474 selectline $idline($id) 1
3475 return
3476 }
3477 if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
3478 set type "SHA1 id"
3479 } else {
3480 set type "Tag"
3481 }
3482 error_popup "$type $sha1string is not known"
3483 }
3484
3485 proc lineenter {x y id} {
3486 global hoverx hovery hoverid hovertimer
3487 global commitinfo canv
3488
3489 if {![info exists commitinfo($id)]} return
3490 set hoverx $x
3491 set hovery $y
3492 set hoverid $id
3493 if {[info exists hovertimer]} {
3494 after cancel $hovertimer
3495 }
3496 set hovertimer [after 500 linehover]
3497 $canv delete hover
3498 }
3499
3500 proc linemotion {x y id} {
3501 global hoverx hovery hoverid hovertimer
3502
3503 if {[info exists hoverid] && $id == $hoverid} {
3504 set hoverx $x
3505 set hovery $y
3506 if {[info exists hovertimer]} {
3507 after cancel $hovertimer
3508 }
3509 set hovertimer [after 500 linehover]
3510 }
3511 }
3512
3513 proc lineleave {id} {
3514 global hoverid hovertimer canv
3515
3516 if {[info exists hoverid] && $id == $hoverid} {
3517 $canv delete hover
3518 if {[info exists hovertimer]} {
3519 after cancel $hovertimer
3520 unset hovertimer
3521 }
3522 unset hoverid
3523 }
3524 }
3525
3526 proc linehover {} {
3527 global hoverx hovery hoverid hovertimer
3528 global canv linespc lthickness
3529 global commitinfo mainfont
3530
3531 set text [lindex $commitinfo($hoverid) 0]
3532 set ymax [lindex [$canv cget -scrollregion] 3]
3533 if {$ymax == {}} return
3534 set yfrac [lindex [$canv yview] 0]
3535 set x [expr {$hoverx + 2 * $linespc}]
3536 set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
3537 set x0 [expr {$x - 2 * $lthickness}]
3538 set y0 [expr {$y - 2 * $lthickness}]
3539 set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
3540 set y1 [expr {$y + $linespc + 2 * $lthickness}]
3541 set t [$canv create rectangle $x0 $y0 $x1 $y1 \
3542 -fill \#ffff80 -outline black -width 1 -tags hover]
3543 $canv raise $t
3544 set t [$canv create text $x $y -anchor nw -text $text -tags hover]
3545 $canv raise $t
3546 }
3547
3548 proc clickisonarrow {id y} {
3549 global mainline mainlinearrow sidelines lthickness
3550
3551 set thresh [expr {2 * $lthickness + 6}]
3552 if {[info exists mainline($id)]} {
3553 if {$mainlinearrow($id) ne "none"} {
3554 if {abs([lindex $mainline($id) 1] - $y) < $thresh} {
3555 return "up"
3556 }
3557 }
3558 }
3559 if {[info exists sidelines($id)]} {
3560 foreach ls $sidelines($id) {
3561 set coords [lindex $ls 0]
3562 set arrow [lindex $ls 2]
3563 if {$arrow eq "first" || $arrow eq "both"} {
3564 if {abs([lindex $coords 1] - $y) < $thresh} {
3565 return "up"
3566 }
3567 }
3568 if {$arrow eq "last" || $arrow eq "both"} {
3569 if {abs([lindex $coords end] - $y) < $thresh} {
3570 return "down"
3571 }
3572 }
3573 }
3574 }
3575 return {}
3576 }
3577
3578 proc arrowjump {id dirn y} {
3579 global mainline sidelines canv
3580
3581 set yt {}
3582 if {$dirn eq "down"} {
3583 if {[info exists mainline($id)]} {
3584 set y1 [lindex $mainline($id) 1]
3585 if {$y1 > $y} {
3586 set yt $y1
3587 }
3588 }
3589 if {[info exists sidelines($id)]} {
3590 foreach ls $sidelines($id) {
3591 set y1 [lindex $ls 0 1]
3592 if {$y1 > $y && ($yt eq {} || $y1 < $yt)} {
3593 set yt $y1
3594 }
3595 }
3596 }
3597 } else {
3598 if {[info exists sidelines($id)]} {
3599 foreach ls $sidelines($id) {
3600 set y1 [lindex $ls 0 end]
3601 if {$y1 < $y && ($yt eq {} || $y1 > $yt)} {
3602 set yt $y1
3603 }
3604 }
3605 }
3606 }
3607 if {$yt eq {}} return
3608 set ymax [lindex [$canv cget -scrollregion] 3]
3609 if {$ymax eq {} || $ymax <= 0} return
3610 set view [$canv yview]
3611 set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
3612 set yfrac [expr {$yt / $ymax - $yspan / 2}]
3613 if {$yfrac < 0} {
3614 set yfrac 0
3615 }
3616 $canv yview moveto $yfrac
3617 }
3618
3619 proc lineclick {x y id isnew} {
3620 global ctext commitinfo children cflist canv thickerline
3621
3622 unmarkmatches
3623 unselectline
3624 normalline
3625 $canv delete hover
3626 # draw this line thicker than normal
3627 drawlines $id 1
3628 set thickerline $id
3629 if {$isnew} {
3630 set ymax [lindex [$canv cget -scrollregion] 3]
3631 if {$ymax eq {}} return
3632 set yfrac [lindex [$canv yview] 0]
3633 set y [expr {$y + $yfrac * $ymax}]
3634 }
3635 set dirn [clickisonarrow $id $y]
3636 if {$dirn ne {}} {
3637 arrowjump $id $dirn $y
3638 return
3639 }
3640
3641 if {$isnew} {
3642 addtohistory [list lineclick $x $y $id 0]
3643 }
3644 # fill the details pane with info about this line
3645 $ctext conf -state normal
3646 $ctext delete 0.0 end
3647 $ctext tag conf link -foreground blue -underline 1
3648 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3649 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3650 $ctext insert end "Parent:\t"
3651 $ctext insert end $id [list link link0]
3652 $ctext tag bind link0 <1> [list selbyid $id]
3653 set info $commitinfo($id)
3654 $ctext insert end "\n\t[lindex $info 0]\n"
3655 $ctext insert end "\tUser:\t[lindex $info 1]\n"
3656 $ctext insert end "\tDate:\t[lindex $info 2]\n"
3657 if {[info exists children($id)]} {
3658 $ctext insert end "\nChildren:"
3659 set i 0
3660 foreach child $children($id) {
3661 incr i
3662 set info $commitinfo($child)
3663 $ctext insert end "\n\t"
3664 $ctext insert end $child [list link link$i]
3665 $ctext tag bind link$i <1> [list selbyid $child]
3666 $ctext insert end "\n\t[lindex $info 0]"
3667 $ctext insert end "\n\tUser:\t[lindex $info 1]"
3668 $ctext insert end "\n\tDate:\t[lindex $info 2]\n"
3669 }
3670 }
3671 $ctext conf -state disabled
3672
3673 $cflist delete 0 end
3674 }
3675
3676 proc normalline {} {
3677 global thickerline
3678 if {[info exists thickerline]} {
3679 drawlines $thickerline 0
3680 unset thickerline
3681 }
3682 }
3683
3684 proc selbyid {id} {
3685 global idline
3686 if {[info exists idline($id)]} {
3687 selectline $idline($id) 1
3688 }
3689 }
3690
3691 proc mstime {} {
3692 global startmstime
3693 if {![info exists startmstime]} {
3694 set startmstime [clock clicks -milliseconds]
3695 }
3696 return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
3697 }
3698
3699 proc rowmenu {x y id} {
3700 global rowctxmenu idline selectedline rowmenuid hgvdiff
3701
3702 if {![info exists selectedline] || $idline($id) eq $selectedline} {
3703 set state disabled
3704 } else {
3705 set state normal
3706 }
3707 $rowctxmenu entryconfigure 0 -state $state
3708 $rowctxmenu entryconfigure 1 -state $state
3709 $rowctxmenu entryconfigure 2 -state $state
3710 if { $hgvdiff ne "" } {
3711 $rowctxmenu entryconfigure 6 -state $state
3712 }
3713 set rowmenuid $id
3714 tk_popup $rowctxmenu $x $y
3715 }
3716
3717 proc diffvssel {dirn} {
3718 global rowmenuid selectedline lineid
3719
3720 if {![info exists selectedline]} return
3721 if {$dirn} {
3722 set oldid $lineid($selectedline)
3723 set newid $rowmenuid
3724 } else {
3725 set oldid $rowmenuid
3726 set newid $lineid($selectedline)
3727 }
3728 addtohistory [list doseldiff $oldid $newid]
3729 doseldiff $oldid $newid
3730 }
3731
3732 proc doseldiff {oldid newid} {
3733 global ctext cflist
3734 global commitinfo
3735
3736 $ctext conf -state normal
3737 $ctext delete 0.0 end
3738 $ctext mark set fmark.0 0.0
3739 $ctext mark gravity fmark.0 left
3740 $cflist delete 0 end
3741 $cflist insert end "Top"
3742 $ctext insert end "From "
3743 $ctext tag conf link -foreground blue -underline 1
3744 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3745 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3746 $ctext tag bind link0 <1> [list selbyid $oldid]
3747 $ctext insert end $oldid [list link link0]
3748 $ctext insert end "\n "
3749 $ctext insert end [lindex $commitinfo($oldid) 0]
3750 $ctext insert end "\n\nTo "
3751 $ctext tag bind link1 <1> [list selbyid $newid]
3752 $ctext insert end $newid [list link link1]
3753 $ctext insert end "\n "
3754 $ctext insert end [lindex $commitinfo($newid) 0]
3755 $ctext insert end "\n"
3756 $ctext conf -state disabled
3757 $ctext tag delete Comments
3758 $ctext tag remove found 1.0 end
3759 startdiff [list $newid $oldid]
3760 }
3761
3762 proc mkpatch {} {
3763 global rowmenuid currentid commitinfo patchtop patchnum
3764
3765 if {![info exists currentid]} return
3766 set oldid $currentid
3767 set oldhead [lindex $commitinfo($oldid) 0]
3768 set newid $rowmenuid
3769 set newhead [lindex $commitinfo($newid) 0]
3770 set top .patch
3771 set patchtop $top
3772 catch {destroy $top}
3773 toplevel $top
3774 ttk::label $top.from -text "From:"
3775 ttk::entry $top.fromsha1 -width 40
3776 $top.fromsha1 insert 0 $oldid
3777 $top.fromsha1 conf -state readonly
3778 grid $top.from $top.fromsha1 -sticky w -pady {10 0}
3779 ttk::entry $top.fromhead -width 60
3780 $top.fromhead insert 0 $oldhead
3781 $top.fromhead conf -state readonly
3782 grid x $top.fromhead -sticky w
3783 ttk::label $top.to -text "To:"
3784 ttk::entry $top.tosha1 -width 40
3785 $top.tosha1 insert 0 $newid
3786 $top.tosha1 conf -state readonly
3787 grid $top.to $top.tosha1 -sticky w
3788 ttk::entry $top.tohead -width 60
3789 $top.tohead insert 0 $newhead
3790 $top.tohead conf -state readonly
3791 grid x $top.tohead -sticky w
3792 ttk::button $top.rev -text "Reverse" -command mkpatchrev
3793 grid $top.rev x -pady 10
3794 ttk::label $top.flab -text "Output file:"
3795 ttk::entry $top.fname -width 60
3796 $top.fname insert 0 [file normalize "patch$patchnum.patch"]
3797 incr patchnum
3798 grid $top.flab $top.fname -sticky w
3799 ttk::frame $top.buts
3800 ttk::button $top.buts.gen -text "Generate" -command mkpatchgo
3801 ttk::button $top.buts.can -text "Cancel" -command mkpatchcan
3802 grid $top.buts.gen $top.buts.can
3803 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3804 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3805 grid $top.buts - -pady 10 -sticky ew
3806 focus $top.fname
3807 popupify $top
3808 wm title $top "Generate a patch"
3809 }
3810
3811 proc mkpatchrev {} {
3812 global patchtop
3813
3814 set oldid [$patchtop.fromsha1 get]
3815 set oldhead [$patchtop.fromhead get]
3816 set newid [$patchtop.tosha1 get]
3817 set newhead [$patchtop.tohead get]
3818 foreach e [list fromsha1 fromhead tosha1 tohead] \
3819 v [list $newid $newhead $oldid $oldhead] {
3820 $patchtop.$e conf -state normal
3821 $patchtop.$e delete 0 end
3822 $patchtop.$e insert 0 $v
3823 $patchtop.$e conf -state readonly
3824 }
3825 }
3826
3827 proc mkpatchgo {} {
3828 global patchtop env
3829
3830 set oldid [$patchtop.fromsha1 get]
3831 set newid [$patchtop.tosha1 get]
3832 set fname [$patchtop.fname get]
3833 if {[catch {exec $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $oldid $newid >$fname &} err]} {
3834 error_popup "Error creating patch: $err"
3835 }
3836 catch {destroy $patchtop}
3837 unset patchtop
3838 }
3839
3840 proc mkpatchcan {} {
3841 global patchtop
3842
3843 catch {destroy $patchtop}
3844 unset patchtop
3845 }
3846
3847 proc mktag {} {
3848 global rowmenuid mktagtop commitinfo
3849
3850 set top .maketag
3851 set mktagtop $top
3852 catch {destroy $top}
3853 toplevel $top
3854 ttk::label $top.id -text "ID:"
3855 ttk::entry $top.sha1 -width 40
3856 $top.sha1 insert 0 $rowmenuid
3857 $top.sha1 conf -state readonly
3858 grid $top.id $top.sha1 -sticky w -pady {10 0}
3859 ttk::entry $top.head -width 60
3860 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3861 $top.head conf -state readonly
3862 grid x $top.head -sticky w
3863 ttk::label $top.tlab -text "Tag name:"
3864 ttk::entry $top.tag -width 60
3865 grid $top.tlab $top.tag -sticky w
3866 ttk::frame $top.buts
3867 ttk::button $top.buts.gen -text "Create" -command mktaggo
3868 ttk::button $top.buts.can -text "Cancel" -command mktagcan
3869 grid $top.buts.gen $top.buts.can
3870 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3871 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3872 grid $top.buts - -pady 10 -sticky ew
3873 focus $top.tag
3874 popupify $top
3875 wm title $top "Create a tag"
3876 }
3877
3878 proc domktag {} {
3879 global mktagtop env tagids idtags
3880
3881 set id [$mktagtop.sha1 get]
3882 set tag [$mktagtop.tag get]
3883 if {$tag == {}} {
3884 error_popup "No tag name specified"
3885 return
3886 }
3887 if {[info exists tagids($tag)]} {
3888 error_popup "Tag \"$tag\" already exists"
3889 return
3890 }
3891 if {[catch {
3892 set out [exec $env(HG) --config ui.report_untrusted=false tag -r $id $tag]
3893 } err]} {
3894 error_popup "Error creating tag: $err"
3895 return
3896 }
3897
3898 set tagids($tag) $id
3899 lappend idtags($id) $tag
3900 redrawtags $id
3901 }
3902
3903 proc redrawtags {id} {
3904 global canv linehtag idline idpos selectedline
3905
3906 if {![info exists idline($id)]} return
3907 $canv delete tag.$id
3908 set xt [eval drawtags $id $idpos($id)]
3909 $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
3910 if {[info exists selectedline] && $selectedline == $idline($id)} {
3911 selectline $selectedline 0
3912 }
3913 }
3914
3915 proc mktagcan {} {
3916 global mktagtop
3917
3918 catch {destroy $mktagtop}
3919 unset mktagtop
3920 }
3921
3922 proc mktaggo {} {
3923 domktag
3924 mktagcan
3925 }
3926
3927 proc writecommit {} {
3928 global rowmenuid wrcomtop commitinfo
3929
3930 set top .writecommit
3931 set wrcomtop $top
3932 catch {destroy $top}
3933 toplevel $top
3934 ttk::label $top.id -text "ID:"
3935 ttk::entry $top.sha1 -width 40
3936 $top.sha1 insert 0 $rowmenuid
3937 $top.sha1 conf -state readonly
3938 grid $top.id $top.sha1 -sticky w -pady {10 0}
3939 ttk::entry $top.head -width 60
3940 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3941 $top.head conf -state readonly
3942 grid x $top.head -sticky w
3943 ttk::label $top.flab -text "Output file:"
3944 ttk::entry $top.fname -width 60
3945 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6].diff"]
3946 grid $top.flab $top.fname -sticky w
3947 ttk::frame $top.buts
3948 ttk::button $top.buts.gen -text "Write" -command wrcomgo
3949 ttk::button $top.buts.can -text "Cancel" -command wrcomcan
3950 grid $top.buts.gen $top.buts.can
3951 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3952 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3953 grid $top.buts - -pady 10 -sticky ew
3954 focus $top.fname
3955 popupify $top
3956 wm title $top "Write commit to a file"
3957 }
3958
3959 proc wrcomgo {} {
3960 global wrcomtop
3961
3962 set id [$wrcomtop.sha1 get]
3963 set fname [$wrcomtop.fname get]
3964 if {[catch {exec $::env(HG) --config ui.report_untrusted=false export --git -o [string map {% %%} $fname] $id} err]} {
3965 error_popup "Error writing commit: $err"
3966 }
3967 catch {destroy $wrcomtop}
3968 unset wrcomtop
3969 }
3970
3971 proc wrcomcan {} {
3972 global wrcomtop
3973
3974 catch {destroy $wrcomtop}
3975 unset wrcomtop
3976 }
3977
3978 proc listrefs {id} {
3979 global idtags idheads idotherrefs idbookmarks
3980
3981 set w {}
3982 if {[info exists idbookmarks($id)]} {
3983 set w $idbookmarks($id)
3984 }
3985 set x {}
3986 if {[info exists idtags($id)]} {
3987 set x $idtags($id)
3988 }
3989 set y {}
3990 if {[info exists idheads($id)]} {
3991 set y $idheads($id)
3992 }
3993 set z {}
3994 if {[info exists idotherrefs($id)]} {
3995 set z $idotherrefs($id)
3996 }
3997 return [list $w $x $y $z]
3998 }
3999
4000 proc rereadrefs {} {
4001 global idbookmarks idtags idheads idotherrefs
4002 global bookmarkids tagids headids otherrefids
4003
4004 set refids [concat [array names idtags] \
4005 [array names idheads] [array names idotherrefs] \
4006 [array names idbookmarks]]
4007 foreach id $refids {
4008 if {![info exists ref($id)]} {
4009 set ref($id) [listrefs $id]
4010 }
4011 }
4012 foreach v {tagids idtags headids idheads otherrefids idotherrefs \
4013 bookmarkids idbookmarks} {
4014 catch {unset $v}
4015 }
4016 readrefs
4017 set refids [lsort -unique [concat $refids [array names idtags] \
4018 [array names idheads] [array names idotherrefs] \
4019 [array names idbookmarks]]]
4020 foreach id $refids {
4021 set v [listrefs $id]
4022 if {![info exists ref($id)] || $ref($id) != $v} {
4023 redrawtags $id
4024 }
4025 }
4026 }
4027
4028 proc vdiff {withparent} {
4029 global env rowmenuid selectedline lineid hgvdiff
4030
4031 if {![info exists rowmenuid]} return
4032 set curid $rowmenuid
4033
4034 if {$withparent} {
4035 set parents [exec $env(HG) --config ui.report_untrusted=false parents --rev $curid --template "{node}\n"]
4036 set firstparent [lindex [split $parents "\n"] 0]
4037 set otherid $firstparent
4038 } else {
4039 if {![info exists selectedline]} return
4040 set otherid $lineid($selectedline)
4041 }
4042 set range "$otherid:$curid"
4043 if {[catch {exec $env(HG) --config ui.report_untrusted=false $hgvdiff -r $range} err]} {
4044 # Ignore errors, this is just visualization
4045 }
4046 }
4047
4048 proc showtag {tag isnew} {
4049 global ctext cflist tagcontents tagids linknum
4050
4051 if {$isnew} {
4052 addtohistory [list showtag $tag 0]
4053 }
4054 $ctext conf -state normal
4055 $ctext delete 0.0 end
4056 set linknum 0
4057 if {[info exists tagcontents($tag)]} {
4058 set text $tagcontents($tag)
4059 } else {
4060 set text "Tag: $tag\nId: $tagids($tag)"
4061 }
4062 appendwithlinks $text
4063 $ctext conf -state disabled
4064 $cflist delete 0 end
4065 }
4066
4067 proc doquit {} {
4068 global stopped
4069 set stopped 100
4070 destroy .
4071 }
4072
4073 proc getconfig {} {
4074 global env
4075 set config {}
4076
4077 set lines [exec $env(HG) debugconfig]
4078 foreach line [split $lines \n] {
4079 set line [string trimright $line \r]
4080 if {[string match hgk.* $line]} {
4081 regexp {(.*)=(.*)} $line - k v
4082 lappend config $k $v
4083 }
4084 }
4085 return $config
4086 }
4087
4088 # defaults...
4089 set datemode 0
4090 set boldnames 0
4091 set diffopts "-U 5 -p"
4092
4093 set mainfont {Helvetica 9}
4094 set curidfont {}
4095 set textfont {Courier 9}
4096 set findmergefiles 0
4097 set gaudydiff 0
4098 set maxgraphpct 50
4099 set maxwidth 16
4100
4101 set colors {green red blue magenta darkgrey brown orange}
4102 set authorcolors {
4103 black blue deeppink mediumorchid blue burlywood4 goldenrod slateblue red2 navy dimgrey
4104 }
4105 set bgcolor white
4106
4107 # This color should probably be some system color (provided by tk),
4108 # but as the bgcolor has always been set to white, I choose to ignore
4109 set fgcolor black
4110 set diffaddcolor "#00a000"
4111 set diffremcolor red
4112 set diffmerge1color red
4113 set diffmerge2color blue
4114 set hunksepcolor blue
4115
4116 catch {source ~/.hgk}
4117
4118 if {$curidfont == ""} { # initialize late based on current mainfont
4119 set curidfont "$mainfont bold italic underline"
4120 }
4121
4122 set namefont $mainfont
4123 if {$boldnames} {
4124 lappend namefont bold
4125 }
4126
4127 set revtreeargs {}
4128 foreach arg $argv {
4129 switch -regexp -- $arg {
4130 "^$" { }
4131 "^-b" { set boldnames 1 }
4132 "^-d" { set datemode 1 }
4133 default {
4134 lappend revtreeargs $arg
4135 }
4136 }
4137 }
4138
4139 set history {}
4140 set historyindex 0
4141
4142 set stopped 0
4143 set redisplaying 0
4144 set stuffsaved 0
4145 set patchnum 0
4146
4147 set config(hgk.vdiff) ""
4148 array set config [getconfig]
4149 set hgvdiff $config(hgk.vdiff)
4150 setcoords
4151 makewindow
4152 readrefs
4153 set hgroot [exec $env(HG) root]
4154 wm title . "hgk $hgroot"
4155 getcommits $revtreeargs
@@ -0,0 +1,97 b''
1 #!/usr/bin/env python
2 #
3 # hgperf - measure performance of Mercurial commands
4 #
5 # Copyright 2014 Matt Mackall <mpm@selenic.com>
6 #
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
9
10 '''measure performance of Mercurial commands
11
12 Using ``hgperf`` instead of ``hg`` measures performance of the target
13 Mercurial command. For example, the execution below measures
14 performance of :hg:`heads --topo`::
15
16 $ hgperf heads --topo
17
18 All command output via ``ui`` is suppressed, and just measurement
19 result is displayed: see also "perf" extension in "contrib".
20
21 Costs of processing before dispatching to the command function like
22 below are not measured::
23
24 - parsing command line (e.g. option validity check)
25 - reading configuration files in
26
27 But ``pre-`` and ``post-`` hook invocation for the target command is
28 measured, even though these are invoked before or after dispatching to
29 the command function, because these may be required to repeat
30 execution of the target command correctly.
31 '''
32
33 import os
34 import sys
35
36 libdir = '@LIBDIR@'
37
38 if libdir != '@' 'LIBDIR' '@':
39 if not os.path.isabs(libdir):
40 libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)),
41 libdir)
42 libdir = os.path.abspath(libdir)
43 sys.path.insert(0, libdir)
44
45 # enable importing on demand to reduce startup time
46 try:
47 from mercurial import demandimport; demandimport.enable()
48 except ImportError:
49 import sys
50 sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" %
51 ' '.join(sys.path))
52 sys.stderr.write("(check your install and PYTHONPATH)\n")
53 sys.exit(-1)
54
55 from mercurial import (
56 dispatch,
57 util,
58 )
59
60 def timer(func, title=None):
61 results = []
62 begin = util.timer()
63 count = 0
64 while True:
65 ostart = os.times()
66 cstart = util.timer()
67 r = func()
68 cstop = util.timer()
69 ostop = os.times()
70 count += 1
71 a, b = ostart, ostop
72 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
73 if cstop - begin > 3 and count >= 100:
74 break
75 if cstop - begin > 10 and count >= 3:
76 break
77 if title:
78 sys.stderr.write("! %s\n" % title)
79 if r:
80 sys.stderr.write("! result: %s\n" % r)
81 m = min(results)
82 sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n"
83 % (m[0], m[1] + m[2], m[1], m[2], count))
84
85 orgruncommand = dispatch.runcommand
86
87 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
88 ui.pushbuffer()
89 lui.pushbuffer()
90 timer(lambda : orgruncommand(lui, repo, cmd, fullargs, ui,
91 options, d, cmdpats, cmdoptions))
92 ui.popbuffer()
93 lui.popbuffer()
94
95 dispatch.runcommand = runcommand
96
97 dispatch.run()
@@ -0,0 +1,13 b''
1 CC := gcc
2 CFLAGS := -g -O2 -Wall -Werror
3
4 prefix ?= /usr/bin
5
6 hgsh: hgsh.o
7 $(CC) -o $@ $<
8
9 install: hgsh
10 install -m755 hgsh $(prefix)
11
12 clean:
13 rm -f *.o hgsh
@@ -0,0 +1,438 b''
1 /*
2 * hgsh.c - restricted login shell for mercurial
3 *
4 * Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 *
6 * This software may be used and distributed according to the terms of the
7 * GNU General Public License, incorporated herein by reference.
8 *
9 * this program is login shell for dedicated mercurial user account. it
10 * only allows few actions:
11 *
12 * 1. run hg in server mode on specific repository. no other hg commands
13 * are allowed. we try to verify that repo to be accessed exists under
14 * given top-level directory.
15 *
16 * 2. (optional) forward ssh connection from firewall/gateway machine to
17 * "real" mercurial host, to let users outside intranet pull and push
18 * changes through firewall.
19 *
20 * 3. (optional) run normal shell, to allow to "su" to mercurial user, use
21 * "sudo" to run programs as that user, or run cron jobs as that user.
22 *
23 * only tested on linux yet. patches for non-linux systems welcome.
24 */
25
26 #ifndef _GNU_SOURCE
27 #define _GNU_SOURCE /* for asprintf */
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sysexits.h>
36 #include <unistd.h>
37
38 /*
39 * user config.
40 *
41 * if you see a hostname below, just use first part of hostname. example,
42 * if you have host named foo.bar.com, use "foo".
43 */
44
45 /*
46 * HG_GATEWAY: hostname of gateway/firewall machine that people outside your
47 * intranet ssh into if they need to ssh to other machines. if you do not
48 * have such machine, set to NULL.
49 */
50 #ifndef HG_GATEWAY
51 #define HG_GATEWAY "gateway"
52 #endif
53
54 /*
55 * HG_HOST: hostname of mercurial server. if any machine is allowed, set to
56 * NULL.
57 */
58 #ifndef HG_HOST
59 #define HG_HOST "mercurial"
60 #endif
61
62 /*
63 * HG_USER: username to log in from HG_GATEWAY to HG_HOST. if gateway and
64 * host username are same, set to NULL.
65 */
66 #ifndef HG_USER
67 #define HG_USER "hg"
68 #endif
69
70 /*
71 * HG_ROOT: root of tree full of mercurial repos. if you do not want to
72 * validate location of repo when someone is try to access, set to NULL.
73 */
74 #ifndef HG_ROOT
75 #define HG_ROOT "/home/hg/repos"
76 #endif
77
78 /*
79 * HG: path to the mercurial executable to run.
80 */
81 #ifndef HG
82 #define HG "/home/hg/bin/hg"
83 #endif
84
85 /*
86 * HG_SHELL: shell to use for actions like "sudo" and "su" access to
87 * mercurial user, and cron jobs. if you want to make these things
88 * impossible, set to NULL.
89 */
90 #ifndef HG_SHELL
91 #define HG_SHELL NULL
92 /* #define HG_SHELL "/bin/bash" */
93 #endif
94
95 /*
96 * HG_HELP: some way for users to get support if they have problem. if they
97 * should not get helpful message, set to NULL.
98 */
99 #ifndef HG_HELP
100 #define HG_HELP "please contact support@example.com for help."
101 #endif
102
103 /*
104 * SSH: path to ssh executable to run, if forwarding from HG_GATEWAY to
105 * HG_HOST. if you want to use rsh instead (why?), you need to modify
106 * arguments it is called with. see forward_through_gateway.
107 */
108 #ifndef SSH
109 #define SSH "/usr/bin/ssh"
110 #endif
111
112 /*
113 * tell whether to print command that is to be executed. useful for
114 * debugging. should not interfere with mercurial operation, since
115 * mercurial only cares about stdin and stdout, and this prints to stderr.
116 */
117 static const int debug = 0;
118
119 static void print_cmdline(int argc, char **argv)
120 {
121 FILE *fp = stderr;
122 int i;
123
124 fputs("command: ", fp);
125
126 for (i = 0; i < argc; i++) {
127 char *spc = strpbrk(argv[i], " \t\r\n");
128 if (spc) {
129 fputc('\'', fp);
130 }
131 fputs(argv[i], fp);
132 if (spc) {
133 fputc('\'', fp);
134 }
135 if (i < argc - 1) {
136 fputc(' ', fp);
137 }
138 }
139 fputc('\n', fp);
140 fflush(fp);
141 }
142
143 static void usage(const char *reason, int exitcode)
144 {
145 char *hg_help = HG_HELP;
146
147 if (reason) {
148 fprintf(stderr, "*** Error: %s.\n", reason);
149 }
150 fprintf(stderr, "*** This program has been invoked incorrectly.\n");
151 if (hg_help) {
152 fprintf(stderr, "*** %s\n", hg_help);
153 }
154 exit(exitcode ? exitcode : EX_USAGE);
155 }
156
157 /*
158 * run on gateway host to make another ssh connection, to "real" mercurial
159 * server. it sends its command line unmodified to far end.
160 *
161 * never called if HG_GATEWAY is NULL.
162 */
163 static void forward_through_gateway(int argc, char **argv)
164 {
165 char *ssh = SSH;
166 char *hg_host = HG_HOST;
167 char *hg_user = HG_USER;
168 char **nargv = alloca((10 + argc) * sizeof(char *));
169 int i = 0, j;
170
171 nargv[i++] = ssh;
172 nargv[i++] = "-q";
173 nargv[i++] = "-T";
174 nargv[i++] = "-x";
175 if (hg_user) {
176 nargv[i++] = "-l";
177 nargv[i++] = hg_user;
178 }
179 nargv[i++] = hg_host;
180
181 /*
182 * sshd called us with added "-c", because it thinks we are a shell.
183 * drop it if we find it.
184 */
185 j = 1;
186 if (j < argc && strcmp(argv[j], "-c") == 0) {
187 j++;
188 }
189
190 for (; j < argc; i++, j++) {
191 nargv[i] = argv[j];
192 }
193 nargv[i] = NULL;
194
195 if (debug) {
196 print_cmdline(i, nargv);
197 }
198
199 execv(ssh, nargv);
200 perror(ssh);
201 exit(EX_UNAVAILABLE);
202 }
203
204 /*
205 * run shell. let administrator "su" to mercurial user's account to do
206 * administrative works.
207 *
208 * never called if HG_SHELL is NULL.
209 */
210 static void run_shell(int argc, char **argv)
211 {
212 char *hg_shell = HG_SHELL;
213 char **nargv;
214 char *c;
215 int i;
216
217 nargv = alloca((argc + 3) * sizeof(char *));
218 c = strrchr(hg_shell, '/');
219
220 /* tell "real" shell it is login shell, if needed. */
221
222 if (argv[0][0] == '-' && c) {
223 nargv[0] = strdup(c);
224 if (nargv[0] == NULL) {
225 perror("malloc");
226 exit(EX_OSERR);
227 }
228 nargv[0][0] = '-';
229 } else {
230 nargv[0] = hg_shell;
231 }
232
233 for (i = 1; i < argc; i++) {
234 nargv[i] = argv[i];
235 }
236 nargv[i] = NULL;
237
238 if (debug) {
239 print_cmdline(i, nargv);
240 }
241
242 execv(hg_shell, nargv);
243 perror(hg_shell);
244 exit(EX_OSFILE);
245 }
246
247 enum cmdline {
248 hg_init,
249 hg_serve,
250 };
251
252 /*
253 * attempt to verify that a directory is really a hg repo, by testing
254 * for the existence of a subdirectory.
255 */
256 static int validate_repo(const char *repo_root, const char *subdir)
257 {
258 char *abs_path;
259 struct stat st;
260 int ret;
261
262 if (asprintf(&abs_path, "%s.hg/%s", repo_root, subdir) == -1) {
263 ret = -1;
264 goto bail;
265 }
266
267 /* verify that we really are looking at valid repo. */
268
269 if (stat(abs_path, &st) == -1) {
270 ret = 0;
271 } else {
272 ret = 1;
273 }
274
275 bail:
276 return ret;
277 }
278
279 /*
280 * paranoid wrapper, runs hg executable in server mode.
281 */
282 static void serve_data(int argc, char **argv)
283 {
284 char *hg_root = HG_ROOT;
285 char *repo, *repo_root;
286 enum cmdline cmd;
287 char *nargv[6];
288 size_t repolen;
289 int i;
290
291 /*
292 * check argv for looking okay. we should be invoked with argv
293 * resembling like this:
294 *
295 * hgsh
296 * -c
297 * hg -R some/path serve --stdio
298 *
299 * the "-c" is added by sshd, because it thinks we are login shell.
300 */
301
302 if (argc != 3) {
303 goto badargs;
304 }
305
306 if (strcmp(argv[1], "-c") != 0) {
307 goto badargs;
308 }
309
310 if (sscanf(argv[2], "hg init %as", &repo) == 1) {
311 cmd = hg_init;
312 } else if (sscanf(argv[2], "hg -R %as serve --stdio", &repo) == 1) {
313 cmd = hg_serve;
314 } else {
315 goto badargs;
316 }
317
318 repolen = repo ? strlen(repo) : 0;
319
320 if (repolen == 0) {
321 goto badargs;
322 }
323
324 if (hg_root) {
325 if (asprintf(&repo_root, "%s/%s/", hg_root, repo) == -1) {
326 goto badargs;
327 }
328
329 /*
330 * attempt to stop break out from inside the
331 * repository tree. could do something more clever
332 * here, because e.g. we could traverse a symlink that
333 * looks safe, but really breaks us out of tree.
334 */
335
336 if (strstr(repo_root, "/../") != NULL) {
337 goto badargs;
338 }
339
340 /* only hg init expects no repo. */
341
342 if (cmd != hg_init) {
343 int valid;
344
345 valid = validate_repo(repo_root, "data");
346
347 if (valid == -1) {
348 goto badargs;
349 }
350
351 if (valid == 0) {
352 valid = validate_repo(repo_root, "store");
353
354 if (valid == -1) {
355 goto badargs;
356 }
357 }
358
359 if (valid == 0) {
360 perror(repo);
361 exit(EX_DATAERR);
362 }
363 }
364
365 if (chdir(hg_root) == -1) {
366 perror(hg_root);
367 exit(EX_SOFTWARE);
368 }
369 }
370
371 i = 0;
372
373 switch (cmd) {
374 case hg_serve:
375 nargv[i++] = HG;
376 nargv[i++] = "-R";
377 nargv[i++] = repo;
378 nargv[i++] = "serve";
379 nargv[i++] = "--stdio";
380 break;
381 case hg_init:
382 nargv[i++] = HG;
383 nargv[i++] = "init";
384 nargv[i++] = repo;
385 break;
386 }
387
388 nargv[i] = NULL;
389
390 if (debug) {
391 print_cmdline(i, nargv);
392 }
393
394 execv(HG, nargv);
395 perror(HG);
396 exit(EX_UNAVAILABLE);
397
398 badargs:
399 /* print useless error message. */
400
401 usage("invalid arguments", EX_DATAERR);
402 }
403
404 int main(int argc, char **argv)
405 {
406 char host[1024];
407 char *c;
408
409 if (gethostname(host, sizeof(host)) == -1) {
410 perror("gethostname");
411 exit(EX_OSERR);
412 }
413
414 if ((c = strchr(host, '.')) != NULL) {
415 *c = '\0';
416 }
417
418 if (getenv("SSH_CLIENT")) {
419 char *hg_gateway = HG_GATEWAY;
420 char *hg_host = HG_HOST;
421
422 if (hg_gateway && strcmp(host, hg_gateway) == 0) {
423 forward_through_gateway(argc, argv);
424 }
425
426 if (hg_host && strcmp(host, hg_host) != 0) {
427 usage("invoked on unexpected host", EX_USAGE);
428 }
429
430 serve_data(argc, argv);
431 } else if (HG_SHELL) {
432 run_shell(argc, argv);
433 } else {
434 usage("invalid arguments", EX_DATAERR);
435 }
436
437 return 0;
438 }
@@ -0,0 +1,19 b''
1 #!/usr/bin/env python
2 #
3 # An example FastCGI script for use with flup, edit as necessary
4
5 # Path to repo or hgweb config to serve (see 'hg help hgweb')
6 config = "/path/to/repo/or/config"
7
8 # Uncomment and adjust if Mercurial is not installed system-wide
9 # (consult "installed modules" path from 'hg debuginstall'):
10 #import sys; sys.path.insert(0, "/path/to/python/lib")
11
12 # Uncomment to send python tracebacks to the browser if an error occurs:
13 #import cgitb; cgitb.enable()
14
15 from mercurial import demandimport; demandimport.enable()
16 from mercurial.hgweb import hgweb
17 from flup.server.fcgi import WSGIServer
18 application = hgweb(config)
19 WSGIServer(application).run()
@@ -0,0 +1,18 b''
1 # An example WSGI for use with mod_wsgi, edit as necessary
2 # See https://mercurial-scm.org/wiki/modwsgi for more information
3
4 # Path to repo or hgweb config to serve (see 'hg help hgweb')
5 config = "/path/to/repo/or/config"
6
7 # Uncomment and adjust if Mercurial is not installed system-wide
8 # (consult "installed modules" path from 'hg debuginstall'):
9 #import sys; sys.path.insert(0, "/path/to/python/lib")
10
11 # Uncomment to send python tracebacks to the browser if an error occurs:
12 #import cgitb; cgitb.enable()
13
14 # enable demandloading to reduce startup time
15 from mercurial import demandimport; demandimport.enable()
16
17 from mercurial.hgweb import hgweb
18 application = hgweb(config)
This diff has been collapsed as it changes many lines, (781 lines changed) Show them Hide them
@@ -0,0 +1,781 b''
1 #!/usr/bin/env python
2
3 from __future__ import absolute_import, print_function
4
5 import ast
6 import collections
7 import os
8 import re
9 import sys
10
11 # Import a minimal set of stdlib modules needed for list_stdlib_modules()
12 # to work when run from a virtualenv. The modules were chosen empirically
13 # so that the return value matches the return value without virtualenv.
14 if True: # disable lexical sorting checks
15 try:
16 import BaseHTTPServer as basehttpserver
17 except ImportError:
18 basehttpserver = None
19 import zlib
20
21 # Whitelist of modules that symbols can be directly imported from.
22 allowsymbolimports = (
23 '__future__',
24 'bzrlib',
25 'hgclient',
26 'mercurial',
27 'mercurial.hgweb.common',
28 'mercurial.hgweb.request',
29 'mercurial.i18n',
30 'mercurial.node',
31 # for cffi modules to re-export pure functions
32 'mercurial.pure.base85',
33 'mercurial.pure.bdiff',
34 'mercurial.pure.mpatch',
35 'mercurial.pure.osutil',
36 'mercurial.pure.parsers',
37 # third-party imports should be directly imported
38 'mercurial.thirdparty',
39 'mercurial.thirdparty.cbor',
40 'mercurial.thirdparty.cbor.cbor2',
41 'mercurial.thirdparty.zope',
42 'mercurial.thirdparty.zope.interface',
43 )
44
45 # Whitelist of symbols that can be directly imported.
46 directsymbols = (
47 'demandimport',
48 )
49
50 # Modules that must be aliased because they are commonly confused with
51 # common variables and can create aliasing and readability issues.
52 requirealias = {
53 'ui': 'uimod',
54 }
55
56 def usingabsolute(root):
57 """Whether absolute imports are being used."""
58 if sys.version_info[0] >= 3:
59 return True
60
61 for node in ast.walk(root):
62 if isinstance(node, ast.ImportFrom):
63 if node.module == '__future__':
64 for n in node.names:
65 if n.name == 'absolute_import':
66 return True
67
68 return False
69
70 def walklocal(root):
71 """Recursively yield all descendant nodes but not in a different scope"""
72 todo = collections.deque(ast.iter_child_nodes(root))
73 yield root, False
74 while todo:
75 node = todo.popleft()
76 newscope = isinstance(node, ast.FunctionDef)
77 if not newscope:
78 todo.extend(ast.iter_child_nodes(node))
79 yield node, newscope
80
81 def dotted_name_of_path(path):
82 """Given a relative path to a source file, return its dotted module name.
83
84 >>> dotted_name_of_path('mercurial/error.py')
85 'mercurial.error'
86 >>> dotted_name_of_path('zlibmodule.so')
87 'zlib'
88 """
89 parts = path.replace(os.sep, '/').split('/')
90 parts[-1] = parts[-1].split('.', 1)[0] # remove .py and .so and .ARCH.so
91 if parts[-1].endswith('module'):
92 parts[-1] = parts[-1][:-6]
93 return '.'.join(parts)
94
95 def fromlocalfunc(modulename, localmods):
96 """Get a function to examine which locally defined module the
97 target source imports via a specified name.
98
99 `modulename` is an `dotted_name_of_path()`-ed source file path,
100 which may have `.__init__` at the end of it, of the target source.
101
102 `localmods` is a set of absolute `dotted_name_of_path()`-ed source file
103 paths of locally defined (= Mercurial specific) modules.
104
105 This function assumes that module names not existing in
106 `localmods` are from the Python standard library.
107
108 This function returns the function, which takes `name` argument,
109 and returns `(absname, dottedpath, hassubmod)` tuple if `name`
110 matches against locally defined module. Otherwise, it returns
111 False.
112
113 It is assumed that `name` doesn't have `.__init__`.
114
115 `absname` is an absolute module name of specified `name`
116 (e.g. "hgext.convert"). This can be used to compose prefix for sub
117 modules or so.
118
119 `dottedpath` is a `dotted_name_of_path()`-ed source file path
120 (e.g. "hgext.convert.__init__") of `name`. This is used to look
121 module up in `localmods` again.
122
123 `hassubmod` is whether it may have sub modules under it (for
124 convenient, even though this is also equivalent to "absname !=
125 dottednpath")
126
127 >>> localmods = {'foo.__init__', 'foo.foo1',
128 ... 'foo.bar.__init__', 'foo.bar.bar1',
129 ... 'baz.__init__', 'baz.baz1'}
130 >>> fromlocal = fromlocalfunc('foo.xxx', localmods)
131 >>> # relative
132 >>> fromlocal('foo1')
133 ('foo.foo1', 'foo.foo1', False)
134 >>> fromlocal('bar')
135 ('foo.bar', 'foo.bar.__init__', True)
136 >>> fromlocal('bar.bar1')
137 ('foo.bar.bar1', 'foo.bar.bar1', False)
138 >>> # absolute
139 >>> fromlocal('baz')
140 ('baz', 'baz.__init__', True)
141 >>> fromlocal('baz.baz1')
142 ('baz.baz1', 'baz.baz1', False)
143 >>> # unknown = maybe standard library
144 >>> fromlocal('os')
145 False
146 >>> fromlocal(None, 1)
147 ('foo', 'foo.__init__', True)
148 >>> fromlocal('foo1', 1)
149 ('foo.foo1', 'foo.foo1', False)
150 >>> fromlocal2 = fromlocalfunc('foo.xxx.yyy', localmods)
151 >>> fromlocal2(None, 2)
152 ('foo', 'foo.__init__', True)
153 >>> fromlocal2('bar2', 1)
154 False
155 >>> fromlocal2('bar', 2)
156 ('foo.bar', 'foo.bar.__init__', True)
157 """
158 if not isinstance(modulename, str):
159 modulename = modulename.decode('ascii')
160 prefix = '.'.join(modulename.split('.')[:-1])
161 if prefix:
162 prefix += '.'
163 def fromlocal(name, level=0):
164 # name is false value when relative imports are used.
165 if not name:
166 # If relative imports are used, level must not be absolute.
167 assert level > 0
168 candidates = ['.'.join(modulename.split('.')[:-level])]
169 else:
170 if not level:
171 # Check relative name first.
172 candidates = [prefix + name, name]
173 else:
174 candidates = ['.'.join(modulename.split('.')[:-level]) +
175 '.' + name]
176
177 for n in candidates:
178 if n in localmods:
179 return (n, n, False)
180 dottedpath = n + '.__init__'
181 if dottedpath in localmods:
182 return (n, dottedpath, True)
183 return False
184 return fromlocal
185
186 def populateextmods(localmods):
187 """Populate C extension modules based on pure modules"""
188 newlocalmods = set(localmods)
189 for n in localmods:
190 if n.startswith('mercurial.pure.'):
191 m = n[len('mercurial.pure.'):]
192 newlocalmods.add('mercurial.cext.' + m)
193 newlocalmods.add('mercurial.cffi._' + m)
194 return newlocalmods
195
196 def list_stdlib_modules():
197 """List the modules present in the stdlib.
198
199 >>> py3 = sys.version_info[0] >= 3
200 >>> mods = set(list_stdlib_modules())
201 >>> 'BaseHTTPServer' in mods or py3
202 True
203
204 os.path isn't really a module, so it's missing:
205
206 >>> 'os.path' in mods
207 False
208
209 sys requires special treatment, because it's baked into the
210 interpreter, but it should still appear:
211
212 >>> 'sys' in mods
213 True
214
215 >>> 'collections' in mods
216 True
217
218 >>> 'cStringIO' in mods or py3
219 True
220
221 >>> 'cffi' in mods
222 True
223 """
224 for m in sys.builtin_module_names:
225 yield m
226 # These modules only exist on windows, but we should always
227 # consider them stdlib.
228 for m in ['msvcrt', '_winreg']:
229 yield m
230 yield '__builtin__'
231 yield 'builtins' # python3 only
232 yield 'importlib.abc' # python3 only
233 yield 'importlib.machinery' # python3 only
234 yield 'importlib.util' # python3 only
235 for m in 'fcntl', 'grp', 'pwd', 'termios': # Unix only
236 yield m
237 for m in 'cPickle', 'datetime': # in Python (not C) on PyPy
238 yield m
239 for m in ['cffi']:
240 yield m
241 stdlib_prefixes = {sys.prefix, sys.exec_prefix}
242 # We need to supplement the list of prefixes for the search to work
243 # when run from within a virtualenv.
244 for mod in (basehttpserver, zlib):
245 if mod is None:
246 continue
247 try:
248 # Not all module objects have a __file__ attribute.
249 filename = mod.__file__
250 except AttributeError:
251 continue
252 dirname = os.path.dirname(filename)
253 for prefix in stdlib_prefixes:
254 if dirname.startswith(prefix):
255 # Then this directory is redundant.
256 break
257 else:
258 stdlib_prefixes.add(dirname)
259 for libpath in sys.path:
260 # We want to walk everything in sys.path that starts with
261 # something in stdlib_prefixes.
262 if not any(libpath.startswith(p) for p in stdlib_prefixes):
263 continue
264 for top, dirs, files in os.walk(libpath):
265 for i, d in reversed(list(enumerate(dirs))):
266 if (not os.path.exists(os.path.join(top, d, '__init__.py'))
267 or top == libpath and d in ('hgdemandimport', 'hgext',
268 'mercurial')):
269 del dirs[i]
270 for name in files:
271 if not name.endswith(('.py', '.so', '.pyc', '.pyo', '.pyd')):
272 continue
273 if name.startswith('__init__.py'):
274 full_path = top
275 else:
276 full_path = os.path.join(top, name)
277 rel_path = full_path[len(libpath) + 1:]
278 mod = dotted_name_of_path(rel_path)
279 yield mod
280
281 stdlib_modules = set(list_stdlib_modules())
282
283 def imported_modules(source, modulename, f, localmods, ignore_nested=False):
284 """Given the source of a file as a string, yield the names
285 imported by that file.
286
287 Args:
288 source: The python source to examine as a string.
289 modulename: of specified python source (may have `__init__`)
290 localmods: set of locally defined module names (may have `__init__`)
291 ignore_nested: If true, import statements that do not start in
292 column zero will be ignored.
293
294 Returns:
295 A list of absolute module names imported by the given source.
296
297 >>> f = 'foo/xxx.py'
298 >>> modulename = 'foo.xxx'
299 >>> localmods = {'foo.__init__': True,
300 ... 'foo.foo1': True, 'foo.foo2': True,
301 ... 'foo.bar.__init__': True, 'foo.bar.bar1': True,
302 ... 'baz.__init__': True, 'baz.baz1': True }
303 >>> # standard library (= not locally defined ones)
304 >>> sorted(imported_modules(
305 ... 'from stdlib1 import foo, bar; import stdlib2',
306 ... modulename, f, localmods))
307 []
308 >>> # relative importing
309 >>> sorted(imported_modules(
310 ... 'import foo1; from bar import bar1',
311 ... modulename, f, localmods))
312 ['foo.bar.bar1', 'foo.foo1']
313 >>> sorted(imported_modules(
314 ... 'from bar.bar1 import name1, name2, name3',
315 ... modulename, f, localmods))
316 ['foo.bar.bar1']
317 >>> # absolute importing
318 >>> sorted(imported_modules(
319 ... 'from baz import baz1, name1',
320 ... modulename, f, localmods))
321 ['baz.__init__', 'baz.baz1']
322 >>> # mixed importing, even though it shouldn't be recommended
323 >>> sorted(imported_modules(
324 ... 'import stdlib, foo1, baz',
325 ... modulename, f, localmods))
326 ['baz.__init__', 'foo.foo1']
327 >>> # ignore_nested
328 >>> sorted(imported_modules(
329 ... '''import foo
330 ... def wat():
331 ... import bar
332 ... ''', modulename, f, localmods))
333 ['foo.__init__', 'foo.bar.__init__']
334 >>> sorted(imported_modules(
335 ... '''import foo
336 ... def wat():
337 ... import bar
338 ... ''', modulename, f, localmods, ignore_nested=True))
339 ['foo.__init__']
340 """
341 fromlocal = fromlocalfunc(modulename, localmods)
342 for node in ast.walk(ast.parse(source, f)):
343 if ignore_nested and getattr(node, 'col_offset', 0) > 0:
344 continue
345 if isinstance(node, ast.Import):
346 for n in node.names:
347 found = fromlocal(n.name)
348 if not found:
349 # this should import standard library
350 continue
351 yield found[1]
352 elif isinstance(node, ast.ImportFrom):
353 found = fromlocal(node.module, node.level)
354 if not found:
355 # this should import standard library
356 continue
357
358 absname, dottedpath, hassubmod = found
359 if not hassubmod:
360 # "dottedpath" is not a package; must be imported
361 yield dottedpath
362 # examination of "node.names" should be redundant
363 # e.g.: from mercurial.node import nullid, nullrev
364 continue
365
366 modnotfound = False
367 prefix = absname + '.'
368 for n in node.names:
369 found = fromlocal(prefix + n.name)
370 if not found:
371 # this should be a function or a property of "node.module"
372 modnotfound = True
373 continue
374 yield found[1]
375 if modnotfound:
376 # "dottedpath" is a package, but imported because of non-module
377 # lookup
378 yield dottedpath
379
380 def verify_import_convention(module, source, localmods):
381 """Verify imports match our established coding convention.
382
383 We have 2 conventions: legacy and modern. The modern convention is in
384 effect when using absolute imports.
385
386 The legacy convention only looks for mixed imports. The modern convention
387 is much more thorough.
388 """
389 root = ast.parse(source)
390 absolute = usingabsolute(root)
391
392 if absolute:
393 return verify_modern_convention(module, root, localmods)
394 else:
395 return verify_stdlib_on_own_line(root)
396
397 def verify_modern_convention(module, root, localmods, root_col_offset=0):
398 """Verify a file conforms to the modern import convention rules.
399
400 The rules of the modern convention are:
401
402 * Ordering is stdlib followed by local imports. Each group is lexically
403 sorted.
404 * Importing multiple modules via "import X, Y" is not allowed: use
405 separate import statements.
406 * Importing multiple modules via "from X import ..." is allowed if using
407 parenthesis and one entry per line.
408 * Only 1 relative import statement per import level ("from .", "from ..")
409 is allowed.
410 * Relative imports from higher levels must occur before lower levels. e.g.
411 "from .." must be before "from .".
412 * Imports from peer packages should use relative import (e.g. do not
413 "import mercurial.foo" from a "mercurial.*" module).
414 * Symbols can only be imported from specific modules (see
415 `allowsymbolimports`). For other modules, first import the module then
416 assign the symbol to a module-level variable. In addition, these imports
417 must be performed before other local imports. This rule only
418 applies to import statements outside of any blocks.
419 * Relative imports from the standard library are not allowed, unless that
420 library is also a local module.
421 * Certain modules must be aliased to alternate names to avoid aliasing
422 and readability problems. See `requirealias`.
423 """
424 if not isinstance(module, str):
425 module = module.decode('ascii')
426 topmodule = module.split('.')[0]
427 fromlocal = fromlocalfunc(module, localmods)
428
429 # Whether a local/non-stdlib import has been performed.
430 seenlocal = None
431 # Whether a local/non-stdlib, non-symbol import has been seen.
432 seennonsymbollocal = False
433 # The last name to be imported (for sorting).
434 lastname = None
435 laststdlib = None
436 # Relative import levels encountered so far.
437 seenlevels = set()
438
439 for node, newscope in walklocal(root):
440 def msg(fmt, *args):
441 return (fmt % args, node.lineno)
442 if newscope:
443 # Check for local imports in function
444 for r in verify_modern_convention(module, node, localmods,
445 node.col_offset + 4):
446 yield r
447 elif isinstance(node, ast.Import):
448 # Disallow "import foo, bar" and require separate imports
449 # for each module.
450 if len(node.names) > 1:
451 yield msg('multiple imported names: %s',
452 ', '.join(n.name for n in node.names))
453
454 name = node.names[0].name
455 asname = node.names[0].asname
456
457 stdlib = name in stdlib_modules
458
459 # Ignore sorting rules on imports inside blocks.
460 if node.col_offset == root_col_offset:
461 if lastname and name < lastname and laststdlib == stdlib:
462 yield msg('imports not lexically sorted: %s < %s',
463 name, lastname)
464
465 lastname = name
466 laststdlib = stdlib
467
468 # stdlib imports should be before local imports.
469 if stdlib and seenlocal and node.col_offset == root_col_offset:
470 yield msg('stdlib import "%s" follows local import: %s',
471 name, seenlocal)
472
473 if not stdlib:
474 seenlocal = name
475
476 # Import of sibling modules should use relative imports.
477 topname = name.split('.')[0]
478 if topname == topmodule:
479 yield msg('import should be relative: %s', name)
480
481 if name in requirealias and asname != requirealias[name]:
482 yield msg('%s module must be "as" aliased to %s',
483 name, requirealias[name])
484
485 elif isinstance(node, ast.ImportFrom):
486 # Resolve the full imported module name.
487 if node.level > 0:
488 fullname = '.'.join(module.split('.')[:-node.level])
489 if node.module:
490 fullname += '.%s' % node.module
491 else:
492 assert node.module
493 fullname = node.module
494
495 topname = fullname.split('.')[0]
496 if topname == topmodule:
497 yield msg('import should be relative: %s', fullname)
498
499 # __future__ is special since it needs to come first and use
500 # symbol import.
501 if fullname != '__future__':
502 if not fullname or (
503 fullname in stdlib_modules
504 and fullname not in localmods
505 and fullname + '.__init__' not in localmods):
506 yield msg('relative import of stdlib module')
507 else:
508 seenlocal = fullname
509
510 # Direct symbol import is only allowed from certain modules and
511 # must occur before non-symbol imports.
512 found = fromlocal(node.module, node.level)
513 if found and found[2]: # node.module is a package
514 prefix = found[0] + '.'
515 symbols = (n.name for n in node.names
516 if not fromlocal(prefix + n.name))
517 else:
518 symbols = (n.name for n in node.names)
519 symbols = [sym for sym in symbols if sym not in directsymbols]
520 if node.module and node.col_offset == root_col_offset:
521 if symbols and fullname not in allowsymbolimports:
522 yield msg('direct symbol import %s from %s',
523 ', '.join(symbols), fullname)
524
525 if symbols and seennonsymbollocal:
526 yield msg('symbol import follows non-symbol import: %s',
527 fullname)
528 if not symbols and fullname not in stdlib_modules:
529 seennonsymbollocal = True
530
531 if not node.module:
532 assert node.level
533
534 # Only allow 1 group per level.
535 if (node.level in seenlevels
536 and node.col_offset == root_col_offset):
537 yield msg('multiple "from %s import" statements',
538 '.' * node.level)
539
540 # Higher-level groups come before lower-level groups.
541 if any(node.level > l for l in seenlevels):
542 yield msg('higher-level import should come first: %s',
543 fullname)
544
545 seenlevels.add(node.level)
546
547 # Entries in "from .X import ( ... )" lists must be lexically
548 # sorted.
549 lastentryname = None
550
551 for n in node.names:
552 if lastentryname and n.name < lastentryname:
553 yield msg('imports from %s not lexically sorted: %s < %s',
554 fullname, n.name, lastentryname)
555
556 lastentryname = n.name
557
558 if n.name in requirealias and n.asname != requirealias[n.name]:
559 yield msg('%s from %s must be "as" aliased to %s',
560 n.name, fullname, requirealias[n.name])
561
562 def verify_stdlib_on_own_line(root):
563 """Given some python source, verify that stdlib imports are done
564 in separate statements from relative local module imports.
565
566 >>> list(verify_stdlib_on_own_line(ast.parse('import sys, foo')))
567 [('mixed imports\\n stdlib: sys\\n relative: foo', 1)]
568 >>> list(verify_stdlib_on_own_line(ast.parse('import sys, os')))
569 []
570 >>> list(verify_stdlib_on_own_line(ast.parse('import foo, bar')))
571 []
572 """
573 for node in ast.walk(root):
574 if isinstance(node, ast.Import):
575 from_stdlib = {False: [], True: []}
576 for n in node.names:
577 from_stdlib[n.name in stdlib_modules].append(n.name)
578 if from_stdlib[True] and from_stdlib[False]:
579 yield ('mixed imports\n stdlib: %s\n relative: %s' %
580 (', '.join(sorted(from_stdlib[True])),
581 ', '.join(sorted(from_stdlib[False]))), node.lineno)
582
583 class CircularImport(Exception):
584 pass
585
586 def checkmod(mod, imports):
587 shortest = {}
588 visit = [[mod]]
589 while visit:
590 path = visit.pop(0)
591 for i in sorted(imports.get(path[-1], [])):
592 if len(path) < shortest.get(i, 1000):
593 shortest[i] = len(path)
594 if i in path:
595 if i == path[0]:
596 raise CircularImport(path)
597 continue
598 visit.append(path + [i])
599
600 def rotatecycle(cycle):
601 """arrange a cycle so that the lexicographically first module listed first
602
603 >>> rotatecycle(['foo', 'bar'])
604 ['bar', 'foo', 'bar']
605 """
606 lowest = min(cycle)
607 idx = cycle.index(lowest)
608 return cycle[idx:] + cycle[:idx] + [lowest]
609
610 def find_cycles(imports):
611 """Find cycles in an already-loaded import graph.
612
613 All module names recorded in `imports` should be absolute one.
614
615 >>> from __future__ import print_function
616 >>> imports = {'top.foo': ['top.bar', 'os.path', 'top.qux'],
617 ... 'top.bar': ['top.baz', 'sys'],
618 ... 'top.baz': ['top.foo'],
619 ... 'top.qux': ['top.foo']}
620 >>> print('\\n'.join(sorted(find_cycles(imports))))
621 top.bar -> top.baz -> top.foo -> top.bar
622 top.foo -> top.qux -> top.foo
623 """
624 cycles = set()
625 for mod in sorted(imports.keys()):
626 try:
627 checkmod(mod, imports)
628 except CircularImport as e:
629 cycle = e.args[0]
630 cycles.add(" -> ".join(rotatecycle(cycle)))
631 return cycles
632
633 def _cycle_sortkey(c):
634 return len(c), c
635
636 def embedded(f, modname, src):
637 """Extract embedded python code
638
639 >>> def _forcestr(thing):
640 ... if not isinstance(thing, str):
641 ... return thing.decode('ascii')
642 ... return thing
643 >>> def test(fn, lines):
644 ... for s, m, f, l in embedded(fn, b"example", lines):
645 ... print("%s %s %d" % (_forcestr(m), _forcestr(f), l))
646 ... print(repr(_forcestr(s)))
647 >>> lines = [
648 ... b'comment',
649 ... b' >>> from __future__ import print_function',
650 ... b" >>> ' multiline",
651 ... b" ... string'",
652 ... b' ',
653 ... b'comment',
654 ... b' $ cat > foo.py <<EOF',
655 ... b' > from __future__ import print_function',
656 ... b' > EOF',
657 ... ]
658 >>> test(b"example.t", lines)
659 example[2] doctest.py 2
660 "from __future__ import print_function\\n' multiline\\nstring'\\n"
661 example[7] foo.py 7
662 'from __future__ import print_function\\n'
663 """
664 inlinepython = 0
665 shpython = 0
666 script = []
667 prefix = 6
668 t = ''
669 n = 0
670 for l in src:
671 n += 1
672 if not l.endswith(b'\n'):
673 l += b'\n'
674 if l.startswith(b' >>> '): # python inlines
675 if shpython:
676 print("%s:%d: Parse Error" % (f, n))
677 if not inlinepython:
678 # We've just entered a Python block.
679 inlinepython = n
680 t = b'doctest.py'
681 script.append(l[prefix:])
682 continue
683 if l.startswith(b' ... '): # python inlines
684 script.append(l[prefix:])
685 continue
686 cat = re.search(br"\$ \s*cat\s*>\s*(\S+\.py)\s*<<\s*EOF", l)
687 if cat:
688 if inlinepython:
689 yield b''.join(script), (b"%s[%d]" %
690 (modname, inlinepython)), t, inlinepython
691 script = []
692 inlinepython = 0
693 shpython = n
694 t = cat.group(1)
695 continue
696 if shpython and l.startswith(b' > '): # sh continuation
697 if l == b' > EOF\n':
698 yield b''.join(script), (b"%s[%d]" %
699 (modname, shpython)), t, shpython
700 script = []
701 shpython = 0
702 else:
703 script.append(l[4:])
704 continue
705 # If we have an empty line or a command for sh, we end the
706 # inline script.
707 if inlinepython and (l == b' \n'
708 or l.startswith(b' $ ')):
709 yield b''.join(script), (b"%s[%d]" %
710 (modname, inlinepython)), t, inlinepython
711 script = []
712 inlinepython = 0
713 continue
714
715 def sources(f, modname):
716 """Yields possibly multiple sources from a filepath
717
718 input: filepath, modulename
719 yields: script(string), modulename, filepath, linenumber
720
721 For embedded scripts, the modulename and filepath will be different
722 from the function arguments. linenumber is an offset relative to
723 the input file.
724 """
725 py = False
726 if not f.endswith('.t'):
727 with open(f, 'rb') as src:
728 yield src.read(), modname, f, 0
729 py = True
730 if py or f.endswith('.t'):
731 with open(f, 'rb') as src:
732 for script, modname, t, line in embedded(f, modname, src):
733 yield script, modname, t, line
734
735 def main(argv):
736 if len(argv) < 2 or (argv[1] == '-' and len(argv) > 2):
737 print('Usage: %s {-|file [file] [file] ...}')
738 return 1
739 if argv[1] == '-':
740 argv = argv[:1]
741 argv.extend(l.rstrip() for l in sys.stdin.readlines())
742 localmodpaths = {}
743 used_imports = {}
744 any_errors = False
745 for source_path in argv[1:]:
746 modname = dotted_name_of_path(source_path)
747 localmodpaths[modname] = source_path
748 localmods = populateextmods(localmodpaths)
749 for localmodname, source_path in sorted(localmodpaths.items()):
750 if not isinstance(localmodname, bytes):
751 # This is only safe because all hg's files are ascii
752 localmodname = localmodname.encode('ascii')
753 for src, modname, name, line in sources(source_path, localmodname):
754 try:
755 used_imports[modname] = sorted(
756 imported_modules(src, modname, name, localmods,
757 ignore_nested=True))
758 for error, lineno in verify_import_convention(modname, src,
759 localmods):
760 any_errors = True
761 print('%s:%d: %s' % (source_path, lineno + line, error))
762 except SyntaxError as e:
763 print('%s:%d: SyntaxError: %s' %
764 (source_path, e.lineno + line, e))
765 cycles = find_cycles(used_imports)
766 if cycles:
767 firstmods = set()
768 for c in sorted(cycles, key=_cycle_sortkey):
769 first = c.split()[0]
770 # As a rough cut, ignore any cycle that starts with the
771 # same module as some other cycle. Otherwise we see lots
772 # of cycles that are effectively duplicates.
773 if first in firstmods:
774 continue
775 print('Import cycle:', c)
776 firstmods.add(first)
777 any_errors = True
778 return any_errors != 0
779
780 if __name__ == '__main__':
781 sys.exit(int(main(sys.argv)))
@@ -0,0 +1,5 b''
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <!-- Created with Inkscape (http://www.inkscape.org/) -->
3 <svg id="Layer_1" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="120" width="100" version="1.0" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 124.766 152.099"><metadata id="metadata6845"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title>Mercurial &quot;droplets&quot; logo</dc:title><dc:creator><cc:Agent><dc:title>Cali Mastny and Matt Mackall</dc:title></cc:Agent></dc:creator><cc:license rdf:resource="http://creativecommons.org/licenses/GPL/2.0/"/><dc:date>Feb 12 2008</dc:date></cc:Work><cc:License rdf:about="http://creativecommons.org/licenses/GPL/2.0/"><cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/><cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/><cc:requires rdf:resource="http://web.resource.org/cc/Notice"/><cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/><cc:requires rdf:resource="http://web.resource.org/cc/ShareAlike"/><cc:requires rdf:resource="http://web.resource.org/cc/SourceCode"/></cc:License></rdf:RDF></metadata>
4 <rect id="rect6847" stroke-linejoin="miter" style="stroke-dasharray:none;" height="150.12" width="124.77" stroke="#000" stroke-miterlimit="4" y="0.98776" x="0.3169" stroke-width="1.9755" fill="#FFF"/><path id="text2611" style="stroke-dasharray:none;" d="M9.848,124.61c1.777-0.79,3.665-1.18,5.479-1.18,1.74,0,2.851,0.43,3.48,1.32,1.332-0.89,3.146-1.32,4.553-1.32,4.221,0,4.369,1.71,4.369,6.73v11.11c0,0.49,0.074,0.49-2.036,0.49v-11.81c0-3.63-0.074-4.74-2.48-4.74-1.073,0-2.184,0.25-3.369,1.03v15.27c-0.037,0.15-0.111,0.18-0.369,0.22-0.038,0-0.074,0.03-0.112,0.03h-1.555v-11.81c0-3.49,0-4.77-2.517-4.77-1.074,0-2.147,0.21-3.406,0.82v15.27c0,0.49,0.074,0.49-2.0361,0.49v-17.15m27.831-1.18c-3.146,0-6.626,0.89-6.626,10.4,0,7.33,2.554,8.47,6.071,8.47,2.701,0,5.034-0.89,5.034-1.32,0-0.53-0.074-1.35-0.259-1.82-1.148,0.79-2.777,1.21-4.59,1.21-2.48,0-4.146-0.71-4.184-6.22,1.629,0,5.776-0.04,8.848-0.65,0.259-1.17,0.37-2.88,0.37-4.37,0-3.56-1.444-5.7-4.664-5.7m-0.185,1.78c2.221,0,2.813,1.46,2.85,4.31,0,0.75-0.037,1.64-0.148,2.49-2.073,0.5-5.591,0.5-7.072,0.5,0.261-6.48,2.481-7.3,4.37-7.3m8.07-0.21c1.739-1.14,3.332-1.57,4.961-1.57,1.814,0,2.666,0.5,2.666,1.11,0,0.35-0.112,0.96-0.297,1.31-0.519-0.28-1.11-0.53-2.074-0.53-1.184,0-2.295,0.32-3.183,1.1v14.85c0,0.49,0.037,0.49-2.073,0.49v-16.76m18.69-0.39c0-0.47-1.554-1.18-3.11-1.18-2.999,0-6.664,1.03-6.664,9.83,0,8.33,2.222,9.07,6.109,9.07,1.924,0,3.665-1.03,3.665-1.6,0-0.32-0.074-0.82-0.26-1.24-0.778,0.56-1.962,1.1-3.22,1.1-2.665,0-4.22-0.75-4.22-7.23,0-7.15,2.554-8.15,4.775-8.15,1.258,0,1.962,0.36,2.665,0.82,0.186-0.43,0.26-1.03,0.26-1.42m14.181,16.55c-1.63,0.82-3.776,1.14-5.627,1.14-4.739,0-5.442-1.99-5.442-6.73v-11.14c0-0.46-0.037-0.46,2.074-0.46v11.82c0,3.56,0.517,4.77,3.294,4.77,1.073,0,2.554-0.22,3.665-0.86v-15.27c0-0.46-0.074-0.46,2.036-0.46v17.19m4.221-16.16c1.739-1.14,3.332-1.57,4.96-1.57,1.814,0,2.666,0.5,2.666,1.11,0,0.35-0.111,0.96-0.296,1.31-0.519-0.28-1.111-0.53-2.074-0.53-1.184,0-2.295,0.32-3.183,1.1v14.85c0,0.49,0.037,0.49-2.073,0.49v-16.76m12.379-1.03c-1.629,0-2.11,0-2.11,0.96v16.83c2.073,0,2.11,0,2.11-0.49v-17.3m-2.184-6.27c0,1.18,0.37,1.6,1.11,1.64,0.851,0,1.259-0.61,1.259-1.67,0.037-1.11-0.26-1.61-1.111-1.61-0.814,0-1.221,0.61-1.258,1.64m5.696,7.3c0-0.39,0.074-0.61,0.222-0.71,0.704-0.39,3.41-0.86,6.48-0.86,2.33,0,3.81,1.11,3.81,4.31v2.31c0,6.34-0.18,11.07-0.18,11.07-0.85,0.47-2.45,1.18-5.04,1.18-2.66,0.03-5.329-0.22-5.329-5.48,0-5.02,2.739-5.81,5.479-5.81,1.04,0,2.26,0.11,3.07,0.43v-3.31c0-2.31-1.18-2.81-2.59-2.81-1.89,0-4.514,0.35-5.662,0.89-0.222-0.39-0.26-1-0.26-1.21m8.512,7.9c-0.7-0.25-1.7-0.35-2.4-0.35-2.11,0-4.04,0.42-4.04,4.34,0,3.66,1.59,3.7,3.48,3.7,1.19,0,2.37-0.32,2.78-0.75,0,0,0.18-4.27,0.18-6.94m7.86,8.37c0,0.49,0.04,0.49-2.04,0.49v-25.2c0-0.96,0.41-0.96,2.04-0.96v25.67" stroke-miterlimit="4" stroke-width="2.02999997" fill="#010101"/><g id="g4503" transform="matrix(0.9351326,0,0,0.9351326,150.39508,-1.251766)"><path id="path2339" fill="#1b1a1b" d="M-45.75,92.692c20.04-33.321-4.232-87.363-48.614-81.873-40.096,4.958-40.746,47.165-5.405,57.191,30.583,8.685,6.318,28.084,7.027,41,0.712,12.92,26.587,17.6,46.992-16.318z"/><circle id="circle2341" transform="matrix(1.0917947,-0.2858168,0.2858168,1.0917947,-180.30817,13.494135)" cy="85.364" cx="33.728" r="15.414" fill="#1b1a1b"/><path id="path2343" fill="#1b1a1b" d="M-140.06,48.936c-6.26,0.606-10.84,6.164-10.24,12.422,0.61,6.262,6.17,10.847,12.43,10.241,6.26-0.614,10.84-6.171,10.23-12.43-0.61-6.253-6.16-10.839-12.42-10.233z"/><path id="path2561" fill="#bfbfbf" d="M-44.993,91.34c20.041-33.321-4.231-87.363-48.613-81.873-40.104,4.9568-40.744,47.166-5.406,57.193,30.583,8.684,6.318,28.083,7.027,41,0.713,12.92,26.587,17.6,46.992-16.32z"/><path id="path2563" fill="#000" d="M-86.842,112.76c-1.215-1.97,0.642-4.16,2.551-3.99,3.039,0.26,9.655-0.04,14.876-3,13.043-7.39,33.114-42.966,23.019-65.405-4.519-10.044-6.72-12.92-11.374-17.833-0.95-1.002-0.405-0.948,0.238-0.609,2.517,1.321,6.94,6.437,11.477,14.765,7.664,14.069,7.267,30.795,4.416,41.287-1.986,7.299-8.825,23.815-18.842,30.955-10.039,7.15-21.785,11.26-26.361,3.83z"/><path id="path2565" fill="#000" d="M-95.93,66.591c-6.83-2.028-15.64-4.853-20.74-11.517-3.75-4.914-5.66-10.277-6.15-13.318-0.17-1.085-0.32-1.991-0.01-2.24,0.15-0.117,2.81,5.896,6.79,10.936,3.97,5.04,9.53,7.988,14.16,9.059,4.117,0.952,12.646,3.044,15.532,5.503,2.967,2.527,3.215,7.987,2.216,8.603-1.006,0.62-3.048-4.429-11.798-7.026z"/><path id="path2567" fill="#FFF" d="M-81.841,113.72c-0.132,1.57,1.665,1.87,4.083,1.51,3.099-0.46,5.72-0.81,9.287-2.6,4.835-2.42,9.728-5.89,13.312-10.57,10.692-13.945,14.478-30.45,13.895-32.824-0.195,1.961-2.776,12.253-8.679,21.532-7.582,11.922-13.079,18.262-25.758,21.342-3.529,0.86-5.967-0.45-6.14,1.61z"/><path id="path2569" fill="#FFF" d="M-109.96,59.479c1.44,1.225,4.4,2.857,10.223,4.767,7.031,2.305,10.455,4.304,11.888,5.262,1.52,1.018,2.483,3.288,2.578,1.272,0.099-2.019-1.145-3.755-3.921-4.675-1.878-0.624-5.038-2.109-8.067-2.707-1.946-0.384-5.111-1.146-7.831-1.978-1.48-0.457-3-1.258-4.87-1.941z"/><circle id="circle2577" transform="matrix(1.0917947,-0.2858168,0.2858168,1.0917947,-180.30817,13.494135)" cy="84.375" cx="34.681" r="15.414" fill="#bfbfbf"/><path id="path2579" fill="#000" d="M-128.68,108.38c13.53,12.54,33.894-4.69,24.93-19.897-1.01-1.708-2.32-3.009-1.89-1.7,2.87,8.747,0.22,15.667-4.72,19.227-4.85,3.5-11.51,4.09-16.84,1.32-1.57-0.81-2.22,0.37-1.48,1.05z"/><path id="path2585" fill="#FFF" d="M-118.07,110.95c1.73-0.36,11.75-2.95,14.1-11.194,0.73-2.569,0.86-2.053,0.66-0.661-1.06,7.105-7.78,12.345-13.49,12.545-1.16,0.12-2.68-0.39-1.27-0.69z"/><path id="path2589" fill="#bfbfbf" d="M-139.3,47.584c-6.26,0.605-10.84,6.164-10.24,12.422,0.61,6.261,6.17,10.847,12.43,10.241,6.25-0.614,10.84-6.173,10.23-12.431-0.61-6.254-6.17-10.838-12.42-10.232z"/><path id="path2591" fill="#000" d="M-144.47,67.571c0.07,0.805,1.17,1.838,2.9,2.312,1.49,0.408,5.32,1.45,10.25-1.658,4.92-3.108,5.49-11.421,3.25-13.865-0.69-1.239-1.59-2.14-0.88-0.164,1.81,4.99-1.7,9.659-4.74,11.82-3.03,2.162-6.88,1.139-8.45,0.66s-2.4,0.064-2.33,0.895z"/><path id="path2597" fill="#FFF" d="M-138.11,68.688c0.45-0.406,2.73-0.24,4.79-1.35,2.07-1.109,4.52-3.54,4.95-6.994,0.26-2.029,0.34-1.519,0.44-0.415-0.32,5.743-5.6,8.916-8.62,9.334-0.82,0.113-2.25,0.044-1.56-0.575z"/><path id="path2561_1_" fill="#999" d="M-47.767,69.694c8.532-24.594-9.323-61.736-45.446-57.268-32.637,4.035-33.167,38.389-4.4,46.55,32.582,4.933,12.962,29.512,10.179,41.904-2.495,11.11,26.331,12.94,39.667-31.186z"/><path id="path2571" fill="#f3f3f3" d="M-70.093,88.904c-8.827-1.092-21.529,18.836-9.552,16.506,5.756-0.86,10.525-2.89,14.794-7.762,5.567-6.353,13.883-20.074,16.288-28.94,2.025-7.476,1.007-19.057-1.081-8.175-2.142,11.167-11.623,29.464-20.449,28.371z"/><path id="path2581" fill="#999" d="M-129.39,104.85c2.05,0.03,3.28,0.32,5.35,1.77,4.09,1.7,11.61,0.62,15.09-3.95,3.47-4.57,3.58-10.868,2.26-14.674-3.24-9.314-16.99-9.149-23.13-1.417-6.64,8.636-1.61,18.231,0.43,18.271z"/><path id="path2593_2_" fill="#999" d="M-147.64,61.684c0.41,1.282,1.45,3.154,3.65,3.466,2.94,0.417,3.54,1.743,7,1.055,3.47-0.688,6.09-3.528,7.14-6.67,1.21-4.347-0.59-6.591-3.31-8.595-2.71-2.003-8.67-1.788-12.23,1.458-2.53,2.305-3.24,6.163-2.25,9.286z"/><path id="path256" fill="#f3f3f3" d="M-136.11,64.558c2.66-0.697,6.18-4.325,4.44-7.096-2.16-3.413-8.17-0.491-8.37,3.309-0.21,3.802,1.11,4.526,3.93,3.787z"/><path id="path258" fill="#f3f3f3" d="M-116.12,105.51c2.28-0.6,9.24-3.43,7.93-13.547-0.66-5.126-3.46,6.361-8.63,8.077-7.85,2.61-6.97,7.48,0.7,5.47z"/></g>
5 </svg>
@@ -0,0 +1,31 b''
1 # memory.py - track memory usage
2 #
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
7
8 '''helper extension to measure memory usage
9
10 Reads current and peak memory usage from ``/proc/self/status`` and
11 prints it to ``stderr`` on exit.
12 '''
13
14 from __future__ import absolute_import
15
16 def memusage(ui):
17 """Report memory usage of the current process."""
18 result = {'peak': 0, 'rss': 0}
19 with open('/proc/self/status', 'r') as status:
20 # This will only work on systems with a /proc file system
21 # (like Linux).
22 for line in status:
23 parts = line.split()
24 key = parts[0][2:-1].lower()
25 if key in result:
26 result[key] = int(parts[1])
27 ui.write_err(", ".join(["%s: %.1f MiB" % (k, v / 1024.0)
28 for k, v in result.iteritems()]) + "\n")
29
30 def extsetup(ui):
31 ui.atexit(memusage, ui)
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now