##// END OF EJS Templates
core: finished removal of pyro4....
marcink -
r213:28f26574 default
parent child Browse files
Show More
@@ -1,85 +1,79 b''
1 1 ################################################################################
2 2 # RhodeCode VCSServer with HTTP Backend - configuration #
3 3 # #
4 4 ################################################################################
5 5
6 6 [app:main]
7 7 use = egg:rhodecode-vcsserver
8 8
9 9 pyramid.default_locale_name = en
10 10 pyramid.includes =
11 11
12 12 # default locale used by VCS systems
13 13 locale = en_US.UTF-8
14 14
15 15 # cache regions, please don't change
16 16 beaker.cache.regions = repo_object
17 17 beaker.cache.repo_object.type = memorylru
18 18 beaker.cache.repo_object.max_items = 100
19 19 # cache auto-expires after N seconds
20 20 beaker.cache.repo_object.expire = 300
21 21 beaker.cache.repo_object.enabled = true
22 22
23 23 [server:main]
24 24 ## COMMON ##
25 25 host = 0.0.0.0
26 26 port = 9900
27 27
28 28 use = egg:waitress#main
29 29
30 30
31 31 ################################
32 32 ### LOGGING CONFIGURATION ####
33 33 ################################
34 34 [loggers]
35 keys = root, vcsserver, pyro4, beaker
35 keys = root, vcsserver, beaker
36 36
37 37 [handlers]
38 38 keys = console
39 39
40 40 [formatters]
41 41 keys = generic
42 42
43 43 #############
44 44 ## LOGGERS ##
45 45 #############
46 46 [logger_root]
47 47 level = NOTSET
48 48 handlers = console
49 49
50 50 [logger_vcsserver]
51 51 level = DEBUG
52 52 handlers =
53 53 qualname = vcsserver
54 54 propagate = 1
55 55
56 56 [logger_beaker]
57 57 level = DEBUG
58 58 handlers =
59 59 qualname = beaker
60 60 propagate = 1
61 61
62 [logger_pyro4]
63 level = DEBUG
64 handlers =
65 qualname = Pyro4
66 propagate = 1
67
68 62
69 63 ##############
70 64 ## HANDLERS ##
71 65 ##############
72 66
73 67 [handler_console]
74 68 class = StreamHandler
75 69 args = (sys.stderr,)
76 70 level = DEBUG
77 71 formatter = generic
78 72
79 73 ################
80 74 ## FORMATTERS ##
81 75 ################
82 76
83 77 [formatter_generic]
84 78 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
85 79 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,109 +1,103 b''
1 1 ################################################################################
2 2 # RhodeCode VCSServer with HTTP Backend - configuration #
3 3 # #
4 4 ################################################################################
5 5
6 6
7 7 [server:main]
8 8 ## COMMON ##
9 9 host = 127.0.0.1
10 10 port = 9900
11 11
12 12
13 13 ##########################
14 14 ## GUNICORN WSGI SERVER ##
15 15 ##########################
16 16 ## run with gunicorn --log-config vcsserver.ini --paste vcsserver.ini
17 17 use = egg:gunicorn#main
18 18 ## Sets the number of process workers. Recommended
19 19 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
20 20 workers = 2
21 21 ## process name
22 22 proc_name = rhodecode_vcsserver
23 23 ## type of worker class, one of sync, gevent
24 24 ## recommended for bigger setup is using of of other than sync one
25 25 worker_class = sync
26 26 ## The maximum number of simultaneous clients. Valid only for Gevent
27 27 #worker_connections = 10
28 28 ## max number of requests that worker will handle before being gracefully
29 29 ## restarted, could prevent memory leaks
30 30 max_requests = 1000
31 31 max_requests_jitter = 30
32 32 ## amount of time a worker can spend with handling a request before it
33 33 ## gets killed and restarted. Set to 6hrs
34 34 timeout = 21600
35 35
36 36
37 37 [app:main]
38 38 use = egg:rhodecode-vcsserver
39 39
40 40 pyramid.default_locale_name = en
41 41 pyramid.includes =
42 42
43 43 ## default locale used by VCS systems
44 44 locale = en_US.UTF-8
45 45
46 46 # cache regions, please don't change
47 47 beaker.cache.regions = repo_object
48 48 beaker.cache.repo_object.type = memorylru
49 49 beaker.cache.repo_object.max_items = 100
50 50 # cache auto-expires after N seconds
51 51 beaker.cache.repo_object.expire = 300
52 52 beaker.cache.repo_object.enabled = true
53 53
54 54
55 55 ################################
56 56 ### LOGGING CONFIGURATION ####
57 57 ################################
58 58 [loggers]
59 keys = root, vcsserver, pyro4, beaker
59 keys = root, vcsserver, beaker
60 60
61 61 [handlers]
62 62 keys = console
63 63
64 64 [formatters]
65 65 keys = generic
66 66
67 67 #############
68 68 ## LOGGERS ##
69 69 #############
70 70 [logger_root]
71 71 level = NOTSET
72 72 handlers = console
73 73
74 74 [logger_vcsserver]
75 75 level = DEBUG
76 76 handlers =
77 77 qualname = vcsserver
78 78 propagate = 1
79 79
80 80 [logger_beaker]
81 81 level = DEBUG
82 82 handlers =
83 83 qualname = beaker
84 84 propagate = 1
85 85
86 [logger_pyro4]
87 level = DEBUG
88 handlers =
89 qualname = Pyro4
90 propagate = 1
91
92 86
93 87 ##############
94 88 ## HANDLERS ##
95 89 ##############
96 90
97 91 [handler_console]
98 92 class = StreamHandler
99 93 args = (sys.stderr,)
100 94 level = DEBUG
101 95 formatter = generic
102 96
103 97 ################
104 98 ## FORMATTERS ##
105 99 ################
106 100
107 101 [formatter_generic]
108 102 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
109 103 datefmt = %Y-%m-%d %H:%M:%S No newline at end of file
@@ -1,812 +1,786 b''
1 1 # Generated by pip2nix 0.4.0
2 2 # See https://github.com/johbo/pip2nix
3 3
4 4 {
5 5 Beaker = super.buildPythonPackage {
6 6 name = "Beaker-1.7.0";
7 7 buildInputs = with self; [];
8 8 doCheck = false;
9 9 propagatedBuildInputs = with self; [];
10 10 src = fetchurl {
11 11 url = "https://pypi.python.org/packages/97/8e/409d2e7c009b8aa803dc9e6f239f1db7c3cdf578249087a404e7c27a505d/Beaker-1.7.0.tar.gz";
12 12 md5 = "386be3f7fe427358881eee4622b428b3";
13 13 };
14 14 meta = {
15 15 license = [ pkgs.lib.licenses.bsdOriginal ];
16 16 };
17 17 };
18 18 Jinja2 = super.buildPythonPackage {
19 19 name = "Jinja2-2.8";
20 20 buildInputs = with self; [];
21 21 doCheck = false;
22 22 propagatedBuildInputs = with self; [MarkupSafe];
23 23 src = fetchurl {
24 24 url = "https://pypi.python.org/packages/f2/2f/0b98b06a345a761bec91a079ccae392d282690c2d8272e708f4d10829e22/Jinja2-2.8.tar.gz";
25 25 md5 = "edb51693fe22c53cee5403775c71a99e";
26 26 };
27 27 meta = {
28 28 license = [ pkgs.lib.licenses.bsdOriginal ];
29 29 };
30 30 };
31 31 Mako = super.buildPythonPackage {
32 32 name = "Mako-1.0.6";
33 33 buildInputs = with self; [];
34 34 doCheck = false;
35 35 propagatedBuildInputs = with self; [MarkupSafe];
36 36 src = fetchurl {
37 37 url = "https://pypi.python.org/packages/56/4b/cb75836863a6382199aefb3d3809937e21fa4cb0db15a4f4ba0ecc2e7e8e/Mako-1.0.6.tar.gz";
38 38 md5 = "a28e22a339080316b2acc352b9ee631c";
39 39 };
40 40 meta = {
41 41 license = [ pkgs.lib.licenses.mit ];
42 42 };
43 43 };
44 44 MarkupSafe = super.buildPythonPackage {
45 45 name = "MarkupSafe-0.23";
46 46 buildInputs = with self; [];
47 47 doCheck = false;
48 48 propagatedBuildInputs = with self; [];
49 49 src = fetchurl {
50 50 url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz";
51 51 md5 = "f5ab3deee4c37cd6a922fb81e730da6e";
52 52 };
53 53 meta = {
54 54 license = [ pkgs.lib.licenses.bsdOriginal ];
55 55 };
56 56 };
57 57 PasteDeploy = super.buildPythonPackage {
58 58 name = "PasteDeploy-1.5.2";
59 59 buildInputs = with self; [];
60 60 doCheck = false;
61 61 propagatedBuildInputs = with self; [];
62 62 src = fetchurl {
63 63 url = "https://pypi.python.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz";
64 64 md5 = "352b7205c78c8de4987578d19431af3b";
65 65 };
66 66 meta = {
67 67 license = [ pkgs.lib.licenses.mit ];
68 68 };
69 69 };
70 Pyro4 = super.buildPythonPackage {
71 name = "Pyro4-4.41";
72 buildInputs = with self; [];
73 doCheck = false;
74 propagatedBuildInputs = with self; [serpent];
75 src = fetchurl {
76 url = "https://pypi.python.org/packages/56/2b/89b566b4bf3e7f8ba790db2d1223852f8cb454c52cab7693dd41f608ca2a/Pyro4-4.41.tar.gz";
77 md5 = "ed69e9bfafa9c06c049a87cb0c4c2b6c";
78 };
79 meta = {
80 license = [ pkgs.lib.licenses.mit ];
81 };
82 };
83 70 WebOb = super.buildPythonPackage {
84 71 name = "WebOb-1.3.1";
85 72 buildInputs = with self; [];
86 73 doCheck = false;
87 74 propagatedBuildInputs = with self; [];
88 75 src = fetchurl {
89 76 url = "https://pypi.python.org/packages/16/78/adfc0380b8a0d75b2d543fa7085ba98a573b1ae486d9def88d172b81b9fa/WebOb-1.3.1.tar.gz";
90 77 md5 = "20918251c5726956ba8fef22d1556177";
91 78 };
92 79 meta = {
93 80 license = [ pkgs.lib.licenses.mit ];
94 81 };
95 82 };
96 83 WebTest = super.buildPythonPackage {
97 84 name = "WebTest-1.4.3";
98 85 buildInputs = with self; [];
99 86 doCheck = false;
100 87 propagatedBuildInputs = with self; [WebOb];
101 88 src = fetchurl {
102 89 url = "https://pypi.python.org/packages/51/3d/84fd0f628df10b30c7db87895f56d0158e5411206b721ca903cb51bfd948/WebTest-1.4.3.zip";
103 90 md5 = "631ce728bed92c681a4020a36adbc353";
104 91 };
105 92 meta = {
106 93 license = [ pkgs.lib.licenses.mit ];
107 94 };
108 95 };
109 96 backports.shutil-get-terminal-size = super.buildPythonPackage {
110 97 name = "backports.shutil-get-terminal-size-1.0.0";
111 98 buildInputs = with self; [];
112 99 doCheck = false;
113 100 propagatedBuildInputs = with self; [];
114 101 src = fetchurl {
115 102 url = "https://pypi.python.org/packages/ec/9c/368086faa9c016efce5da3e0e13ba392c9db79e3ab740b763fe28620b18b/backports.shutil_get_terminal_size-1.0.0.tar.gz";
116 103 md5 = "03267762480bd86b50580dc19dff3c66";
117 104 };
118 105 meta = {
119 106 license = [ pkgs.lib.licenses.mit ];
120 107 };
121 108 };
122 109 configobj = super.buildPythonPackage {
123 110 name = "configobj-5.0.6";
124 111 buildInputs = with self; [];
125 112 doCheck = false;
126 113 propagatedBuildInputs = with self; [six];
127 114 src = fetchurl {
128 115 url = "https://pypi.python.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz";
129 116 md5 = "e472a3a1c2a67bb0ec9b5d54c13a47d6";
130 117 };
131 118 meta = {
132 119 license = [ pkgs.lib.licenses.bsdOriginal ];
133 120 };
134 121 };
135 122 cov-core = super.buildPythonPackage {
136 123 name = "cov-core-1.15.0";
137 124 buildInputs = with self; [];
138 125 doCheck = false;
139 126 propagatedBuildInputs = with self; [coverage];
140 127 src = fetchurl {
141 128 url = "https://pypi.python.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz";
142 129 md5 = "f519d4cb4c4e52856afb14af52919fe6";
143 130 };
144 131 meta = {
145 132 license = [ pkgs.lib.licenses.mit ];
146 133 };
147 134 };
148 135 coverage = super.buildPythonPackage {
149 136 name = "coverage-3.7.1";
150 137 buildInputs = with self; [];
151 138 doCheck = false;
152 139 propagatedBuildInputs = with self; [];
153 140 src = fetchurl {
154 141 url = "https://pypi.python.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz";
155 142 md5 = "c47b36ceb17eaff3ecfab3bcd347d0df";
156 143 };
157 144 meta = {
158 145 license = [ pkgs.lib.licenses.bsdOriginal ];
159 146 };
160 147 };
161 148 decorator = super.buildPythonPackage {
162 149 name = "decorator-4.0.11";
163 150 buildInputs = with self; [];
164 151 doCheck = false;
165 152 propagatedBuildInputs = with self; [];
166 153 src = fetchurl {
167 154 url = "https://pypi.python.org/packages/cc/ac/5a16f1fc0506ff72fcc8fd4e858e3a1c231f224ab79bb7c4c9b2094cc570/decorator-4.0.11.tar.gz";
168 155 md5 = "73644c8f0bd4983d1b6a34b49adec0ae";
169 156 };
170 157 meta = {
171 158 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ];
172 159 };
173 160 };
174 161 dulwich = super.buildPythonPackage {
175 162 name = "dulwich-0.13.0";
176 163 buildInputs = with self; [];
177 164 doCheck = false;
178 165 propagatedBuildInputs = with self; [];
179 166 src = fetchurl {
180 167 url = "https://pypi.python.org/packages/84/95/732d280eee829dacc954e8109f97b47abcadcca472c2ab013e1635eb4792/dulwich-0.13.0.tar.gz";
181 168 md5 = "6dede0626657c2bd08f48ca1221eea91";
182 169 };
183 170 meta = {
184 171 license = [ pkgs.lib.licenses.gpl2Plus ];
185 172 };
186 173 };
187 174 enum34 = super.buildPythonPackage {
188 175 name = "enum34-1.1.6";
189 176 buildInputs = with self; [];
190 177 doCheck = false;
191 178 propagatedBuildInputs = with self; [];
192 179 src = fetchurl {
193 180 url = "https://pypi.python.org/packages/bf/3e/31d502c25302814a7c2f1d3959d2a3b3f78e509002ba91aea64993936876/enum34-1.1.6.tar.gz";
194 181 md5 = "5f13a0841a61f7fc295c514490d120d0";
195 182 };
196 183 meta = {
197 184 license = [ pkgs.lib.licenses.bsdOriginal ];
198 185 };
199 186 };
200 187 gevent = super.buildPythonPackage {
201 188 name = "gevent-1.1.2";
202 189 buildInputs = with self; [];
203 190 doCheck = false;
204 191 propagatedBuildInputs = with self; [greenlet];
205 192 src = fetchurl {
206 193 url = "https://pypi.python.org/packages/43/8f/cb3224a0e6ab663547f45c10d0651cfd52633fde4283bf68d627084df8cc/gevent-1.1.2.tar.gz";
207 194 md5 = "bb32a2f852a4997138014d5007215c6e";
208 195 };
209 196 meta = {
210 197 license = [ pkgs.lib.licenses.mit ];
211 198 };
212 199 };
213 200 gprof2dot = super.buildPythonPackage {
214 201 name = "gprof2dot-2016.10.13";
215 202 buildInputs = with self; [];
216 203 doCheck = false;
217 204 propagatedBuildInputs = with self; [];
218 205 src = fetchurl {
219 206 url = "https://pypi.python.org/packages/a0/e0/73c71baed306f0402a00a94ffc7b2be94ad1296dfcb8b46912655b93154c/gprof2dot-2016.10.13.tar.gz";
220 207 md5 = "0125401f15fd2afe1df686a76c64a4fd";
221 208 };
222 209 meta = {
223 210 license = [ { fullName = "LGPL"; } ];
224 211 };
225 212 };
226 213 greenlet = super.buildPythonPackage {
227 214 name = "greenlet-0.4.10";
228 215 buildInputs = with self; [];
229 216 doCheck = false;
230 217 propagatedBuildInputs = with self; [];
231 218 src = fetchurl {
232 219 url = "https://pypi.python.org/packages/67/62/ca2a95648666eaa2ffeb6a9b3964f21d419ae27f82f2e66b53da5b943fc4/greenlet-0.4.10.zip";
233 220 md5 = "bed0c4b3b896702131f4d5c72f87c41d";
234 221 };
235 222 meta = {
236 223 license = [ pkgs.lib.licenses.mit ];
237 224 };
238 225 };
239 226 gunicorn = super.buildPythonPackage {
240 227 name = "gunicorn-19.6.0";
241 228 buildInputs = with self; [];
242 229 doCheck = false;
243 230 propagatedBuildInputs = with self; [];
244 231 src = fetchurl {
245 232 url = "https://pypi.python.org/packages/84/ce/7ea5396efad1cef682bbc4068e72a0276341d9d9d0f501da609fab9fcb80/gunicorn-19.6.0.tar.gz";
246 233 md5 = "338e5e8a83ea0f0625f768dba4597530";
247 234 };
248 235 meta = {
249 236 license = [ pkgs.lib.licenses.mit ];
250 237 };
251 238 };
252 239 hgsubversion = super.buildPythonPackage {
253 240 name = "hgsubversion-1.8.6";
254 241 buildInputs = with self; [];
255 242 doCheck = false;
256 243 propagatedBuildInputs = with self; [mercurial subvertpy];
257 244 src = fetchurl {
258 245 url = "https://pypi.python.org/packages/ce/97/032e5093ad250e9908cea04395cbddb6902d587f712a79b53b2d778bdfdd/hgsubversion-1.8.6.tar.gz";
259 246 md5 = "9310cb266031cf8d0779885782a84a5b";
260 247 };
261 248 meta = {
262 249 license = [ pkgs.lib.licenses.gpl1 ];
263 250 };
264 251 };
265 252 infrae.cache = super.buildPythonPackage {
266 253 name = "infrae.cache-1.0.1";
267 254 buildInputs = with self; [];
268 255 doCheck = false;
269 256 propagatedBuildInputs = with self; [Beaker repoze.lru];
270 257 src = fetchurl {
271 258 url = "https://pypi.python.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz";
272 259 md5 = "b09076a766747e6ed2a755cc62088e32";
273 260 };
274 261 meta = {
275 262 license = [ pkgs.lib.licenses.zpt21 ];
276 263 };
277 264 };
278 265 ipdb = super.buildPythonPackage {
279 266 name = "ipdb-0.10.1";
280 267 buildInputs = with self; [];
281 268 doCheck = false;
282 269 propagatedBuildInputs = with self; [ipython setuptools];
283 270 src = fetchurl {
284 271 url = "https://pypi.python.org/packages/eb/0a/0a37dc19572580336ad3813792c0d18c8d7117c2d66fc63c501f13a7a8f8/ipdb-0.10.1.tar.gz";
285 272 md5 = "4aeab65f633ddc98ebdb5eebf08dc713";
286 273 };
287 274 meta = {
288 275 license = [ pkgs.lib.licenses.bsdOriginal ];
289 276 };
290 277 };
291 278 ipython = super.buildPythonPackage {
292 279 name = "ipython-5.1.0";
293 280 buildInputs = with self; [];
294 281 doCheck = false;
295 282 propagatedBuildInputs = with self; [setuptools decorator pickleshare simplegeneric traitlets prompt-toolkit pygments pexpect backports.shutil-get-terminal-size pathlib2 pexpect];
296 283 src = fetchurl {
297 284 url = "https://pypi.python.org/packages/89/63/a9292f7cd9d0090a0f995e1167f3f17d5889dcbc9a175261719c513b9848/ipython-5.1.0.tar.gz";
298 285 md5 = "47c8122420f65b58784cb4b9b4af35e3";
299 286 };
300 287 meta = {
301 288 license = [ pkgs.lib.licenses.bsdOriginal ];
302 289 };
303 290 };
304 291 ipython-genutils = super.buildPythonPackage {
305 292 name = "ipython-genutils-0.2.0";
306 293 buildInputs = with self; [];
307 294 doCheck = false;
308 295 propagatedBuildInputs = with self; [];
309 296 src = fetchurl {
310 297 url = "https://pypi.python.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz";
311 298 md5 = "5a4f9781f78466da0ea1a648f3e1f79f";
312 299 };
313 300 meta = {
314 301 license = [ pkgs.lib.licenses.bsdOriginal ];
315 302 };
316 303 };
317 304 mercurial = super.buildPythonPackage {
318 305 name = "mercurial-4.1.2";
319 306 buildInputs = with self; [];
320 307 doCheck = false;
321 308 propagatedBuildInputs = with self; [];
322 309 src = fetchurl {
323 310 url = "https://pypi.python.org/packages/88/c1/f0501fd67f5e69346da41ee0bd7b2619ce4bbc9854bb645074c418b9941f/mercurial-4.1.2.tar.gz";
324 311 md5 = "934c99808bdc8385e074b902d59b0d93";
325 312 };
326 313 meta = {
327 314 license = [ pkgs.lib.licenses.gpl1 pkgs.lib.licenses.gpl2Plus ];
328 315 };
329 316 };
330 317 mock = super.buildPythonPackage {
331 318 name = "mock-1.0.1";
332 319 buildInputs = with self; [];
333 320 doCheck = false;
334 321 propagatedBuildInputs = with self; [];
335 322 src = fetchurl {
336 323 url = "https://pypi.python.org/packages/15/45/30273ee91feb60dabb8fbb2da7868520525f02cf910279b3047182feed80/mock-1.0.1.zip";
337 324 md5 = "869f08d003c289a97c1a6610faf5e913";
338 325 };
339 326 meta = {
340 327 license = [ pkgs.lib.licenses.bsdOriginal ];
341 328 };
342 329 };
343 330 msgpack-python = super.buildPythonPackage {
344 331 name = "msgpack-python-0.4.8";
345 332 buildInputs = with self; [];
346 333 doCheck = false;
347 334 propagatedBuildInputs = with self; [];
348 335 src = fetchurl {
349 336 url = "https://pypi.python.org/packages/21/27/8a1d82041c7a2a51fcc73675875a5f9ea06c2663e02fcfeb708be1d081a0/msgpack-python-0.4.8.tar.gz";
350 337 md5 = "dcd854fb41ee7584ebbf35e049e6be98";
351 338 };
352 339 meta = {
353 340 license = [ pkgs.lib.licenses.asl20 ];
354 341 };
355 342 };
356 343 pathlib2 = super.buildPythonPackage {
357 344 name = "pathlib2-2.1.0";
358 345 buildInputs = with self; [];
359 346 doCheck = false;
360 347 propagatedBuildInputs = with self; [six];
361 348 src = fetchurl {
362 349 url = "https://pypi.python.org/packages/c9/27/8448b10d8440c08efeff0794adf7d0ed27adb98372c70c7b38f3947d4749/pathlib2-2.1.0.tar.gz";
363 350 md5 = "38e4f58b4d69dfcb9edb49a54a8b28d2";
364 351 };
365 352 meta = {
366 353 license = [ pkgs.lib.licenses.mit ];
367 354 };
368 355 };
369 356 pexpect = super.buildPythonPackage {
370 357 name = "pexpect-4.2.1";
371 358 buildInputs = with self; [];
372 359 doCheck = false;
373 360 propagatedBuildInputs = with self; [ptyprocess];
374 361 src = fetchurl {
375 362 url = "https://pypi.python.org/packages/e8/13/d0b0599099d6cd23663043a2a0bb7c61e58c6ba359b2656e6fb000ef5b98/pexpect-4.2.1.tar.gz";
376 363 md5 = "3694410001a99dff83f0b500a1ca1c95";
377 364 };
378 365 meta = {
379 366 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
380 367 };
381 368 };
382 369 pickleshare = super.buildPythonPackage {
383 370 name = "pickleshare-0.7.4";
384 371 buildInputs = with self; [];
385 372 doCheck = false;
386 373 propagatedBuildInputs = with self; [pathlib2];
387 374 src = fetchurl {
388 375 url = "https://pypi.python.org/packages/69/fe/dd137d84daa0fd13a709e448138e310d9ea93070620c9db5454e234af525/pickleshare-0.7.4.tar.gz";
389 376 md5 = "6a9e5dd8dfc023031f6b7b3f824cab12";
390 377 };
391 378 meta = {
392 379 license = [ pkgs.lib.licenses.mit ];
393 380 };
394 381 };
395 382 prompt-toolkit = super.buildPythonPackage {
396 383 name = "prompt-toolkit-1.0.14";
397 384 buildInputs = with self; [];
398 385 doCheck = false;
399 386 propagatedBuildInputs = with self; [six wcwidth];
400 387 src = fetchurl {
401 388 url = "https://pypi.python.org/packages/55/56/8c39509b614bda53e638b7500f12577d663ac1b868aef53426fc6a26c3f5/prompt_toolkit-1.0.14.tar.gz";
402 389 md5 = "f24061ae133ed32c6b764e92bd48c496";
403 390 };
404 391 meta = {
405 392 license = [ pkgs.lib.licenses.bsdOriginal ];
406 393 };
407 394 };
408 395 ptyprocess = super.buildPythonPackage {
409 396 name = "ptyprocess-0.5.1";
410 397 buildInputs = with self; [];
411 398 doCheck = false;
412 399 propagatedBuildInputs = with self; [];
413 400 src = fetchurl {
414 401 url = "https://pypi.python.org/packages/db/d7/b465161910f3d1cef593c5e002bff67e0384898f597f1a7fdc8db4c02bf6/ptyprocess-0.5.1.tar.gz";
415 402 md5 = "94e537122914cc9ec9c1eadcd36e73a1";
416 403 };
417 404 meta = {
418 405 license = [ ];
419 406 };
420 407 };
421 408 py = super.buildPythonPackage {
422 409 name = "py-1.4.31";
423 410 buildInputs = with self; [];
424 411 doCheck = false;
425 412 propagatedBuildInputs = with self; [];
426 413 src = fetchurl {
427 414 url = "https://pypi.python.org/packages/f4/9a/8dfda23f36600dd701c6722316ba8a3ab4b990261f83e7d3ffc6dfedf7ef/py-1.4.31.tar.gz";
428 415 md5 = "5d2c63c56dc3f2115ec35c066ecd582b";
429 416 };
430 417 meta = {
431 418 license = [ pkgs.lib.licenses.mit ];
432 419 };
433 420 };
434 421 pygments = super.buildPythonPackage {
435 422 name = "pygments-2.2.0";
436 423 buildInputs = with self; [];
437 424 doCheck = false;
438 425 propagatedBuildInputs = with self; [];
439 426 src = fetchurl {
440 427 url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
441 428 md5 = "13037baca42f16917cbd5ad2fab50844";
442 429 };
443 430 meta = {
444 431 license = [ pkgs.lib.licenses.bsdOriginal ];
445 432 };
446 433 };
447 434 pyramid = super.buildPythonPackage {
448 435 name = "pyramid-1.7.4";
449 436 buildInputs = with self; [];
450 437 doCheck = false;
451 438 propagatedBuildInputs = with self; [setuptools WebOb repoze.lru zope.interface zope.deprecation venusian translationstring PasteDeploy];
452 439 src = fetchurl {
453 440 url = "https://pypi.python.org/packages/33/91/55f5c661f8923902cd1f68d75f2b937c45e7682857356cf18f0be5493899/pyramid-1.7.4.tar.gz";
454 441 md5 = "6ef1dfdcff9136d04490410757c4c446";
455 442 };
456 443 meta = {
457 444 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
458 445 };
459 446 };
460 447 pyramid-jinja2 = super.buildPythonPackage {
461 448 name = "pyramid-jinja2-2.5";
462 449 buildInputs = with self; [];
463 450 doCheck = false;
464 451 propagatedBuildInputs = with self; [pyramid zope.deprecation Jinja2 MarkupSafe];
465 452 src = fetchurl {
466 453 url = "https://pypi.python.org/packages/a1/80/595e26ffab7deba7208676b6936b7e5a721875710f982e59899013cae1ed/pyramid_jinja2-2.5.tar.gz";
467 454 md5 = "07cb6547204ac5e6f0b22a954ccee928";
468 455 };
469 456 meta = {
470 457 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
471 458 };
472 459 };
473 460 pyramid-mako = super.buildPythonPackage {
474 461 name = "pyramid-mako-1.0.2";
475 462 buildInputs = with self; [];
476 463 doCheck = false;
477 464 propagatedBuildInputs = with self; [pyramid Mako];
478 465 src = fetchurl {
479 466 url = "https://pypi.python.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz";
480 467 md5 = "ee25343a97eb76bd90abdc2a774eb48a";
481 468 };
482 469 meta = {
483 470 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
484 471 };
485 472 };
486 473 pytest = super.buildPythonPackage {
487 474 name = "pytest-3.0.5";
488 475 buildInputs = with self; [];
489 476 doCheck = false;
490 477 propagatedBuildInputs = with self; [py];
491 478 src = fetchurl {
492 479 url = "https://pypi.python.org/packages/a8/87/b7ca49efe52d2b4169f2bfc49aa5e384173c4619ea8e635f123a0dac5b75/pytest-3.0.5.tar.gz";
493 480 md5 = "cefd527b59332688bf5db4a10aa8a7cb";
494 481 };
495 482 meta = {
496 483 license = [ pkgs.lib.licenses.mit ];
497 484 };
498 485 };
499 486 pytest-catchlog = super.buildPythonPackage {
500 487 name = "pytest-catchlog-1.2.2";
501 488 buildInputs = with self; [];
502 489 doCheck = false;
503 490 propagatedBuildInputs = with self; [py pytest];
504 491 src = fetchurl {
505 492 url = "https://pypi.python.org/packages/f2/2b/2faccdb1a978fab9dd0bf31cca9f6847fbe9184a0bdcc3011ac41dd44191/pytest-catchlog-1.2.2.zip";
506 493 md5 = "09d890c54c7456c818102b7ff8c182c8";
507 494 };
508 495 meta = {
509 496 license = [ pkgs.lib.licenses.mit ];
510 497 };
511 498 };
512 499 pytest-cov = super.buildPythonPackage {
513 500 name = "pytest-cov-2.4.0";
514 501 buildInputs = with self; [];
515 502 doCheck = false;
516 503 propagatedBuildInputs = with self; [pytest coverage];
517 504 src = fetchurl {
518 505 url = "https://pypi.python.org/packages/00/c0/2bfd1fcdb9d407b8ac8185b1cb5ff458105c6b207a9a7f0e13032de9828f/pytest-cov-2.4.0.tar.gz";
519 506 md5 = "2fda09677d232acc99ec1b3c5831e33f";
520 507 };
521 508 meta = {
522 509 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.mit ];
523 510 };
524 511 };
525 512 pytest-profiling = super.buildPythonPackage {
526 513 name = "pytest-profiling-1.2.2";
527 514 buildInputs = with self; [];
528 515 doCheck = false;
529 516 propagatedBuildInputs = with self; [six pytest gprof2dot];
530 517 src = fetchurl {
531 518 url = "https://pypi.python.org/packages/73/e8/804681323bac0bc45c520ec34185ba8469008942266d0074699b204835c1/pytest-profiling-1.2.2.tar.gz";
532 519 md5 = "0a16d7dda2d23b91e9730fa4558cf728";
533 520 };
534 521 meta = {
535 522 license = [ pkgs.lib.licenses.mit ];
536 523 };
537 524 };
538 525 pytest-runner = super.buildPythonPackage {
539 526 name = "pytest-runner-2.9";
540 527 buildInputs = with self; [];
541 528 doCheck = false;
542 529 propagatedBuildInputs = with self; [];
543 530 src = fetchurl {
544 531 url = "https://pypi.python.org/packages/11/d4/c335ddf94463e451109e3494e909765c3e5205787b772e3b25ee8601b86a/pytest-runner-2.9.tar.gz";
545 532 md5 = "2212a2e34404b0960b2fdc2c469247b2";
546 533 };
547 534 meta = {
548 535 license = [ pkgs.lib.licenses.mit ];
549 536 };
550 537 };
551 538 pytest-sugar = super.buildPythonPackage {
552 539 name = "pytest-sugar-0.7.1";
553 540 buildInputs = with self; [];
554 541 doCheck = false;
555 542 propagatedBuildInputs = with self; [pytest termcolor];
556 543 src = fetchurl {
557 544 url = "https://pypi.python.org/packages/03/97/05d988b4fa870e7373e8ee4582408543b9ca2bd35c3c67b569369c6f9c49/pytest-sugar-0.7.1.tar.gz";
558 545 md5 = "7400f7c11f3d572b2c2a3b60352d35fe";
559 546 };
560 547 meta = {
561 548 license = [ pkgs.lib.licenses.bsdOriginal ];
562 549 };
563 550 };
564 551 pytest-timeout = super.buildPythonPackage {
565 552 name = "pytest-timeout-1.2.0";
566 553 buildInputs = with self; [];
567 554 doCheck = false;
568 555 propagatedBuildInputs = with self; [pytest];
569 556 src = fetchurl {
570 557 url = "https://pypi.python.org/packages/cc/b7/b2a61365ea6b6d2e8881360ae7ed8dad0327ad2df89f2f0be4a02304deb2/pytest-timeout-1.2.0.tar.gz";
571 558 md5 = "83607d91aa163562c7ee835da57d061d";
572 559 };
573 560 meta = {
574 561 license = [ pkgs.lib.licenses.mit { fullName = "DFSG approved"; } ];
575 562 };
576 563 };
577 564 repoze.lru = super.buildPythonPackage {
578 565 name = "repoze.lru-0.6";
579 566 buildInputs = with self; [];
580 567 doCheck = false;
581 568 propagatedBuildInputs = with self; [];
582 569 src = fetchurl {
583 570 url = "https://pypi.python.org/packages/6e/1e/aa15cc90217e086dc8769872c8778b409812ff036bf021b15795638939e4/repoze.lru-0.6.tar.gz";
584 571 md5 = "2c3b64b17a8e18b405f55d46173e14dd";
585 572 };
586 573 meta = {
587 574 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
588 575 };
589 576 };
590 577 rhodecode-vcsserver = super.buildPythonPackage {
591 578 name = "rhodecode-vcsserver-4.8.0";
592 579 buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj];
593 580 doCheck = true;
594 propagatedBuildInputs = with self; [Beaker configobj decorator dulwich hgsubversion infrae.cache mercurial msgpack-python pyramid pyramid-jinja2 pyramid-mako repoze.lru simplejson subprocess32 subvertpy six translationstring WebOb wheel zope.deprecation zope.interface ipdb ipython gevent greenlet gunicorn waitress Pyro4 serpent pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage];
581 propagatedBuildInputs = with self; [Beaker configobj decorator dulwich hgsubversion infrae.cache mercurial msgpack-python pyramid pyramid-jinja2 pyramid-mako repoze.lru simplejson subprocess32 subvertpy six translationstring WebOb wheel zope.deprecation zope.interface ipdb ipython gevent greenlet gunicorn waitress pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage];
595 582 src = ./.;
596 583 meta = {
597 584 license = [ { fullName = "GPL V3"; } { fullName = "GNU General Public License v3 or later (GPLv3+)"; } ];
598 585 };
599 586 };
600 serpent = super.buildPythonPackage {
601 name = "serpent-1.15";
602 buildInputs = with self; [];
603 doCheck = false;
604 propagatedBuildInputs = with self; [];
605 src = fetchurl {
606 url = "https://pypi.python.org/packages/7b/38/b2b27673a882ff2ea5871bb3e3e6b496ebbaafd1612e51990ffb158b9254/serpent-1.15.tar.gz";
607 md5 = "e27b1aad5c218e16442f52abb7c7053a";
608 };
609 meta = {
610 license = [ pkgs.lib.licenses.mit ];
611 };
612 };
613 587 setuptools = super.buildPythonPackage {
614 588 name = "setuptools-30.1.0";
615 589 buildInputs = with self; [];
616 590 doCheck = false;
617 591 propagatedBuildInputs = with self; [];
618 592 src = fetchurl {
619 593 url = "https://pypi.python.org/packages/1e/43/002c8616db9a3e7be23c2556e39b90a32bb40ba0dc652de1999d5334d372/setuptools-30.1.0.tar.gz";
620 594 md5 = "cac497f42e5096ac8df29e38d3f81c3e";
621 595 };
622 596 meta = {
623 597 license = [ pkgs.lib.licenses.mit ];
624 598 };
625 599 };
626 600 simplegeneric = super.buildPythonPackage {
627 601 name = "simplegeneric-0.8.1";
628 602 buildInputs = with self; [];
629 603 doCheck = false;
630 604 propagatedBuildInputs = with self; [];
631 605 src = fetchurl {
632 606 url = "https://pypi.python.org/packages/3d/57/4d9c9e3ae9a255cd4e1106bb57e24056d3d0709fc01b2e3e345898e49d5b/simplegeneric-0.8.1.zip";
633 607 md5 = "f9c1fab00fd981be588fc32759f474e3";
634 608 };
635 609 meta = {
636 610 license = [ pkgs.lib.licenses.zpt21 ];
637 611 };
638 612 };
639 613 simplejson = super.buildPythonPackage {
640 614 name = "simplejson-3.7.2";
641 615 buildInputs = with self; [];
642 616 doCheck = false;
643 617 propagatedBuildInputs = with self; [];
644 618 src = fetchurl {
645 619 url = "https://pypi.python.org/packages/6d/89/7f13f099344eea9d6722779a1f165087cb559598107844b1ac5dbd831fb1/simplejson-3.7.2.tar.gz";
646 620 md5 = "a5fc7d05d4cb38492285553def5d4b46";
647 621 };
648 622 meta = {
649 623 license = [ { fullName = "Academic Free License (AFL)"; } pkgs.lib.licenses.mit ];
650 624 };
651 625 };
652 626 six = super.buildPythonPackage {
653 627 name = "six-1.9.0";
654 628 buildInputs = with self; [];
655 629 doCheck = false;
656 630 propagatedBuildInputs = with self; [];
657 631 src = fetchurl {
658 632 url = "https://pypi.python.org/packages/16/64/1dc5e5976b17466fd7d712e59cbe9fb1e18bec153109e5ba3ed6c9102f1a/six-1.9.0.tar.gz";
659 633 md5 = "476881ef4012262dfc8adc645ee786c4";
660 634 };
661 635 meta = {
662 636 license = [ pkgs.lib.licenses.mit ];
663 637 };
664 638 };
665 639 subprocess32 = super.buildPythonPackage {
666 640 name = "subprocess32-3.2.6";
667 641 buildInputs = with self; [];
668 642 doCheck = false;
669 643 propagatedBuildInputs = with self; [];
670 644 src = fetchurl {
671 645 url = "https://pypi.python.org/packages/28/8d/33ccbff51053f59ae6c357310cac0e79246bbed1d345ecc6188b176d72c3/subprocess32-3.2.6.tar.gz";
672 646 md5 = "754c5ab9f533e764f931136974b618f1";
673 647 };
674 648 meta = {
675 649 license = [ pkgs.lib.licenses.psfl ];
676 650 };
677 651 };
678 652 subvertpy = super.buildPythonPackage {
679 653 name = "subvertpy-0.9.3";
680 654 buildInputs = with self; [];
681 655 doCheck = false;
682 656 propagatedBuildInputs = with self; [];
683 657 src = fetchurl {
684 658 url = "https://code.rhodecode.com/upstream/subvertpy/archive/subvertpy-0.9.3.tar.gz?md5=4e49da2fe07608239cc9a80a7bb8f33c";
685 659 md5 = "4e49da2fe07608239cc9a80a7bb8f33c";
686 660 };
687 661 meta = {
688 662 license = [ pkgs.lib.licenses.lgpl21Plus ];
689 663 };
690 664 };
691 665 termcolor = super.buildPythonPackage {
692 666 name = "termcolor-1.1.0";
693 667 buildInputs = with self; [];
694 668 doCheck = false;
695 669 propagatedBuildInputs = with self; [];
696 670 src = fetchurl {
697 671 url = "https://pypi.python.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz";
698 672 md5 = "043e89644f8909d462fbbfa511c768df";
699 673 };
700 674 meta = {
701 675 license = [ pkgs.lib.licenses.mit ];
702 676 };
703 677 };
704 678 traitlets = super.buildPythonPackage {
705 679 name = "traitlets-4.3.2";
706 680 buildInputs = with self; [];
707 681 doCheck = false;
708 682 propagatedBuildInputs = with self; [ipython-genutils six decorator enum34];
709 683 src = fetchurl {
710 684 url = "https://pypi.python.org/packages/a5/98/7f5ef2fe9e9e071813aaf9cb91d1a732e0a68b6c44a32b38cb8e14c3f069/traitlets-4.3.2.tar.gz";
711 685 md5 = "3068663f2f38fd939a9eb3a500ccc154";
712 686 };
713 687 meta = {
714 688 license = [ pkgs.lib.licenses.bsdOriginal ];
715 689 };
716 690 };
717 691 translationstring = super.buildPythonPackage {
718 692 name = "translationstring-1.3";
719 693 buildInputs = with self; [];
720 694 doCheck = false;
721 695 propagatedBuildInputs = with self; [];
722 696 src = fetchurl {
723 697 url = "https://pypi.python.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz";
724 698 md5 = "a4b62e0f3c189c783a1685b3027f7c90";
725 699 };
726 700 meta = {
727 701 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
728 702 };
729 703 };
730 704 venusian = super.buildPythonPackage {
731 705 name = "venusian-1.0";
732 706 buildInputs = with self; [];
733 707 doCheck = false;
734 708 propagatedBuildInputs = with self; [];
735 709 src = fetchurl {
736 710 url = "https://pypi.python.org/packages/86/20/1948e0dfc4930ddde3da8c33612f6a5717c0b4bc28f591a5c5cf014dd390/venusian-1.0.tar.gz";
737 711 md5 = "dccf2eafb7113759d60c86faf5538756";
738 712 };
739 713 meta = {
740 714 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
741 715 };
742 716 };
743 717 waitress = super.buildPythonPackage {
744 718 name = "waitress-1.0.1";
745 719 buildInputs = with self; [];
746 720 doCheck = false;
747 721 propagatedBuildInputs = with self; [];
748 722 src = fetchurl {
749 723 url = "https://pypi.python.org/packages/78/7d/84d11b96c3f60164dec3bef4a859a03aeae0231aa93f57fbe0d05fa4ff36/waitress-1.0.1.tar.gz";
750 724 md5 = "dda92358a7569669086155923a46e57c";
751 725 };
752 726 meta = {
753 727 license = [ pkgs.lib.licenses.zpt21 ];
754 728 };
755 729 };
756 730 wcwidth = super.buildPythonPackage {
757 731 name = "wcwidth-0.1.7";
758 732 buildInputs = with self; [];
759 733 doCheck = false;
760 734 propagatedBuildInputs = with self; [];
761 735 src = fetchurl {
762 736 url = "https://pypi.python.org/packages/55/11/e4a2bb08bb450fdbd42cc709dd40de4ed2c472cf0ccb9e64af22279c5495/wcwidth-0.1.7.tar.gz";
763 737 md5 = "b3b6a0a08f0c8a34d1de8cf44150a4ad";
764 738 };
765 739 meta = {
766 740 license = [ pkgs.lib.licenses.mit ];
767 741 };
768 742 };
769 743 wheel = super.buildPythonPackage {
770 744 name = "wheel-0.29.0";
771 745 buildInputs = with self; [];
772 746 doCheck = false;
773 747 propagatedBuildInputs = with self; [];
774 748 src = fetchurl {
775 749 url = "https://pypi.python.org/packages/c9/1d/bd19e691fd4cfe908c76c429fe6e4436c9e83583c4414b54f6c85471954a/wheel-0.29.0.tar.gz";
776 750 md5 = "555a67e4507cedee23a0deb9651e452f";
777 751 };
778 752 meta = {
779 753 license = [ pkgs.lib.licenses.mit ];
780 754 };
781 755 };
782 756 zope.deprecation = super.buildPythonPackage {
783 757 name = "zope.deprecation-4.1.2";
784 758 buildInputs = with self; [];
785 759 doCheck = false;
786 760 propagatedBuildInputs = with self; [setuptools];
787 761 src = fetchurl {
788 762 url = "https://pypi.python.org/packages/c1/d3/3919492d5e57d8dd01b36f30b34fc8404a30577392b1eb817c303499ad20/zope.deprecation-4.1.2.tar.gz";
789 763 md5 = "e9a663ded58f4f9f7881beb56cae2782";
790 764 };
791 765 meta = {
792 766 license = [ pkgs.lib.licenses.zpt21 ];
793 767 };
794 768 };
795 769 zope.interface = super.buildPythonPackage {
796 770 name = "zope.interface-4.1.3";
797 771 buildInputs = with self; [];
798 772 doCheck = false;
799 773 propagatedBuildInputs = with self; [setuptools];
800 774 src = fetchurl {
801 775 url = "https://pypi.python.org/packages/9d/81/2509ca3c6f59080123c1a8a97125eb48414022618cec0e64eb1313727bfe/zope.interface-4.1.3.tar.gz";
802 776 md5 = "9ae3d24c0c7415deb249dd1a132f0f79";
803 777 };
804 778 meta = {
805 779 license = [ pkgs.lib.licenses.zpt21 ];
806 780 };
807 781 };
808 782
809 783 ### Test requirements
810 784
811 785
812 786 }
@@ -1,43 +1,39 b''
1 1 ## core
2 2 setuptools==30.1.0
3 3
4 4 Beaker==1.7.0
5 5 configobj==5.0.6
6 6 decorator==4.0.11
7 7 dulwich==0.13.0
8 8 hgsubversion==1.8.6
9 9 infrae.cache==1.0.1
10 10 mercurial==4.1.2
11 11 msgpack-python==0.4.8
12 12 pyramid-jinja2==2.5
13 13 pyramid==1.7.4
14 14 pyramid-mako==1.0.2
15 15 repoze.lru==0.6
16 16 simplejson==3.7.2
17 17 subprocess32==3.2.6
18 18
19 19 # Custom subvertpy that is not available on pypi.
20 20 https://code.rhodecode.com/upstream/subvertpy/archive/subvertpy-0.9.3.tar.gz?md5=4e49da2fe07608239cc9a80a7bb8f33c#egg=subvertpy==0.9.3
21 21
22 22 six==1.9.0
23 23 translationstring==1.3
24 24 WebOb==1.3.1
25 25 wheel==0.29.0
26 26 zope.deprecation==4.1.2
27 27 zope.interface==4.1.3
28 28
29 29 ## debug
30 30 ipdb==0.10.1
31 31 ipython==5.1.0
32 32 # http servers
33 33 gevent==1.1.2
34 34 greenlet==0.4.10
35 35 gunicorn==19.6.0
36 36 waitress==1.0.1
37 37
38 # Pyro/Deprecated TODO(Marcink): remove in 4.7 release.
39 Pyro4==4.41
40 serpent==1.15
41
42 38 ## test related requirements
43 39 -r requirements_test.txt
@@ -1,93 +1,87 b''
1 1 ################################################################################
2 2 # RhodeCode VCSServer - configuration #
3 3 # #
4 4 ################################################################################
5 5
6 6 [DEFAULT]
7 7 host = 127.0.0.1
8 8 port = 9901
9 9 locale = en_US.UTF-8
10 10 # number of worker threads, this should be set based on a formula threadpool=N*6
11 11 # where N is number of RhodeCode Enterprise workers, eg. running 2 instances
12 12 # 8 gunicorn workers each would be 2 * 8 * 6 = 96, threadpool_size = 96
13 13 threadpool_size = 96
14 14 timeout = 0
15 15
16 16 # cache regions, please don't change
17 17 beaker.cache.regions = repo_object
18 18 beaker.cache.repo_object.type = memorylru
19 19 beaker.cache.repo_object.max_items = 100
20 20 # cache auto-expires after N seconds
21 21 beaker.cache.repo_object.expire = 300
22 22 beaker.cache.repo_object.enabled = true
23 23
24 24
25 25 ################################
26 26 ### LOGGING CONFIGURATION ####
27 27 ################################
28 28 [loggers]
29 keys = root, vcsserver, pyro4, beaker
29 keys = root, vcsserver, beaker
30 30
31 31 [handlers]
32 32 keys = console
33 33
34 34 [formatters]
35 35 keys = generic
36 36
37 37 #############
38 38 ## LOGGERS ##
39 39 #############
40 40 [logger_root]
41 41 level = NOTSET
42 42 handlers = console
43 43
44 44 [logger_vcsserver]
45 45 level = DEBUG
46 46 handlers =
47 47 qualname = vcsserver
48 48 propagate = 1
49 49
50 50 [logger_beaker]
51 51 level = DEBUG
52 52 handlers =
53 53 qualname = beaker
54 54 propagate = 1
55 55
56 [logger_pyro4]
57 level = DEBUG
58 handlers =
59 qualname = Pyro4
60 propagate = 1
61
62 56
63 57 ##############
64 58 ## HANDLERS ##
65 59 ##############
66 60
67 61 [handler_console]
68 62 class = StreamHandler
69 63 args = (sys.stderr,)
70 64 level = INFO
71 65 formatter = generic
72 66
73 67 [handler_file]
74 68 class = FileHandler
75 69 args = ('vcsserver.log', 'a',)
76 70 level = DEBUG
77 71 formatter = generic
78 72
79 73 [handler_file_rotating]
80 74 class = logging.handlers.TimedRotatingFileHandler
81 75 # 'D', 5 - rotate every 5days
82 76 # you can set 'h', 'midnight'
83 77 args = ('vcsserver.log', 'D', 5, 10,)
84 78 level = DEBUG
85 79 formatter = generic
86 80
87 81 ################
88 82 ## FORMATTERS ##
89 83 ################
90 84
91 85 [formatter_generic]
92 86 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
93 87 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,727 +1,727 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2017 RodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
6 6 # the Free Software Foundation; either version 3 of the License, or
7 7 # (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software Foundation,
16 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18 18 import io
19 19 import logging
20 20 import stat
21 21 import urllib
22 22 import urllib2
23 23
24 24 from hgext import largefiles, rebase
25 25 from hgext.strip import strip as hgext_strip
26 26 from mercurial import commands
27 27 from mercurial import unionrepo
28 28 from mercurial import verify
29 29
30 30 from vcsserver import exceptions
31 31 from vcsserver.base import RepoFactory, obfuscate_qs, raise_from_original
32 32 from vcsserver.hgcompat import (
33 33 archival, bin, clone, config as hgconfig, diffopts, hex,
34 34 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler,
35 35 httppeer, localrepository, match, memctx, exchange, memfilectx, nullrev,
36 36 patch, peer, revrange, ui, Abort, LookupError, RepoError, RepoLookupError,
37 37 InterventionRequired, RequirementError)
38 38
39 39 log = logging.getLogger(__name__)
40 40
41 41
42 42 def make_ui_from_config(repo_config):
43 43 baseui = ui.ui()
44 44
45 45 # clean the baseui object
46 46 baseui._ocfg = hgconfig.config()
47 47 baseui._ucfg = hgconfig.config()
48 48 baseui._tcfg = hgconfig.config()
49 49
50 50 for section, option, value in repo_config:
51 51 baseui.setconfig(section, option, value)
52 52
53 53 # make our hgweb quiet so it doesn't print output
54 54 baseui.setconfig('ui', 'quiet', 'true')
55 55
56 56 # force mercurial to only use 1 thread, otherwise it may try to set a
57 57 # signal in a non-main thread, thus generating a ValueError.
58 58 baseui.setconfig('worker', 'numcpus', 1)
59 59
60 60 # If there is no config for the largefiles extension, we explicitly disable
61 61 # it here. This overrides settings from repositories hgrc file. Recent
62 62 # mercurial versions enable largefiles in hgrc on clone from largefile
63 63 # repo.
64 64 if not baseui.hasconfig('extensions', 'largefiles'):
65 65 log.debug('Explicitly disable largefiles extension for repo.')
66 66 baseui.setconfig('extensions', 'largefiles', '!')
67 67
68 68 return baseui
69 69
70 70
71 71 def reraise_safe_exceptions(func):
72 72 """Decorator for converting mercurial exceptions to something neutral."""
73 73 def wrapper(*args, **kwargs):
74 74 try:
75 75 return func(*args, **kwargs)
76 76 except (Abort, InterventionRequired):
77 77 raise_from_original(exceptions.AbortException)
78 78 except RepoLookupError:
79 79 raise_from_original(exceptions.LookupException)
80 80 except RequirementError:
81 81 raise_from_original(exceptions.RequirementException)
82 82 except RepoError:
83 83 raise_from_original(exceptions.VcsException)
84 84 except LookupError:
85 85 raise_from_original(exceptions.LookupException)
86 86 except Exception as e:
87 87 if not hasattr(e, '_vcs_kind'):
88 88 log.exception("Unhandled exception in hg remote call")
89 89 raise_from_original(exceptions.UnhandledException)
90 90 raise
91 91 return wrapper
92 92
93 93
94 94 class MercurialFactory(RepoFactory):
95 95
96 96 def _create_config(self, config, hooks=True):
97 97 if not hooks:
98 98 hooks_to_clean = frozenset((
99 99 'changegroup.repo_size', 'preoutgoing.pre_pull',
100 100 'outgoing.pull_logger', 'prechangegroup.pre_push'))
101 101 new_config = []
102 102 for section, option, value in config:
103 103 if section == 'hooks' and option in hooks_to_clean:
104 104 continue
105 105 new_config.append((section, option, value))
106 106 config = new_config
107 107
108 108 baseui = make_ui_from_config(config)
109 109 return baseui
110 110
111 111 def _create_repo(self, wire, create):
112 112 baseui = self._create_config(wire["config"])
113 113 return localrepository(baseui, wire["path"], create)
114 114
115 115
116 116 class HgRemote(object):
117 117
118 118 def __init__(self, factory):
119 119 self._factory = factory
120 120
121 121 self._bulk_methods = {
122 122 "affected_files": self.ctx_files,
123 123 "author": self.ctx_user,
124 124 "branch": self.ctx_branch,
125 125 "children": self.ctx_children,
126 126 "date": self.ctx_date,
127 127 "message": self.ctx_description,
128 128 "parents": self.ctx_parents,
129 129 "status": self.ctx_status,
130 130 "_file_paths": self.ctx_list,
131 131 }
132 132
133 133 @reraise_safe_exceptions
134 134 def discover_hg_version(self):
135 135 from mercurial import util
136 136 return util.version()
137 137
138 138 @reraise_safe_exceptions
139 139 def archive_repo(self, archive_path, mtime, file_info, kind):
140 140 if kind == "tgz":
141 141 archiver = archival.tarit(archive_path, mtime, "gz")
142 142 elif kind == "tbz2":
143 143 archiver = archival.tarit(archive_path, mtime, "bz2")
144 144 elif kind == 'zip':
145 145 archiver = archival.zipit(archive_path, mtime)
146 146 else:
147 147 raise exceptions.ArchiveException(
148 148 'Remote does not support: "%s".' % kind)
149 149
150 150 for f_path, f_mode, f_is_link, f_content in file_info:
151 151 archiver.addfile(f_path, f_mode, f_is_link, f_content)
152 152 archiver.done()
153 153
154 154 @reraise_safe_exceptions
155 155 def bookmarks(self, wire):
156 156 repo = self._factory.repo(wire)
157 157 return dict(repo._bookmarks)
158 158
159 159 @reraise_safe_exceptions
160 160 def branches(self, wire, normal, closed):
161 161 repo = self._factory.repo(wire)
162 162 iter_branches = repo.branchmap().iterbranches()
163 163 bt = {}
164 164 for branch_name, _heads, tip, is_closed in iter_branches:
165 165 if normal and not is_closed:
166 166 bt[branch_name] = tip
167 167 if closed and is_closed:
168 168 bt[branch_name] = tip
169 169
170 170 return bt
171 171
172 172 @reraise_safe_exceptions
173 173 def bulk_request(self, wire, rev, pre_load):
174 174 result = {}
175 175 for attr in pre_load:
176 176 try:
177 177 method = self._bulk_methods[attr]
178 178 result[attr] = method(wire, rev)
179 179 except KeyError:
180 180 raise exceptions.VcsException(
181 181 'Unknown bulk attribute: "%s"' % attr)
182 182 return result
183 183
184 184 @reraise_safe_exceptions
185 185 def clone(self, wire, source, dest, update_after_clone=False, hooks=True):
186 186 baseui = self._factory._create_config(wire["config"], hooks=hooks)
187 187 clone(baseui, source, dest, noupdate=not update_after_clone)
188 188
189 189 @reraise_safe_exceptions
190 190 def commitctx(
191 191 self, wire, message, parents, commit_time, commit_timezone,
192 192 user, files, extra, removed, updated):
193 193
194 194 def _filectxfn(_repo, memctx, path):
195 195 """
196 196 Marks given path as added/changed/removed in a given _repo. This is
197 197 for internal mercurial commit function.
198 198 """
199 199
200 200 # check if this path is removed
201 201 if path in removed:
202 202 # returning None is a way to mark node for removal
203 203 return None
204 204
205 205 # check if this path is added
206 206 for node in updated:
207 207 if node['path'] == path:
208 208 return memfilectx(
209 209 _repo,
210 210 path=node['path'],
211 211 data=node['content'],
212 212 islink=False,
213 213 isexec=bool(node['mode'] & stat.S_IXUSR),
214 214 copied=False,
215 215 memctx=memctx)
216 216
217 217 raise exceptions.AbortException(
218 218 "Given path haven't been marked as added, "
219 219 "changed or removed (%s)" % path)
220 220
221 221 repo = self._factory.repo(wire)
222 222
223 223 commit_ctx = memctx(
224 224 repo=repo,
225 225 parents=parents,
226 226 text=message,
227 227 files=files,
228 228 filectxfn=_filectxfn,
229 229 user=user,
230 230 date=(commit_time, commit_timezone),
231 231 extra=extra)
232 232
233 233 n = repo.commitctx(commit_ctx)
234 234 new_id = hex(n)
235 235
236 236 return new_id
237 237
238 238 @reraise_safe_exceptions
239 239 def ctx_branch(self, wire, revision):
240 240 repo = self._factory.repo(wire)
241 241 ctx = repo[revision]
242 242 return ctx.branch()
243 243
244 244 @reraise_safe_exceptions
245 245 def ctx_children(self, wire, revision):
246 246 repo = self._factory.repo(wire)
247 247 ctx = repo[revision]
248 248 return [child.rev() for child in ctx.children()]
249 249
250 250 @reraise_safe_exceptions
251 251 def ctx_date(self, wire, revision):
252 252 repo = self._factory.repo(wire)
253 253 ctx = repo[revision]
254 254 return ctx.date()
255 255
256 256 @reraise_safe_exceptions
257 257 def ctx_description(self, wire, revision):
258 258 repo = self._factory.repo(wire)
259 259 ctx = repo[revision]
260 260 return ctx.description()
261 261
262 262 @reraise_safe_exceptions
263 263 def ctx_diff(
264 264 self, wire, revision, git=True, ignore_whitespace=True, context=3):
265 265 repo = self._factory.repo(wire)
266 266 ctx = repo[revision]
267 267 result = ctx.diff(
268 268 git=git, ignore_whitespace=ignore_whitespace, context=context)
269 269 return list(result)
270 270
271 271 @reraise_safe_exceptions
272 272 def ctx_files(self, wire, revision):
273 273 repo = self._factory.repo(wire)
274 274 ctx = repo[revision]
275 275 return ctx.files()
276 276
277 277 @reraise_safe_exceptions
278 278 def ctx_list(self, path, revision):
279 279 repo = self._factory.repo(path)
280 280 ctx = repo[revision]
281 281 return list(ctx)
282 282
283 283 @reraise_safe_exceptions
284 284 def ctx_parents(self, wire, revision):
285 285 repo = self._factory.repo(wire)
286 286 ctx = repo[revision]
287 287 return [parent.rev() for parent in ctx.parents()]
288 288
289 289 @reraise_safe_exceptions
290 290 def ctx_substate(self, wire, revision):
291 291 repo = self._factory.repo(wire)
292 292 ctx = repo[revision]
293 293 return ctx.substate
294 294
295 295 @reraise_safe_exceptions
296 296 def ctx_status(self, wire, revision):
297 297 repo = self._factory.repo(wire)
298 298 ctx = repo[revision]
299 299 status = repo[ctx.p1().node()].status(other=ctx.node())
300 300 # object of status (odd, custom named tuple in mercurial) is not
301 # correctly serializable via Pyro, we make it a list, as the underling
301 # correctly serializable, we make it a list, as the underling
302 302 # API expects this to be a list
303 303 return list(status)
304 304
305 305 @reraise_safe_exceptions
306 306 def ctx_user(self, wire, revision):
307 307 repo = self._factory.repo(wire)
308 308 ctx = repo[revision]
309 309 return ctx.user()
310 310
311 311 @reraise_safe_exceptions
312 312 def check_url(self, url, config):
313 313 _proto = None
314 314 if '+' in url[:url.find('://')]:
315 315 _proto = url[0:url.find('+')]
316 316 url = url[url.find('+') + 1:]
317 317 handlers = []
318 318 url_obj = url_parser(url)
319 319 test_uri, authinfo = url_obj.authinfo()
320 320 url_obj.passwd = '*****' if url_obj.passwd else url_obj.passwd
321 321 url_obj.query = obfuscate_qs(url_obj.query)
322 322
323 323 cleaned_uri = str(url_obj)
324 324 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
325 325
326 326 if authinfo:
327 327 # create a password manager
328 328 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
329 329 passmgr.add_password(*authinfo)
330 330
331 331 handlers.extend((httpbasicauthhandler(passmgr),
332 332 httpdigestauthhandler(passmgr)))
333 333
334 334 o = urllib2.build_opener(*handlers)
335 335 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
336 336 ('Accept', 'application/mercurial-0.1')]
337 337
338 338 q = {"cmd": 'between'}
339 339 q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
340 340 qs = '?%s' % urllib.urlencode(q)
341 341 cu = "%s%s" % (test_uri, qs)
342 342 req = urllib2.Request(cu, None, {})
343 343
344 344 try:
345 345 log.debug("Trying to open URL %s", cleaned_uri)
346 346 resp = o.open(req)
347 347 if resp.code != 200:
348 348 raise exceptions.URLError('Return Code is not 200')
349 349 except Exception as e:
350 350 log.warning("URL cannot be opened: %s", cleaned_uri, exc_info=True)
351 351 # means it cannot be cloned
352 352 raise exceptions.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
353 353
354 354 # now check if it's a proper hg repo, but don't do it for svn
355 355 try:
356 356 if _proto == 'svn':
357 357 pass
358 358 else:
359 359 # check for pure hg repos
360 360 log.debug(
361 361 "Verifying if URL is a Mercurial repository: %s",
362 362 cleaned_uri)
363 363 httppeer(make_ui_from_config(config), url).lookup('tip')
364 364 except Exception as e:
365 365 log.warning("URL is not a valid Mercurial repository: %s",
366 366 cleaned_uri)
367 367 raise exceptions.URLError(
368 368 "url [%s] does not look like an hg repo org_exc: %s"
369 369 % (cleaned_uri, e))
370 370
371 371 log.info("URL is a valid Mercurial repository: %s", cleaned_uri)
372 372 return True
373 373
374 374 @reraise_safe_exceptions
375 375 def diff(
376 376 self, wire, rev1, rev2, file_filter, opt_git, opt_ignorews,
377 377 context):
378 378 repo = self._factory.repo(wire)
379 379
380 380 if file_filter:
381 381 match_filter = match(file_filter[0], '', [file_filter[1]])
382 382 else:
383 383 match_filter = file_filter
384 384 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context)
385 385
386 386 try:
387 387 return "".join(patch.diff(
388 388 repo, node1=rev1, node2=rev2, match=match_filter, opts=opts))
389 389 except RepoLookupError:
390 390 raise exceptions.LookupException()
391 391
392 392 @reraise_safe_exceptions
393 393 def file_history(self, wire, revision, path, limit):
394 394 repo = self._factory.repo(wire)
395 395
396 396 ctx = repo[revision]
397 397 fctx = ctx.filectx(path)
398 398
399 399 def history_iter():
400 400 limit_rev = fctx.rev()
401 401 for obj in reversed(list(fctx.filelog())):
402 402 obj = fctx.filectx(obj)
403 403 if limit_rev >= obj.rev():
404 404 yield obj
405 405
406 406 history = []
407 407 for cnt, obj in enumerate(history_iter()):
408 408 if limit and cnt >= limit:
409 409 break
410 410 history.append(hex(obj.node()))
411 411
412 412 return [x for x in history]
413 413
414 414 @reraise_safe_exceptions
415 415 def file_history_untill(self, wire, revision, path, limit):
416 416 repo = self._factory.repo(wire)
417 417 ctx = repo[revision]
418 418 fctx = ctx.filectx(path)
419 419
420 420 file_log = list(fctx.filelog())
421 421 if limit:
422 422 # Limit to the last n items
423 423 file_log = file_log[-limit:]
424 424
425 425 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
426 426
427 427 @reraise_safe_exceptions
428 428 def fctx_annotate(self, wire, revision, path):
429 429 repo = self._factory.repo(wire)
430 430 ctx = repo[revision]
431 431 fctx = ctx.filectx(path)
432 432
433 433 result = []
434 434 for i, annotate_data in enumerate(fctx.annotate()):
435 435 ln_no = i + 1
436 436 node_info, content = annotate_data
437 437 sha = hex(node_info[0].node())
438 438 result.append((ln_no, sha, content))
439 439 return result
440 440
441 441 @reraise_safe_exceptions
442 442 def fctx_data(self, wire, revision, path):
443 443 repo = self._factory.repo(wire)
444 444 ctx = repo[revision]
445 445 fctx = ctx.filectx(path)
446 446 return fctx.data()
447 447
448 448 @reraise_safe_exceptions
449 449 def fctx_flags(self, wire, revision, path):
450 450 repo = self._factory.repo(wire)
451 451 ctx = repo[revision]
452 452 fctx = ctx.filectx(path)
453 453 return fctx.flags()
454 454
455 455 @reraise_safe_exceptions
456 456 def fctx_size(self, wire, revision, path):
457 457 repo = self._factory.repo(wire)
458 458 ctx = repo[revision]
459 459 fctx = ctx.filectx(path)
460 460 return fctx.size()
461 461
462 462 @reraise_safe_exceptions
463 463 def get_all_commit_ids(self, wire, name):
464 464 repo = self._factory.repo(wire)
465 465 revs = repo.filtered(name).changelog.index
466 466 return map(lambda x: hex(x[7]), revs)[:-1]
467 467
468 468 @reraise_safe_exceptions
469 469 def get_config_value(self, wire, section, name, untrusted=False):
470 470 repo = self._factory.repo(wire)
471 471 return repo.ui.config(section, name, untrusted=untrusted)
472 472
473 473 @reraise_safe_exceptions
474 474 def get_config_bool(self, wire, section, name, untrusted=False):
475 475 repo = self._factory.repo(wire)
476 476 return repo.ui.configbool(section, name, untrusted=untrusted)
477 477
478 478 @reraise_safe_exceptions
479 479 def get_config_list(self, wire, section, name, untrusted=False):
480 480 repo = self._factory.repo(wire)
481 481 return repo.ui.configlist(section, name, untrusted=untrusted)
482 482
483 483 @reraise_safe_exceptions
484 484 def is_large_file(self, wire, path):
485 485 return largefiles.lfutil.isstandin(path)
486 486
487 487 @reraise_safe_exceptions
488 488 def in_largefiles_store(self, wire, sha):
489 489 repo = self._factory.repo(wire)
490 490 return largefiles.lfutil.instore(repo, sha)
491 491
492 492 @reraise_safe_exceptions
493 493 def in_user_cache(self, wire, sha):
494 494 repo = self._factory.repo(wire)
495 495 return largefiles.lfutil.inusercache(repo.ui, sha)
496 496
497 497 @reraise_safe_exceptions
498 498 def store_path(self, wire, sha):
499 499 repo = self._factory.repo(wire)
500 500 return largefiles.lfutil.storepath(repo, sha)
501 501
502 502 @reraise_safe_exceptions
503 503 def link(self, wire, sha, path):
504 504 repo = self._factory.repo(wire)
505 505 largefiles.lfutil.link(
506 506 largefiles.lfutil.usercachepath(repo.ui, sha), path)
507 507
508 508 @reraise_safe_exceptions
509 509 def localrepository(self, wire, create=False):
510 510 self._factory.repo(wire, create=create)
511 511
512 512 @reraise_safe_exceptions
513 513 def lookup(self, wire, revision, both):
514 514 # TODO Paris: Ugly hack to "deserialize" long for msgpack
515 515 if isinstance(revision, float):
516 516 revision = long(revision)
517 517 repo = self._factory.repo(wire)
518 518 try:
519 519 ctx = repo[revision]
520 520 except RepoLookupError:
521 521 raise exceptions.LookupException(revision)
522 522 except LookupError as e:
523 523 raise exceptions.LookupException(e.name)
524 524
525 525 if not both:
526 526 return ctx.hex()
527 527
528 528 ctx = repo[ctx.hex()]
529 529 return ctx.hex(), ctx.rev()
530 530
531 531 @reraise_safe_exceptions
532 532 def pull(self, wire, url, commit_ids=None):
533 533 repo = self._factory.repo(wire)
534 534 remote = peer(repo, {}, url)
535 535 if commit_ids:
536 536 commit_ids = [bin(commit_id) for commit_id in commit_ids]
537 537
538 538 return exchange.pull(
539 539 repo, remote, heads=commit_ids, force=None).cgresult
540 540
541 541 @reraise_safe_exceptions
542 542 def revision(self, wire, rev):
543 543 repo = self._factory.repo(wire)
544 544 ctx = repo[rev]
545 545 return ctx.rev()
546 546
547 547 @reraise_safe_exceptions
548 548 def rev_range(self, wire, filter):
549 549 repo = self._factory.repo(wire)
550 550 revisions = [rev for rev in revrange(repo, filter)]
551 551 return revisions
552 552
553 553 @reraise_safe_exceptions
554 554 def rev_range_hash(self, wire, node):
555 555 repo = self._factory.repo(wire)
556 556
557 557 def get_revs(repo, rev_opt):
558 558 if rev_opt:
559 559 revs = revrange(repo, rev_opt)
560 560 if len(revs) == 0:
561 561 return (nullrev, nullrev)
562 562 return max(revs), min(revs)
563 563 else:
564 564 return len(repo) - 1, 0
565 565
566 566 stop, start = get_revs(repo, [node + ':'])
567 567 revs = [hex(repo[r].node()) for r in xrange(start, stop + 1)]
568 568 return revs
569 569
570 570 @reraise_safe_exceptions
571 571 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
572 572 other_path = kwargs.pop('other_path', None)
573 573
574 574 # case when we want to compare two independent repositories
575 575 if other_path and other_path != wire["path"]:
576 576 baseui = self._factory._create_config(wire["config"])
577 577 repo = unionrepo.unionrepository(baseui, other_path, wire["path"])
578 578 else:
579 579 repo = self._factory.repo(wire)
580 580 return list(repo.revs(rev_spec, *args))
581 581
582 582 @reraise_safe_exceptions
583 583 def strip(self, wire, revision, update, backup):
584 584 repo = self._factory.repo(wire)
585 585 ctx = repo[revision]
586 586 hgext_strip(
587 587 repo.baseui, repo, ctx.node(), update=update, backup=backup)
588 588
589 589 @reraise_safe_exceptions
590 590 def verify(self, wire,):
591 591 repo = self._factory.repo(wire)
592 592 baseui = self._factory._create_config(wire['config'])
593 593 baseui.setconfig('ui', 'quiet', 'false')
594 594 output = io.BytesIO()
595 595
596 596 def write(data, **unused_kwargs):
597 597 output.write(data)
598 598 baseui.write = write
599 599
600 600 repo.ui = baseui
601 601 verify.verify(repo)
602 602 return output.getvalue()
603 603
604 604 @reraise_safe_exceptions
605 605 def tag(self, wire, name, revision, message, local, user,
606 606 tag_time, tag_timezone):
607 607 repo = self._factory.repo(wire)
608 608 ctx = repo[revision]
609 609 node = ctx.node()
610 610
611 611 date = (tag_time, tag_timezone)
612 612 try:
613 613 repo.tag(name, node, message, local, user, date)
614 614 except Abort as e:
615 615 log.exception("Tag operation aborted")
616 616 # Exception can contain unicode which we convert
617 617 raise exceptions.AbortException(repr(e))
618 618
619 619 @reraise_safe_exceptions
620 620 def tags(self, wire):
621 621 repo = self._factory.repo(wire)
622 622 return repo.tags()
623 623
624 624 @reraise_safe_exceptions
625 625 def update(self, wire, node=None, clean=False):
626 626 repo = self._factory.repo(wire)
627 627 baseui = self._factory._create_config(wire['config'])
628 628 commands.update(baseui, repo, node=node, clean=clean)
629 629
630 630 @reraise_safe_exceptions
631 631 def identify(self, wire):
632 632 repo = self._factory.repo(wire)
633 633 baseui = self._factory._create_config(wire['config'])
634 634 output = io.BytesIO()
635 635 baseui.write = output.write
636 636 # This is required to get a full node id
637 637 baseui.debugflag = True
638 638 commands.identify(baseui, repo, id=True)
639 639
640 640 return output.getvalue()
641 641
642 642 @reraise_safe_exceptions
643 643 def pull_cmd(self, wire, source, bookmark=None, branch=None, revision=None,
644 644 hooks=True):
645 645 repo = self._factory.repo(wire)
646 646 baseui = self._factory._create_config(wire['config'], hooks=hooks)
647 647
648 648 # Mercurial internally has a lot of logic that checks ONLY if
649 649 # option is defined, we just pass those if they are defined then
650 650 opts = {}
651 651 if bookmark:
652 652 opts['bookmark'] = bookmark
653 653 if branch:
654 654 opts['branch'] = branch
655 655 if revision:
656 656 opts['rev'] = revision
657 657
658 658 commands.pull(baseui, repo, source, **opts)
659 659
660 660 @reraise_safe_exceptions
661 661 def heads(self, wire, branch=None):
662 662 repo = self._factory.repo(wire)
663 663 baseui = self._factory._create_config(wire['config'])
664 664 output = io.BytesIO()
665 665
666 666 def write(data, **unused_kwargs):
667 667 output.write(data)
668 668
669 669 baseui.write = write
670 670 if branch:
671 671 args = [branch]
672 672 else:
673 673 args = []
674 674 commands.heads(baseui, repo, template='{node} ', *args)
675 675
676 676 return output.getvalue()
677 677
678 678 @reraise_safe_exceptions
679 679 def ancestor(self, wire, revision1, revision2):
680 680 repo = self._factory.repo(wire)
681 681 changelog = repo.changelog
682 682 lookup = repo.lookup
683 683 a = changelog.ancestor(lookup(revision1), lookup(revision2))
684 684 return hex(a)
685 685
686 686 @reraise_safe_exceptions
687 687 def push(self, wire, revisions, dest_path, hooks=True,
688 688 push_branches=False):
689 689 repo = self._factory.repo(wire)
690 690 baseui = self._factory._create_config(wire['config'], hooks=hooks)
691 691 commands.push(baseui, repo, dest=dest_path, rev=revisions,
692 692 new_branch=push_branches)
693 693
694 694 @reraise_safe_exceptions
695 695 def merge(self, wire, revision):
696 696 repo = self._factory.repo(wire)
697 697 baseui = self._factory._create_config(wire['config'])
698 698 repo.ui.setconfig('ui', 'merge', 'internal:dump')
699 699
700 700 # In case of sub repositories are used mercurial prompts the user in
701 701 # case of merge conflicts or different sub repository sources. By
702 702 # setting the interactive flag to `False` mercurial doesn't prompt the
703 703 # used but instead uses a default value.
704 704 repo.ui.setconfig('ui', 'interactive', False)
705 705
706 706 commands.merge(baseui, repo, rev=revision)
707 707
708 708 @reraise_safe_exceptions
709 709 def commit(self, wire, message, username):
710 710 repo = self._factory.repo(wire)
711 711 baseui = self._factory._create_config(wire['config'])
712 712 repo.ui.setconfig('ui', 'username', username)
713 713 commands.commit(baseui, repo, message=message)
714 714
715 715 @reraise_safe_exceptions
716 716 def rebase(self, wire, source=None, dest=None, abort=False):
717 717 repo = self._factory.repo(wire)
718 718 baseui = self._factory._create_config(wire['config'])
719 719 repo.ui.setconfig('ui', 'merge', 'internal:dump')
720 720 rebase.rebase(
721 721 baseui, repo, base=source, dest=dest, abort=abort, keep=not abort)
722 722
723 723 @reraise_safe_exceptions
724 724 def bookmark(self, wire, bookmark, revision=None):
725 725 repo = self._factory.repo(wire)
726 726 baseui = self._factory._create_config(wire['config'])
727 727 commands.bookmark(baseui, repo, bookmark, rev=revision, force=True)
@@ -1,404 +1,390 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # RhodeCode VCSServer provides access to different vcs backends via network.
4 4 # Copyright (C) 2014-2017 RodeCode GmbH
5 5 #
6 6 # This program is free software; you can redistribute it and/or modify
7 7 # it under the terms of the GNU General Public License as published by
8 8 # the Free Software Foundation; either version 3 of the License, or
9 9 # (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software Foundation,
18 18 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 19
20 20 import io
21 21 import sys
22 22 import json
23 23 import logging
24 24 import collections
25 25 import importlib
26 26 import subprocess
27 27
28 28 from httplib import HTTPConnection
29 29
30 30
31 31 import mercurial.scmutil
32 32 import mercurial.node
33 import Pyro4
34 33 import simplejson as json
35 34
36 35 from vcsserver import exceptions
37 36
38 37 log = logging.getLogger(__name__)
39 38
40 39
41 40 class HooksHttpClient(object):
42 41 connection = None
43 42
44 43 def __init__(self, hooks_uri):
45 44 self.hooks_uri = hooks_uri
46 45
47 46 def __call__(self, method, extras):
48 47 connection = HTTPConnection(self.hooks_uri)
49 48 body = self._serialize(method, extras)
50 49 connection.request('POST', '/', body)
51 50 response = connection.getresponse()
52 51 return json.loads(response.read())
53 52
54 53 def _serialize(self, hook_name, extras):
55 54 data = {
56 55 'method': hook_name,
57 56 'extras': extras
58 57 }
59 58 return json.dumps(data)
60 59
61 60
62 61 class HooksDummyClient(object):
63 62 def __init__(self, hooks_module):
64 63 self._hooks_module = importlib.import_module(hooks_module)
65 64
66 65 def __call__(self, hook_name, extras):
67 66 with self._hooks_module.Hooks() as hooks:
68 67 return getattr(hooks, hook_name)(extras)
69 68
70 69
71 class HooksPyro4Client(object):
72 def __init__(self, hooks_uri):
73 self.hooks_uri = hooks_uri
74
75 def __call__(self, hook_name, extras):
76 with Pyro4.Proxy(self.hooks_uri) as hooks:
77 return getattr(hooks, hook_name)(extras)
78
79
80 70 class RemoteMessageWriter(object):
81 71 """Writer base class."""
82 72 def write(message):
83 73 raise NotImplementedError()
84 74
85 75
86 76 class HgMessageWriter(RemoteMessageWriter):
87 77 """Writer that knows how to send messages to mercurial clients."""
88 78
89 79 def __init__(self, ui):
90 80 self.ui = ui
91 81
92 82 def write(self, message):
93 83 # TODO: Check why the quiet flag is set by default.
94 84 old = self.ui.quiet
95 85 self.ui.quiet = False
96 86 self.ui.status(message.encode('utf-8'))
97 87 self.ui.quiet = old
98 88
99 89
100 90 class GitMessageWriter(RemoteMessageWriter):
101 91 """Writer that knows how to send messages to git clients."""
102 92
103 93 def __init__(self, stdout=None):
104 94 self.stdout = stdout or sys.stdout
105 95
106 96 def write(self, message):
107 97 self.stdout.write(message.encode('utf-8'))
108 98
109 99
110 100 def _handle_exception(result):
111 101 exception_class = result.get('exception')
112 102 exception_traceback = result.get('exception_traceback')
113 103
114 104 if exception_traceback:
115 105 log.error('Got traceback from remote call:%s', exception_traceback)
116 106
117 107 if exception_class == 'HTTPLockedRC':
118 108 raise exceptions.RepositoryLockedException(*result['exception_args'])
119 109 elif exception_class == 'RepositoryError':
120 110 raise exceptions.VcsException(*result['exception_args'])
121 111 elif exception_class:
122 112 raise Exception('Got remote exception "%s" with args "%s"' %
123 113 (exception_class, result['exception_args']))
124 114
125 115
126 116 def _get_hooks_client(extras):
127 117 if 'hooks_uri' in extras:
128 118 protocol = extras.get('hooks_protocol')
129 return (
130 HooksHttpClient(extras['hooks_uri'])
131 if protocol == 'http'
132 else HooksPyro4Client(extras['hooks_uri'])
133 )
119 return HooksHttpClient(extras['hooks_uri'])
134 120 else:
135 121 return HooksDummyClient(extras['hooks_module'])
136 122
137 123
138 124 def _call_hook(hook_name, extras, writer):
139 125 hooks = _get_hooks_client(extras)
140 126 result = hooks(hook_name, extras)
141 127 writer.write(result['output'])
142 128 _handle_exception(result)
143 129
144 130 return result['status']
145 131
146 132
147 133 def _extras_from_ui(ui):
148 134 extras = json.loads(ui.config('rhodecode', 'RC_SCM_DATA'))
149 135 return extras
150 136
151 137
152 138 def repo_size(ui, repo, **kwargs):
153 139 return _call_hook('repo_size', _extras_from_ui(ui), HgMessageWriter(ui))
154 140
155 141
156 142 def pre_pull(ui, repo, **kwargs):
157 143 return _call_hook('pre_pull', _extras_from_ui(ui), HgMessageWriter(ui))
158 144
159 145
160 146 def post_pull(ui, repo, **kwargs):
161 147 return _call_hook('post_pull', _extras_from_ui(ui), HgMessageWriter(ui))
162 148
163 149
164 150 def pre_push(ui, repo, node=None, **kwargs):
165 151 extras = _extras_from_ui(ui)
166 152
167 153 rev_data = []
168 154 if node and kwargs.get('hooktype') == 'pretxnchangegroup':
169 155 branches = collections.defaultdict(list)
170 156 for commit_id, branch in _rev_range_hash(repo, node, with_branch=True):
171 157 branches[branch].append(commit_id)
172 158
173 159 for branch, commits in branches.iteritems():
174 160 old_rev = kwargs.get('node_last') or commits[0]
175 161 rev_data.append({
176 162 'old_rev': old_rev,
177 163 'new_rev': commits[-1],
178 164 'ref': '',
179 165 'type': 'branch',
180 166 'name': branch,
181 167 })
182 168
183 169 extras['commit_ids'] = rev_data
184 170 return _call_hook('pre_push', extras, HgMessageWriter(ui))
185 171
186 172
187 173 def _rev_range_hash(repo, node, with_branch=False):
188 174
189 175 commits = []
190 176 for rev in xrange(repo[node], len(repo)):
191 177 ctx = repo[rev]
192 178 commit_id = mercurial.node.hex(ctx.node())
193 179 branch = ctx.branch()
194 180 if with_branch:
195 181 commits.append((commit_id, branch))
196 182 else:
197 183 commits.append(commit_id)
198 184
199 185 return commits
200 186
201 187
202 188 def post_push(ui, repo, node, **kwargs):
203 189 commit_ids = _rev_range_hash(repo, node)
204 190
205 191 extras = _extras_from_ui(ui)
206 192 extras['commit_ids'] = commit_ids
207 193
208 194 return _call_hook('post_push', extras, HgMessageWriter(ui))
209 195
210 196
211 197 # backward compat
212 198 log_pull_action = post_pull
213 199
214 200 # backward compat
215 201 log_push_action = post_push
216 202
217 203
218 204 def handle_git_pre_receive(unused_repo_path, unused_revs, unused_env):
219 205 """
220 206 Old hook name: keep here for backward compatibility.
221 207
222 208 This is only required when the installed git hooks are not upgraded.
223 209 """
224 210 pass
225 211
226 212
227 213 def handle_git_post_receive(unused_repo_path, unused_revs, unused_env):
228 214 """
229 215 Old hook name: keep here for backward compatibility.
230 216
231 217 This is only required when the installed git hooks are not upgraded.
232 218 """
233 219 pass
234 220
235 221
236 222 HookResponse = collections.namedtuple('HookResponse', ('status', 'output'))
237 223
238 224
239 225 def git_pre_pull(extras):
240 226 """
241 227 Pre pull hook.
242 228
243 229 :param extras: dictionary containing the keys defined in simplevcs
244 230 :type extras: dict
245 231
246 232 :return: status code of the hook. 0 for success.
247 233 :rtype: int
248 234 """
249 235 if 'pull' not in extras['hooks']:
250 236 return HookResponse(0, '')
251 237
252 238 stdout = io.BytesIO()
253 239 try:
254 240 status = _call_hook('pre_pull', extras, GitMessageWriter(stdout))
255 241 except Exception as error:
256 242 status = 128
257 243 stdout.write('ERROR: %s\n' % str(error))
258 244
259 245 return HookResponse(status, stdout.getvalue())
260 246
261 247
262 248 def git_post_pull(extras):
263 249 """
264 250 Post pull hook.
265 251
266 252 :param extras: dictionary containing the keys defined in simplevcs
267 253 :type extras: dict
268 254
269 255 :return: status code of the hook. 0 for success.
270 256 :rtype: int
271 257 """
272 258 if 'pull' not in extras['hooks']:
273 259 return HookResponse(0, '')
274 260
275 261 stdout = io.BytesIO()
276 262 try:
277 263 status = _call_hook('post_pull', extras, GitMessageWriter(stdout))
278 264 except Exception as error:
279 265 status = 128
280 266 stdout.write('ERROR: %s\n' % error)
281 267
282 268 return HookResponse(status, stdout.getvalue())
283 269
284 270
285 271 def _parse_git_ref_lines(revision_lines):
286 272 rev_data = []
287 273 for revision_line in revision_lines or []:
288 274 old_rev, new_rev, ref = revision_line.strip().split(' ')
289 275 ref_data = ref.split('/', 2)
290 276 if ref_data[1] in ('tags', 'heads'):
291 277 rev_data.append({
292 278 'old_rev': old_rev,
293 279 'new_rev': new_rev,
294 280 'ref': ref,
295 281 'type': ref_data[1],
296 282 'name': ref_data[2],
297 283 })
298 284 return rev_data
299 285
300 286
301 287 def git_pre_receive(unused_repo_path, revision_lines, env):
302 288 """
303 289 Pre push hook.
304 290
305 291 :param extras: dictionary containing the keys defined in simplevcs
306 292 :type extras: dict
307 293
308 294 :return: status code of the hook. 0 for success.
309 295 :rtype: int
310 296 """
311 297 extras = json.loads(env['RC_SCM_DATA'])
312 298 rev_data = _parse_git_ref_lines(revision_lines)
313 299 if 'push' not in extras['hooks']:
314 300 return 0
315 301 extras['commit_ids'] = rev_data
316 302 return _call_hook('pre_push', extras, GitMessageWriter())
317 303
318 304
319 305 def _run_command(arguments):
320 306 """
321 307 Run the specified command and return the stdout.
322 308
323 309 :param arguments: sequence of program arguments (including the program name)
324 310 :type arguments: list[str]
325 311 """
326 312 # TODO(skreft): refactor this method and all the other similar ones.
327 313 # Probably this should be using subprocessio.
328 314 process = subprocess.Popen(
329 315 arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
330 316 stdout, _ = process.communicate()
331 317
332 318 if process.returncode != 0:
333 319 raise Exception(
334 320 'Command %s exited with exit code %s' % (arguments,
335 321 process.returncode))
336 322
337 323 return stdout
338 324
339 325
340 326 def git_post_receive(unused_repo_path, revision_lines, env):
341 327 """
342 328 Post push hook.
343 329
344 330 :param extras: dictionary containing the keys defined in simplevcs
345 331 :type extras: dict
346 332
347 333 :return: status code of the hook. 0 for success.
348 334 :rtype: int
349 335 """
350 336 extras = json.loads(env['RC_SCM_DATA'])
351 337 if 'push' not in extras['hooks']:
352 338 return 0
353 339
354 340 rev_data = _parse_git_ref_lines(revision_lines)
355 341
356 342 git_revs = []
357 343
358 344 # N.B.(skreft): it is ok to just call git, as git before calling a
359 345 # subcommand sets the PATH environment variable so that it point to the
360 346 # correct version of the git executable.
361 347 empty_commit_id = '0' * 40
362 348 for push_ref in rev_data:
363 349 type_ = push_ref['type']
364 350 if type_ == 'heads':
365 351 if push_ref['old_rev'] == empty_commit_id:
366 352
367 353 # Fix up head revision if needed
368 354 cmd = ['git', 'show', 'HEAD']
369 355 try:
370 356 _run_command(cmd)
371 357 except Exception:
372 358 cmd = ['git', 'symbolic-ref', 'HEAD',
373 359 'refs/heads/%s' % push_ref['name']]
374 360 print("Setting default branch to %s" % push_ref['name'])
375 361 _run_command(cmd)
376 362
377 363 cmd = ['git', 'for-each-ref', '--format=%(refname)',
378 364 'refs/heads/*']
379 365 heads = _run_command(cmd)
380 366 heads = heads.replace(push_ref['ref'], '')
381 367 heads = ' '.join(head for head in heads.splitlines() if head)
382 368 cmd = ['git', 'log', '--reverse', '--pretty=format:%H',
383 369 '--', push_ref['new_rev'], '--not', heads]
384 370 git_revs.extend(_run_command(cmd).splitlines())
385 371 elif push_ref['new_rev'] == empty_commit_id:
386 372 # delete branch case
387 373 git_revs.append('delete_branch=>%s' % push_ref['name'])
388 374 else:
389 375 cmd = ['git', 'log',
390 376 '{old_rev}..{new_rev}'.format(**push_ref),
391 377 '--reverse', '--pretty=format:%H']
392 378 git_revs.extend(_run_command(cmd).splitlines())
393 379 elif type_ == 'tags':
394 380 git_revs.append('tag=>%s' % push_ref['name'])
395 381
396 382 extras['commit_ids'] = git_revs
397 383
398 384 if 'repo_size' in extras['hooks']:
399 385 try:
400 386 _call_hook('repo_size', extras, GitMessageWriter())
401 387 except:
402 388 pass
403 389
404 390 return _call_hook('post_push', extras, GitMessageWriter())
@@ -1,30 +1,19 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2017 RodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
6 6 # the Free Software Foundation; either version 3 of the License, or
7 7 # (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software Foundation,
16 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18
19 PYRO_PORT = 9900
20
21 PYRO_GIT = 'git_remote'
22 PYRO_HG = 'hg_remote'
23 PYRO_SVN = 'svn_remote'
24 PYRO_VCSSERVER = 'vcs_server'
25 PYRO_GIT_REMOTE_WSGI = 'git_remote_wsgi'
26 PYRO_HG_REMOTE_WSGI = 'hg_remote_wsgi'
27
28 18 WIRE_ENCODING = 'UTF-8'
29
30 19 GIT_EXECUTABLE = 'git'
@@ -1,549 +1,239 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2017 RodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
6 6 # the Free Software Foundation; either version 3 of the License, or
7 7 # (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software Foundation,
16 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18 18 import contextlib
19 19 import io
20 20 import threading
21 21 from BaseHTTPServer import BaseHTTPRequestHandler
22 22 from SocketServer import TCPServer
23 23
24 24 import mercurial.ui
25 25 import mock
26 26 import pytest
27 27 import simplejson as json
28 28
29 29 from vcsserver import hooks
30 30
31 31
32 class HooksStub(object):
33 """
34 Simulates a Proy4.Proxy object.
35
36 Will always return `result`, no matter which hook has been called on it.
37 """
38
39 def __init__(self, result):
40 self._result = result
41
42 def __call__(self, hooks_uri):
43 return self
44
45 def __enter__(self):
46 return self
47
48 def __exit__(self, exc_type, exc_value, traceback):
49 pass
50
51 def __getattr__(self, name):
52 return mock.Mock(return_value=self._result)
53
54
55 @contextlib.contextmanager
56 def mock_hook_response(
57 status=0, output='', exception=None, exception_args=None):
58 response = {
59 'status': status,
60 'output': output,
61 }
62 if exception:
63 response.update({
64 'exception': exception,
65 'exception_args': exception_args,
66 })
67
68 with mock.patch('Pyro4.Proxy', HooksStub(response)):
69 yield
70
71
72 32 def get_hg_ui(extras=None):
73 33 """Create a Config object with a valid RC_SCM_DATA entry."""
74 34 extras = extras or {}
75 35 required_extras = {
76 36 'username': '',
77 37 'repository': '',
78 38 'locked_by': '',
79 39 'scm': '',
80 40 'make_lock': '',
81 41 'action': '',
82 42 'ip': '',
83 43 'hooks_uri': 'fake_hooks_uri',
84 44 }
85 45 required_extras.update(extras)
86 46 hg_ui = mercurial.ui.ui()
87 47 hg_ui.setconfig('rhodecode', 'RC_SCM_DATA', json.dumps(required_extras))
88 48
89 49 return hg_ui
90 50
91 51
92 def test_call_hook_no_error(capsys):
93 extras = {
94 'hooks_uri': 'fake_hook_uri',
95 }
96 expected_output = 'My mock outptut'
97 writer = mock.Mock()
98
99 with mock_hook_response(status=1, output=expected_output):
100 hooks._call_hook('hook_name', extras, writer)
101
102 out, err = capsys.readouterr()
103
104 writer.write.assert_called_with(expected_output)
105 assert err == ''
106
107
108 def test_call_hook_with_exception(capsys):
109 extras = {
110 'hooks_uri': 'fake_hook_uri',
111 }
112 expected_output = 'My mock outptut'
113 writer = mock.Mock()
114
115 with mock_hook_response(status=1, output=expected_output,
116 exception='TypeError',
117 exception_args=('Mock exception', )):
118 with pytest.raises(Exception) as excinfo:
119 hooks._call_hook('hook_name', extras, writer)
120
121 assert excinfo.type == Exception
122 assert 'Mock exception' in str(excinfo.value)
123
124 out, err = capsys.readouterr()
125
126 writer.write.assert_called_with(expected_output)
127 assert err == ''
128
129
130 def test_call_hook_with_locked_exception(capsys):
131 extras = {
132 'hooks_uri': 'fake_hook_uri',
133 }
134 expected_output = 'My mock outptut'
135 writer = mock.Mock()
136
137 with mock_hook_response(status=1, output=expected_output,
138 exception='HTTPLockedRC',
139 exception_args=('message',)):
140 with pytest.raises(Exception) as excinfo:
141 hooks._call_hook('hook_name', extras, writer)
142
143 assert excinfo.value._vcs_kind == 'repo_locked'
144 assert 'message' == str(excinfo.value)
145
146 out, err = capsys.readouterr()
147
148 writer.write.assert_called_with(expected_output)
149 assert err == ''
150
151
152 def test_call_hook_with_stdout():
153 extras = {
154 'hooks_uri': 'fake_hook_uri',
155 }
156 expected_output = 'My mock outptut'
157
158 stdout = io.BytesIO()
159 with mock_hook_response(status=1, output=expected_output):
160 hooks._call_hook('hook_name', extras, stdout)
161
162 assert stdout.getvalue() == expected_output
163
164
165 def test_repo_size():
166 hg_ui = get_hg_ui()
167
168 with mock_hook_response(status=1):
169 assert hooks.repo_size(hg_ui, None) == 1
170
171
172 def test_pre_pull():
173 hg_ui = get_hg_ui()
174
175 with mock_hook_response(status=1):
176 assert hooks.pre_pull(hg_ui, None) == 1
177
178
179 def test_post_pull():
180 hg_ui = get_hg_ui()
181
182 with mock_hook_response(status=1):
183 assert hooks.post_pull(hg_ui, None) == 1
184
185
186 def test_pre_push():
187 hg_ui = get_hg_ui()
188
189 with mock_hook_response(status=1):
190 assert hooks.pre_push(hg_ui, None) == 1
191
192
193 def test_post_push():
194 hg_ui = get_hg_ui()
195
196 with mock_hook_response(status=1):
197 with mock.patch('vcsserver.hooks._rev_range_hash', return_value=[]):
198 assert hooks.post_push(hg_ui, None, None) == 1
199
200
201 def test_git_pre_receive():
202 extras = {
203 'hooks': ['push'],
204 'hooks_uri': 'fake_hook_uri',
205 }
206 with mock_hook_response(status=1):
207 response = hooks.git_pre_receive(None, None,
208 {'RC_SCM_DATA': json.dumps(extras)})
209 assert response == 1
210
211
212 52 def test_git_pre_receive_is_disabled():
213 53 extras = {'hooks': ['pull']}
214 54 response = hooks.git_pre_receive(None, None,
215 55 {'RC_SCM_DATA': json.dumps(extras)})
216 56
217 57 assert response == 0
218 58
219 59
220 def test_git_post_receive_no_subprocess_call():
221 extras = {
222 'hooks': ['push'],
223 'hooks_uri': 'fake_hook_uri',
224 }
225 # Setting revision_lines to '' avoid all subprocess_calls
226 with mock_hook_response(status=1):
227 response = hooks.git_post_receive(None, '',
228 {'RC_SCM_DATA': json.dumps(extras)})
229 assert response == 1
230
231
232 60 def test_git_post_receive_is_disabled():
233 61 extras = {'hooks': ['pull']}
234 62 response = hooks.git_post_receive(None, '',
235 63 {'RC_SCM_DATA': json.dumps(extras)})
236 64
237 65 assert response == 0
238 66
239 67
240 68 def test_git_post_receive_calls_repo_size():
241 69 extras = {'hooks': ['push', 'repo_size']}
242 70 with mock.patch.object(hooks, '_call_hook') as call_hook_mock:
243 71 hooks.git_post_receive(
244 72 None, '', {'RC_SCM_DATA': json.dumps(extras)})
245 73 extras.update({'commit_ids': []})
246 74 expected_calls = [
247 75 mock.call('repo_size', extras, mock.ANY),
248 76 mock.call('post_push', extras, mock.ANY),
249 77 ]
250 78 assert call_hook_mock.call_args_list == expected_calls
251 79
252 80
253 81 def test_git_post_receive_does_not_call_disabled_repo_size():
254 82 extras = {'hooks': ['push']}
255 83 with mock.patch.object(hooks, '_call_hook') as call_hook_mock:
256 84 hooks.git_post_receive(
257 85 None, '', {'RC_SCM_DATA': json.dumps(extras)})
258 86 extras.update({'commit_ids': []})
259 87 expected_calls = [
260 88 mock.call('post_push', extras, mock.ANY)
261 89 ]
262 90 assert call_hook_mock.call_args_list == expected_calls
263 91
264 92
265 93 def test_repo_size_exception_does_not_affect_git_post_receive():
266 94 extras = {'hooks': ['push', 'repo_size']}
267 95 status = 0
268 96
269 97 def side_effect(name, *args, **kwargs):
270 98 if name == 'repo_size':
271 99 raise Exception('Fake exception')
272 100 else:
273 101 return status
274 102
275 103 with mock.patch.object(hooks, '_call_hook') as call_hook_mock:
276 104 call_hook_mock.side_effect = side_effect
277 105 result = hooks.git_post_receive(
278 106 None, '', {'RC_SCM_DATA': json.dumps(extras)})
279 107 assert result == status
280 108
281 109
282 @mock.patch('vcsserver.hooks._run_command')
283 def test_git_post_receive_first_commit_sub_branch(cmd_mock):
284 def cmd_mock_returns(args):
285 if args == ['git', 'show', 'HEAD']:
286 raise
287 if args == ['git', 'for-each-ref', '--format=%(refname)',
288 'refs/heads/*']:
289 return 'refs/heads/test-branch2/sub-branch'
290 if args == ['git', 'log', '--reverse', '--pretty=format:%H', '--',
291 '9695eef57205c17566a3ae543be187759b310bb7', '--not',
292 'refs/heads/test-branch2/sub-branch']:
293 return ''
294
295 cmd_mock.side_effect = cmd_mock_returns
296
297 extras = {
298 'hooks': ['push'],
299 'hooks_uri': 'fake_hook_uri'
300 }
301 rev_lines = ['0000000000000000000000000000000000000000 '
302 '9695eef57205c17566a3ae543be187759b310bb7 '
303 'refs/heads/feature/sub-branch\n']
304 with mock_hook_response(status=0):
305 response = hooks.git_post_receive(None, rev_lines,
306 {'RC_SCM_DATA': json.dumps(extras)})
307
308 calls = [
309 mock.call(['git', 'show', 'HEAD']),
310 mock.call(['git', 'symbolic-ref', 'HEAD',
311 'refs/heads/feature/sub-branch']),
312 ]
313 cmd_mock.assert_has_calls(calls, any_order=True)
314 assert response == 0
315
316
317 @mock.patch('vcsserver.hooks._run_command')
318 def test_git_post_receive_first_commit_revs(cmd_mock):
319 extras = {
320 'hooks': ['push'],
321 'hooks_uri': 'fake_hook_uri'
322 }
323 rev_lines = [
324 '0000000000000000000000000000000000000000 '
325 '9695eef57205c17566a3ae543be187759b310bb7 refs/heads/master\n']
326 with mock_hook_response(status=0):
327 response = hooks.git_post_receive(
328 None, rev_lines, {'RC_SCM_DATA': json.dumps(extras)})
329
330 calls = [
331 mock.call(['git', 'show', 'HEAD']),
332 mock.call(['git', 'for-each-ref', '--format=%(refname)',
333 'refs/heads/*']),
334 mock.call(['git', 'log', '--reverse', '--pretty=format:%H',
335 '--', '9695eef57205c17566a3ae543be187759b310bb7', '--not',
336 ''])
337 ]
338 cmd_mock.assert_has_calls(calls, any_order=True)
339
340 assert response == 0
341
342
343 def test_git_pre_pull():
344 extras = {
345 'hooks': ['pull'],
346 'hooks_uri': 'fake_hook_uri',
347 }
348 with mock_hook_response(status=1, output='foo'):
349 assert hooks.git_pre_pull(extras) == hooks.HookResponse(1, 'foo')
350
351
352 def test_git_pre_pull_exception_is_caught():
353 extras = {
354 'hooks': ['pull'],
355 'hooks_uri': 'fake_hook_uri',
356 }
357 with mock_hook_response(status=2, exception=Exception('foo')):
358 assert hooks.git_pre_pull(extras).status == 128
359
360
361 110 def test_git_pre_pull_is_disabled():
362 111 assert hooks.git_pre_pull({'hooks': ['push']}) == hooks.HookResponse(0, '')
363 112
364 113
365 def test_git_post_pull():
366 extras = {
367 'hooks': ['pull'],
368 'hooks_uri': 'fake_hook_uri',
369 }
370 with mock_hook_response(status=1, output='foo'):
371 assert hooks.git_post_pull(extras) == hooks.HookResponse(1, 'foo')
372
373
374 def test_git_post_pull_exception_is_caught():
375 extras = {
376 'hooks': ['pull'],
377 'hooks_uri': 'fake_hook_uri',
378 }
379 with mock_hook_response(status=2, exception='Exception',
380 exception_args=('foo',)):
381 assert hooks.git_post_pull(extras).status == 128
382
383
384 114 def test_git_post_pull_is_disabled():
385 115 assert (
386 116 hooks.git_post_pull({'hooks': ['push']}) == hooks.HookResponse(0, ''))
387 117
388 118
389 119 class TestGetHooksClient(object):
390 def test_returns_pyro_client_when_protocol_matches(self):
391 hooks_uri = 'localhost:8000'
392 result = hooks._get_hooks_client({
393 'hooks_uri': hooks_uri,
394 'hooks_protocol': 'pyro4'
395 })
396 assert isinstance(result, hooks.HooksPyro4Client)
397 assert result.hooks_uri == hooks_uri
398 120
399 121 def test_returns_http_client_when_protocol_matches(self):
400 122 hooks_uri = 'localhost:8000'
401 123 result = hooks._get_hooks_client({
402 124 'hooks_uri': hooks_uri,
403 125 'hooks_protocol': 'http'
404 126 })
405 127 assert isinstance(result, hooks.HooksHttpClient)
406 128 assert result.hooks_uri == hooks_uri
407 129
408 def test_returns_pyro4_client_when_no_protocol_is_specified(self):
409 hooks_uri = 'localhost:8000'
410 result = hooks._get_hooks_client({
411 'hooks_uri': hooks_uri
412 })
413 assert isinstance(result, hooks.HooksPyro4Client)
414 assert result.hooks_uri == hooks_uri
415
416 130 def test_returns_dummy_client_when_hooks_uri_not_specified(self):
417 131 fake_module = mock.Mock()
418 132 import_patcher = mock.patch.object(
419 133 hooks.importlib, 'import_module', return_value=fake_module)
420 134 fake_module_name = 'fake.module'
421 135 with import_patcher as import_mock:
422 136 result = hooks._get_hooks_client(
423 137 {'hooks_module': fake_module_name})
424 138
425 139 import_mock.assert_called_once_with(fake_module_name)
426 140 assert isinstance(result, hooks.HooksDummyClient)
427 141 assert result._hooks_module == fake_module
428 142
429 143
430 144 class TestHooksHttpClient(object):
431 145 def test_init_sets_hooks_uri(self):
432 146 uri = 'localhost:3000'
433 147 client = hooks.HooksHttpClient(uri)
434 148 assert client.hooks_uri == uri
435 149
436 150 def test_serialize_returns_json_string(self):
437 151 client = hooks.HooksHttpClient('localhost:3000')
438 152 hook_name = 'test'
439 153 extras = {
440 154 'first': 1,
441 155 'second': 'two'
442 156 }
443 157 result = client._serialize(hook_name, extras)
444 158 expected_result = json.dumps({
445 159 'method': hook_name,
446 160 'extras': extras
447 161 })
448 162 assert result == expected_result
449 163
450 164 def test_call_queries_http_server(self, http_mirror):
451 165 client = hooks.HooksHttpClient(http_mirror.uri)
452 166 hook_name = 'test'
453 167 extras = {
454 168 'first': 1,
455 169 'second': 'two'
456 170 }
457 171 result = client(hook_name, extras)
458 172 expected_result = {
459 173 'method': hook_name,
460 174 'extras': extras
461 175 }
462 176 assert result == expected_result
463 177
464 178
465 179 class TestHooksDummyClient(object):
466 180 def test_init_imports_hooks_module(self):
467 181 hooks_module_name = 'rhodecode.fake.module'
468 182 hooks_module = mock.MagicMock()
469 183
470 184 import_patcher = mock.patch.object(
471 185 hooks.importlib, 'import_module', return_value=hooks_module)
472 186 with import_patcher as import_mock:
473 187 client = hooks.HooksDummyClient(hooks_module_name)
474 188 import_mock.assert_called_once_with(hooks_module_name)
475 189 assert client._hooks_module == hooks_module
476 190
477 191 def test_call_returns_hook_result(self):
478 192 hooks_module_name = 'rhodecode.fake.module'
479 193 hooks_module = mock.MagicMock()
480 194 import_patcher = mock.patch.object(
481 195 hooks.importlib, 'import_module', return_value=hooks_module)
482 196 with import_patcher:
483 197 client = hooks.HooksDummyClient(hooks_module_name)
484 198
485 199 result = client('post_push', {})
486 200 hooks_module.Hooks.assert_called_once_with()
487 201 assert result == hooks_module.Hooks().__enter__().post_push()
488 202
489 203
490 class TestHooksPyro4Client(object):
491 def test_init_sets_hooks_uri(self):
492 uri = 'localhost:3000'
493 client = hooks.HooksPyro4Client(uri)
494 assert client.hooks_uri == uri
495
496 def test_call_returns_hook_value(self):
497 hooks_uri = 'localhost:3000'
498 client = hooks.HooksPyro4Client(hooks_uri)
499 hooks_module = mock.Mock()
500 context_manager = mock.MagicMock()
501 context_manager.__enter__.return_value = hooks_module
502 pyro4_patcher = mock.patch.object(
503 hooks.Pyro4, 'Proxy', return_value=context_manager)
504 extras = {
505 'test': 'test'
506 }
507 with pyro4_patcher as pyro4_mock:
508 result = client('post_push', extras)
509 pyro4_mock.assert_called_once_with(hooks_uri)
510 hooks_module.post_push.assert_called_once_with(extras)
511 assert result == hooks_module.post_push.return_value
512
513
514 204 @pytest.fixture
515 205 def http_mirror(request):
516 206 server = MirrorHttpServer()
517 207 request.addfinalizer(server.stop)
518 208 return server
519 209
520 210
521 211 class MirrorHttpHandler(BaseHTTPRequestHandler):
522 212 def do_POST(self):
523 213 length = int(self.headers['Content-Length'])
524 214 body = self.rfile.read(length).decode('utf-8')
525 215 self.send_response(200)
526 216 self.end_headers()
527 217 self.wfile.write(body)
528 218
529 219
530 220 class MirrorHttpServer(object):
531 221 ip_address = '127.0.0.1'
532 222 port = 0
533 223
534 224 def __init__(self):
535 225 self._daemon = TCPServer((self.ip_address, 0), MirrorHttpHandler)
536 226 _, self.port = self._daemon.server_address
537 227 self._thread = threading.Thread(target=self._daemon.serve_forever)
538 228 self._thread.daemon = True
539 229 self._thread.start()
540 230
541 231 def stop(self):
542 232 self._daemon.shutdown()
543 233 self._thread.join()
544 234 self._daemon = None
545 235 self._thread = None
546 236
547 237 @property
548 238 def uri(self):
549 239 return '{}:{}'.format(self.ip_address, self.port)
@@ -1,57 +1,57 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2017 RodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
6 6 # the Free Software Foundation; either version 3 of the License, or
7 7 # (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software Foundation,
16 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18 18 import mock
19 19 import pytest
20 20
21 from vcsserver import main
21 from vcsserver import http_main
22 22 from vcsserver.base import obfuscate_qs
23 23
24 24
25 @mock.patch('vcsserver.main.VcsServerCommand', mock.Mock())
25 @mock.patch('vcsserver.http_main.VCS', mock.Mock())
26 26 @mock.patch('vcsserver.hgpatches.patch_largefiles_capabilities')
27 27 def test_applies_largefiles_patch(patch_largefiles_capabilities):
28 main.main([])
28 http_main.main([])
29 29 patch_largefiles_capabilities.assert_called_once_with()
30 30
31 31
32 @mock.patch('vcsserver.main.VcsServerCommand', mock.Mock())
33 @mock.patch('vcsserver.main.MercurialFactory', None)
32 @mock.patch('vcsserver.http_main.VCS', mock.Mock())
33 @mock.patch('vcsserver.http_main.MercurialFactory', None)
34 34 @mock.patch(
35 35 'vcsserver.hgpatches.patch_largefiles_capabilities',
36 36 mock.Mock(side_effect=Exception("Must not be called")))
37 37 def test_applies_largefiles_patch_only_if_mercurial_is_available():
38 main.main([])
38 http_main.main([])
39 39
40 40
41 41 @pytest.mark.parametrize('given, expected', [
42 42 ('bad', 'bad'),
43 43 ('query&foo=bar', 'query&foo=bar'),
44 44 ('equery&auth_token=bar', 'equery&auth_token=*****'),
45 45 ('a;b;c;query&foo=bar&auth_token=secret',
46 46 'a&b&c&query&foo=bar&auth_token=*****'),
47 47 ('', ''),
48 48 (None, None),
49 49 ('foo=bar', 'foo=bar'),
50 50 ('auth_token=secret', 'auth_token=*****'),
51 51 ('auth_token=secret&api_key=secret2',
52 52 'auth_token=*****&api_key=*****'),
53 53 ('auth_token=secret&api_key=secret2&param=value',
54 54 'auth_token=*****&api_key=*****&param=value'),
55 55 ])
56 56 def test_obfuscate_qs(given, expected):
57 57 assert expected == obfuscate_qs(given)
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (508 lines changed) Show them Hide them
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now