##// END OF EJS Templates
release: Merge default into stable for release preparation
marcink -
r108:a1a58274 merge stable
parent child Browse files
Show More
@@ -0,0 +1,63 b''
1 diff -rup subversion-1.9.4-orig/subversion/include/svn_auth.h subversion-1.9.4/subversion/include/svn_auth.h
2 --- subversion-1.9.4-orig/subversion/include/svn_auth.h 2015-02-13 12:17:40.000000000 +0100
3 +++ subversion-1.9.4/subversion/include/svn_auth.h 2016-09-21 12:55:27.000000000 +0200
4 @@ -943,7 +943,7 @@ svn_auth_get_windows_ssl_server_trust_pr
5
6 #endif /* WIN32 && !__MINGW32__ || DOXYGEN */
7
8 -#if defined(DARWIN) || defined(DOXYGEN)
9 +#if defined(SVN_HAVE_KEYCHAIN_SERVICES) || defined(DOXYGEN)
10 /**
11 * Set @a *provider to an authentication provider of type @c
12 * svn_auth_cred_simple_t that gets/sets information from the user's
13 @@ -984,7 +984,7 @@ void
14 svn_auth_get_keychain_ssl_client_cert_pw_provider(
15 svn_auth_provider_object_t **provider,
16 apr_pool_t *pool);
17 -#endif /* DARWIN || DOXYGEN */
18 +#endif /* SVN_HAVE_KEYCHAIN_SERVICES || DOXYGEN */
19
20 /* Note that the gnome keyring unlock prompt related items below must be
21 * declared for all platforms in order to allow SWIG interfaces to be
22 diff -rup subversion-1.9.4-orig/subversion/libsvn_subr/auth.h subversion-1.9.4/subversion/libsvn_subr/auth.h
23 --- subversion-1.9.4-orig/subversion/libsvn_subr/auth.h 2015-08-27 06:00:31.000000000 +0200
24 +++ subversion-1.9.4/subversion/libsvn_subr/auth.h 2016-09-21 12:56:20.000000000 +0200
25 @@ -103,7 +103,7 @@ svn_auth__get_windows_ssl_server_trust_p
26 apr_pool_t *pool);
27 #endif /* WIN32 && !__MINGW32__ || DOXYGEN */
28
29 -#if defined(DARWIN) || defined(DOXYGEN)
30 +#if defined(SVN_HAVE_KEYCHAIN_SERVICES) || defined(DOXYGEN)
31 /**
32 * Set @a *provider to an authentication provider of type @c
33 * svn_auth_cred_simple_t that gets/sets information from the user's
34 @@ -134,7 +134,7 @@ void
35 svn_auth__get_keychain_ssl_client_cert_pw_provider(
36 svn_auth_provider_object_t **provider,
37 apr_pool_t *pool);
38 -#endif /* DARWIN || DOXYGEN */
39 +#endif /* SVN_HAVE_KEYCHAIN_SERVICES || DOXYGEN */
40
41 #if !defined(WIN32) || defined(DOXYGEN)
42 /**
43 diff -rup subversion-1.9.4-orig/subversion/libsvn_subr/deprecated.c subversion-1.9.4/subversion/libsvn_subr/deprecated.c
44 --- subversion-1.9.4-orig/subversion/libsvn_subr/deprecated.c 2015-08-27 06:00:31.000000000 +0200
45 +++ subversion-1.9.4/subversion/libsvn_subr/deprecated.c 2016-09-21 12:57:08.000000000 +0200
46 @@ -1479,7 +1479,7 @@ svn_auth_get_windows_ssl_server_trust_pr
47 #endif /* WIN32 && !__MINGW32__ */
48
49 /*** From macos_keychain.c ***/
50 -#if defined(DARWIN)
51 +#if defined(SVN_HAVE_KEYCHAIN_SERVICES)
52 void
53 svn_auth_get_keychain_simple_provider(svn_auth_provider_object_t **provider,
54 apr_pool_t *pool)
55 @@ -1494,7 +1494,7 @@ svn_auth_get_keychain_ssl_client_cert_pw
56 {
57 svn_auth__get_keychain_ssl_client_cert_pw_provider(provider, pool);
58 }
59 -#endif /* DARWIN */
60 +#endif /* SVN_HAVE_KEYCHAIN_SERVICES */
61
62 #if !defined(WIN32)
63 void
@@ -1,5 +1,5 b''
1 [bumpversion]
1 [bumpversion]
2 current_version = 4.4.2
2 current_version = 4.5.0
3 message = release: Bump version {current_version} to {new_version}
3 message = release: Bump version {current_version} to {new_version}
4
4
5 [bumpversion:file:vcsserver/VERSION]
5 [bumpversion:file:vcsserver/VERSION]
@@ -5,12 +5,10 b' done = false'
5 done = true
5 done = true
6
6
7 [task:fixes_on_stable]
7 [task:fixes_on_stable]
8 done = true
9
8
10 [task:pip2nix_generated]
9 [task:pip2nix_generated]
11 done = true
12
10
13 [release]
11 [release]
14 state = prepared
12 state = in_progress
15 version = 4.4.2
13 version = 4.5.0
16
14
@@ -3,22 +3,6 b''
3 # #
3 # #
4 ################################################################################
4 ################################################################################
5
5
6 [app:main]
7 use = egg:rhodecode-vcsserver
8
9 pyramid.default_locale_name = en
10 pyramid.includes =
11
12 # default locale used by VCS systems
13 locale = en_US.UTF-8
14
15 # cache regions, please don't change
16 beaker.cache.regions = repo_object
17 beaker.cache.repo_object.type = memorylru
18 beaker.cache.repo_object.max_items = 100
19 # cache auto-expires after N seconds
20 beaker.cache.repo_object.expire = 300
21 beaker.cache.repo_object.enabled = true
22
6
23 [server:main]
7 [server:main]
24 ## COMMON ##
8 ## COMMON ##
@@ -29,7 +13,7 b' port = 9900'
29 ##########################
13 ##########################
30 ## GUNICORN WSGI SERVER ##
14 ## GUNICORN WSGI SERVER ##
31 ##########################
15 ##########################
32 ## run with gunicorn --log-config <inifile.ini> --paste <inifile.ini>
16 ## run with gunicorn --log-config vcsserver.ini --paste vcsserver.ini
33 use = egg:gunicorn#main
17 use = egg:gunicorn#main
34 ## Sets the number of process workers. You must set `instance_id = *`
18 ## Sets the number of process workers. You must set `instance_id = *`
35 ## when this option is set to more than one worker, recommended
19 ## when this option is set to more than one worker, recommended
@@ -52,6 +36,22 b' max_requests_jitter = 30'
52 timeout = 21600
36 timeout = 21600
53
37
54
38
39 [app:main]
40 use = egg:rhodecode-vcsserver
41
42 pyramid.default_locale_name = en
43 pyramid.includes =
44
45 ## default locale used by VCS systems
46 locale = en_US.UTF-8
47
48 # cache regions, please don't change
49 beaker.cache.regions = repo_object
50 beaker.cache.repo_object.type = memorylru
51 beaker.cache.repo_object.max_items = 100
52 # cache auto-expires after N seconds
53 beaker.cache.repo_object.expire = 300
54 beaker.cache.repo_object.enabled = true
55
55
56
56
57 ################################
57 ################################
@@ -16,12 +16,19 b' let'
16 pkgs = pkgs_.overridePackages (self: super: {
16 pkgs = pkgs_.overridePackages (self: super: {
17 # Override subversion derivation to
17 # Override subversion derivation to
18 # - activate python bindings
18 # - activate python bindings
19 # - set version to 1.8
19 subversion = let
20 subversion = super.subversion18.override {
20 subversionWithPython = super.subversion.override {
21 httpSupport = true;
21 httpSupport = true;
22 pythonBindings = true;
22 pythonBindings = true;
23 python = self.python27Packages.python;
23 python = self.python27Packages.python;
24 };
24 };
25 in pkgs.lib.overrideDerivation subversionWithPython (oldAttrs: {
26 patches = (oldAttrs.patches or []) ++
27 pkgs.lib.optionals pkgs.stdenv.isDarwin [
28 # johbo: "import svn.client" fails on darwin currently.
29 ./pkgs/subversion-1.9.4-darwin.patch
30 ];
31 });
25 });
32 });
26
33
27 inherit (pkgs.lib) fix extends;
34 inherit (pkgs.lib) fix extends;
@@ -86,21 +93,6 b' let'
86 pythonPackages = self;
93 pythonPackages = self;
87 };
94 };
88
95
89 # Somewhat snappier setup of the development environment
90 # TODO: move into shell.nix
91 # TODO: think of supporting a stable path again, so that multiple shells
92 # can share it.
93 shellHook = ''
94 # Set locale
95 export LC_ALL="en_US.UTF-8"
96
97 tmp_path=$(mktemp -d)
98 export PATH="$tmp_path/bin:$PATH"
99 export PYTHONPATH="$tmp_path/${self.python.sitePackages}:$PYTHONPATH"
100 mkdir -p $tmp_path/${self.python.sitePackages}
101 python setup.py develop --prefix $tmp_path --allow-hosts ""
102 '';
103
104 # Add VCSServer bin directory to path so that tests can find 'vcsserver'.
96 # Add VCSServer bin directory to path so that tests can find 'vcsserver'.
105 preCheck = ''
97 preCheck = ''
106 export PATH="$out/bin:$PATH"
98 export PATH="$out/bin:$PATH"
@@ -13,7 +13,8 b' in'
13 self: super: {
13 self: super: {
14
14
15 subvertpy = super.subvertpy.override (attrs: {
15 subvertpy = super.subvertpy.override (attrs: {
16 SVN_PREFIX = "${pkgs.subversion}";
16 # TODO: johbo: Remove the "or" once we drop 16.03 support
17 SVN_PREFIX = "${pkgs.subversion.dev or pkgs.subversion}";
17 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
18 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
18 pkgs.aprutil
19 pkgs.aprutil
19 pkgs.subversion
20 pkgs.subversion
@@ -1,3 +1,6 b''
1 # Generated by pip2nix 0.4.0.dev1
2 # See https://github.com/johbo/pip2nix
3
1 {
4 {
2 Beaker = super.buildPythonPackage {
5 Beaker = super.buildPythonPackage {
3 name = "Beaker-1.7.0";
6 name = "Beaker-1.7.0";
@@ -26,13 +29,13 b''
26 };
29 };
27 };
30 };
28 Mako = super.buildPythonPackage {
31 Mako = super.buildPythonPackage {
29 name = "Mako-1.0.4";
32 name = "Mako-1.0.6";
30 buildInputs = with self; [];
33 buildInputs = with self; [];
31 doCheck = false;
34 doCheck = false;
32 propagatedBuildInputs = with self; [MarkupSafe];
35 propagatedBuildInputs = with self; [MarkupSafe];
33 src = fetchurl {
36 src = fetchurl {
34 url = "https://pypi.python.org/packages/7a/ae/925434246ee90b42e8ef57d3b30a0ab7caf9a2de3e449b876c56dcb48155/Mako-1.0.4.tar.gz";
37 url = "https://pypi.python.org/packages/56/4b/cb75836863a6382199aefb3d3809937e21fa4cb0db15a4f4ba0ecc2e7e8e/Mako-1.0.6.tar.gz";
35 md5 = "c5fc31a323dd4990683d2f2da02d4e20";
38 md5 = "a28e22a339080316b2acc352b9ee631c";
36 };
39 };
37 meta = {
40 meta = {
38 license = [ pkgs.lib.licenses.mit ];
41 license = [ pkgs.lib.licenses.mit ];
@@ -103,6 +106,19 b''
103 license = [ pkgs.lib.licenses.mit ];
106 license = [ pkgs.lib.licenses.mit ];
104 };
107 };
105 };
108 };
109 backports.shutil-get-terminal-size = super.buildPythonPackage {
110 name = "backports.shutil-get-terminal-size-1.0.0";
111 buildInputs = with self; [];
112 doCheck = false;
113 propagatedBuildInputs = with self; [];
114 src = fetchurl {
115 url = "https://pypi.python.org/packages/ec/9c/368086faa9c016efce5da3e0e13ba392c9db79e3ab740b763fe28620b18b/backports.shutil_get_terminal_size-1.0.0.tar.gz";
116 md5 = "03267762480bd86b50580dc19dff3c66";
117 };
118 meta = {
119 license = [ pkgs.lib.licenses.mit ];
120 };
121 };
106 configobj = super.buildPythonPackage {
122 configobj = super.buildPythonPackage {
107 name = "configobj-5.0.6";
123 name = "configobj-5.0.6";
108 buildInputs = with self; [];
124 buildInputs = with self; [];
@@ -116,6 +132,19 b''
116 license = [ pkgs.lib.licenses.bsdOriginal ];
132 license = [ pkgs.lib.licenses.bsdOriginal ];
117 };
133 };
118 };
134 };
135 decorator = super.buildPythonPackage {
136 name = "decorator-4.0.10";
137 buildInputs = with self; [];
138 doCheck = false;
139 propagatedBuildInputs = with self; [];
140 src = fetchurl {
141 url = "https://pypi.python.org/packages/13/8a/4eed41e338e8dcc13ca41c94b142d4d20c0de684ee5065523fee406ce76f/decorator-4.0.10.tar.gz";
142 md5 = "434b57fdc3230c500716c5aff8896100";
143 };
144 meta = {
145 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ];
146 };
147 };
119 dulwich = super.buildPythonPackage {
148 dulwich = super.buildPythonPackage {
120 name = "dulwich-0.13.0";
149 name = "dulwich-0.13.0";
121 buildInputs = with self; [];
150 buildInputs = with self; [];
@@ -129,6 +158,19 b''
129 license = [ pkgs.lib.licenses.gpl2Plus ];
158 license = [ pkgs.lib.licenses.gpl2Plus ];
130 };
159 };
131 };
160 };
161 enum34 = super.buildPythonPackage {
162 name = "enum34-1.1.6";
163 buildInputs = with self; [];
164 doCheck = false;
165 propagatedBuildInputs = with self; [];
166 src = fetchurl {
167 url = "https://pypi.python.org/packages/bf/3e/31d502c25302814a7c2f1d3959d2a3b3f78e509002ba91aea64993936876/enum34-1.1.6.tar.gz";
168 md5 = "5f13a0841a61f7fc295c514490d120d0";
169 };
170 meta = {
171 license = [ pkgs.lib.licenses.bsdOriginal ];
172 };
173 };
132 greenlet = super.buildPythonPackage {
174 greenlet = super.buildPythonPackage {
133 name = "greenlet-0.4.7";
175 name = "greenlet-0.4.7";
134 buildInputs = with self; [];
176 buildInputs = with self; [];
@@ -181,6 +223,45 b''
181 license = [ pkgs.lib.licenses.zpt21 ];
223 license = [ pkgs.lib.licenses.zpt21 ];
182 };
224 };
183 };
225 };
226 ipdb = super.buildPythonPackage {
227 name = "ipdb-0.10.1";
228 buildInputs = with self; [];
229 doCheck = false;
230 propagatedBuildInputs = with self; [ipython setuptools];
231 src = fetchurl {
232 url = "https://pypi.python.org/packages/eb/0a/0a37dc19572580336ad3813792c0d18c8d7117c2d66fc63c501f13a7a8f8/ipdb-0.10.1.tar.gz";
233 md5 = "4aeab65f633ddc98ebdb5eebf08dc713";
234 };
235 meta = {
236 license = [ pkgs.lib.licenses.bsdOriginal ];
237 };
238 };
239 ipython = super.buildPythonPackage {
240 name = "ipython-5.1.0";
241 buildInputs = with self; [];
242 doCheck = false;
243 propagatedBuildInputs = with self; [setuptools decorator pickleshare simplegeneric traitlets prompt-toolkit pygments pexpect backports.shutil-get-terminal-size pathlib2 pexpect];
244 src = fetchurl {
245 url = "https://pypi.python.org/packages/89/63/a9292f7cd9d0090a0f995e1167f3f17d5889dcbc9a175261719c513b9848/ipython-5.1.0.tar.gz";
246 md5 = "47c8122420f65b58784cb4b9b4af35e3";
247 };
248 meta = {
249 license = [ pkgs.lib.licenses.bsdOriginal ];
250 };
251 };
252 ipython-genutils = super.buildPythonPackage {
253 name = "ipython-genutils-0.1.0";
254 buildInputs = with self; [];
255 doCheck = false;
256 propagatedBuildInputs = with self; [];
257 src = fetchurl {
258 url = "https://pypi.python.org/packages/71/b7/a64c71578521606edbbce15151358598f3dfb72a3431763edc2baf19e71f/ipython_genutils-0.1.0.tar.gz";
259 md5 = "9a8afbe0978adbcbfcb3b35b2d015a56";
260 };
261 meta = {
262 license = [ pkgs.lib.licenses.bsdOriginal ];
263 };
264 };
184 mercurial = super.buildPythonPackage {
265 mercurial = super.buildPythonPackage {
185 name = "mercurial-3.8.4";
266 name = "mercurial-3.8.4";
186 buildInputs = with self; [];
267 buildInputs = with self; [];
@@ -220,6 +301,71 b''
220 license = [ pkgs.lib.licenses.asl20 ];
301 license = [ pkgs.lib.licenses.asl20 ];
221 };
302 };
222 };
303 };
304 pathlib2 = super.buildPythonPackage {
305 name = "pathlib2-2.1.0";
306 buildInputs = with self; [];
307 doCheck = false;
308 propagatedBuildInputs = with self; [six];
309 src = fetchurl {
310 url = "https://pypi.python.org/packages/c9/27/8448b10d8440c08efeff0794adf7d0ed27adb98372c70c7b38f3947d4749/pathlib2-2.1.0.tar.gz";
311 md5 = "38e4f58b4d69dfcb9edb49a54a8b28d2";
312 };
313 meta = {
314 license = [ pkgs.lib.licenses.mit ];
315 };
316 };
317 pexpect = super.buildPythonPackage {
318 name = "pexpect-4.2.1";
319 buildInputs = with self; [];
320 doCheck = false;
321 propagatedBuildInputs = with self; [ptyprocess];
322 src = fetchurl {
323 url = "https://pypi.python.org/packages/e8/13/d0b0599099d6cd23663043a2a0bb7c61e58c6ba359b2656e6fb000ef5b98/pexpect-4.2.1.tar.gz";
324 md5 = "3694410001a99dff83f0b500a1ca1c95";
325 };
326 meta = {
327 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
328 };
329 };
330 pickleshare = super.buildPythonPackage {
331 name = "pickleshare-0.7.4";
332 buildInputs = with self; [];
333 doCheck = false;
334 propagatedBuildInputs = with self; [pathlib2];
335 src = fetchurl {
336 url = "https://pypi.python.org/packages/69/fe/dd137d84daa0fd13a709e448138e310d9ea93070620c9db5454e234af525/pickleshare-0.7.4.tar.gz";
337 md5 = "6a9e5dd8dfc023031f6b7b3f824cab12";
338 };
339 meta = {
340 license = [ pkgs.lib.licenses.mit ];
341 };
342 };
343 prompt-toolkit = super.buildPythonPackage {
344 name = "prompt-toolkit-1.0.9";
345 buildInputs = with self; [];
346 doCheck = false;
347 propagatedBuildInputs = with self; [six wcwidth];
348 src = fetchurl {
349 url = "https://pypi.python.org/packages/83/14/5ac258da6c530eca02852ee25c7a9ff3ca78287bb4c198d0d0055845d856/prompt_toolkit-1.0.9.tar.gz";
350 md5 = "a39f91a54308fb7446b1a421c11f227c";
351 };
352 meta = {
353 license = [ pkgs.lib.licenses.bsdOriginal ];
354 };
355 };
356 ptyprocess = super.buildPythonPackage {
357 name = "ptyprocess-0.5.1";
358 buildInputs = with self; [];
359 doCheck = false;
360 propagatedBuildInputs = with self; [];
361 src = fetchurl {
362 url = "https://pypi.python.org/packages/db/d7/b465161910f3d1cef593c5e002bff67e0384898f597f1a7fdc8db4c02bf6/ptyprocess-0.5.1.tar.gz";
363 md5 = "94e537122914cc9ec9c1eadcd36e73a1";
364 };
365 meta = {
366 license = [ ];
367 };
368 };
223 py = super.buildPythonPackage {
369 py = super.buildPythonPackage {
224 name = "py-1.4.29";
370 name = "py-1.4.29";
225 buildInputs = with self; [];
371 buildInputs = with self; [];
@@ -233,6 +379,19 b''
233 license = [ pkgs.lib.licenses.mit ];
379 license = [ pkgs.lib.licenses.mit ];
234 };
380 };
235 };
381 };
382 pygments = super.buildPythonPackage {
383 name = "pygments-2.1.3";
384 buildInputs = with self; [];
385 doCheck = false;
386 propagatedBuildInputs = with self; [];
387 src = fetchurl {
388 url = "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz";
389 md5 = "ed3fba2467c8afcda4d317e4ef2c6150";
390 };
391 meta = {
392 license = [ pkgs.lib.licenses.bsdOriginal ];
393 };
394 };
236 pyramid = super.buildPythonPackage {
395 pyramid = super.buildPythonPackage {
237 name = "pyramid-1.6.1";
396 name = "pyramid-1.6.1";
238 buildInputs = with self; [];
397 buildInputs = with self; [];
@@ -299,8 +458,8 b''
299 };
458 };
300 };
459 };
301 rhodecode-vcsserver = super.buildPythonPackage {
460 rhodecode-vcsserver = super.buildPythonPackage {
302 name = "rhodecode-vcsserver-4.4.2";
461 name = "rhodecode-vcsserver-4.5.0";
303 buildInputs = with self; [mock pytest WebTest];
462 buildInputs = with self; [mock pytest pytest-sugar WebTest];
304 doCheck = true;
463 doCheck = true;
305 propagatedBuildInputs = with self; [configobj dulwich hgsubversion infrae.cache mercurial msgpack-python pyramid Pyro4 simplejson subprocess32 waitress WebOb];
464 propagatedBuildInputs = with self; [configobj dulwich hgsubversion infrae.cache mercurial msgpack-python pyramid Pyro4 simplejson subprocess32 waitress WebOb];
306 src = ./.;
465 src = ./.;
@@ -334,6 +493,19 b''
334 license = [ pkgs.lib.licenses.mit ];
493 license = [ pkgs.lib.licenses.mit ];
335 };
494 };
336 };
495 };
496 simplegeneric = super.buildPythonPackage {
497 name = "simplegeneric-0.8.1";
498 buildInputs = with self; [];
499 doCheck = false;
500 propagatedBuildInputs = with self; [];
501 src = fetchurl {
502 url = "https://pypi.python.org/packages/3d/57/4d9c9e3ae9a255cd4e1106bb57e24056d3d0709fc01b2e3e345898e49d5b/simplegeneric-0.8.1.zip";
503 md5 = "f9c1fab00fd981be588fc32759f474e3";
504 };
505 meta = {
506 license = [ pkgs.lib.licenses.zpt21 ];
507 };
508 };
337 simplejson = super.buildPythonPackage {
509 simplejson = super.buildPythonPackage {
338 name = "simplejson-3.7.2";
510 name = "simplejson-3.7.2";
339 buildInputs = with self; [];
511 buildInputs = with self; [];
@@ -344,7 +516,7 b''
344 md5 = "a5fc7d05d4cb38492285553def5d4b46";
516 md5 = "a5fc7d05d4cb38492285553def5d4b46";
345 };
517 };
346 meta = {
518 meta = {
347 license = [ pkgs.lib.licenses.mit pkgs.lib.licenses.afl21 ];
519 license = [ { fullName = "Academic Free License (AFL)"; } pkgs.lib.licenses.mit ];
348 };
520 };
349 };
521 };
350 six = super.buildPythonPackage {
522 six = super.buildPythonPackage {
@@ -386,6 +558,19 b''
386 license = [ pkgs.lib.licenses.lgpl21Plus ];
558 license = [ pkgs.lib.licenses.lgpl21Plus ];
387 };
559 };
388 };
560 };
561 traitlets = super.buildPythonPackage {
562 name = "traitlets-4.3.1";
563 buildInputs = with self; [];
564 doCheck = false;
565 propagatedBuildInputs = with self; [ipython-genutils six decorator enum34];
566 src = fetchurl {
567 url = "https://pypi.python.org/packages/b1/d6/5b5aa6d5c474691909b91493da1e8972e309c9f01ecfe4aeafd272eb3234/traitlets-4.3.1.tar.gz";
568 md5 = "dd0b1b6e5d31ce446d55a4b5e5083c98";
569 };
570 meta = {
571 license = [ pkgs.lib.licenses.bsdOriginal ];
572 };
573 };
389 translationstring = super.buildPythonPackage {
574 translationstring = super.buildPythonPackage {
390 name = "translationstring-1.3";
575 name = "translationstring-1.3";
391 buildInputs = with self; [];
576 buildInputs = with self; [];
@@ -425,6 +610,19 b''
425 license = [ pkgs.lib.licenses.zpt21 ];
610 license = [ pkgs.lib.licenses.zpt21 ];
426 };
611 };
427 };
612 };
613 wcwidth = super.buildPythonPackage {
614 name = "wcwidth-0.1.7";
615 buildInputs = with self; [];
616 doCheck = false;
617 propagatedBuildInputs = with self; [];
618 src = fetchurl {
619 url = "https://pypi.python.org/packages/55/11/e4a2bb08bb450fdbd42cc709dd40de4ed2c472cf0ccb9e64af22279c5495/wcwidth-0.1.7.tar.gz";
620 md5 = "b3b6a0a08f0c8a34d1de8cf44150a4ad";
621 };
622 meta = {
623 license = [ pkgs.lib.licenses.mit ];
624 };
625 };
428 wheel = super.buildPythonPackage {
626 wheel = super.buildPythonPackage {
429 name = "wheel-0.29.0";
627 name = "wheel-0.29.0";
430 buildInputs = with self; [];
628 buildInputs = with self; [];
@@ -467,5 +665,30 b''
467
665
468 ### Test requirements
666 ### Test requirements
469
667
470
668 pytest-sugar = super.buildPythonPackage {
669 name = "pytest-sugar-0.7.1";
670 buildInputs = with self; [];
671 doCheck = false;
672 propagatedBuildInputs = with self; [pytest termcolor];
673 src = fetchurl {
674 url = "https://pypi.python.org/packages/03/97/05d988b4fa870e7373e8ee4582408543b9ca2bd35c3c67b569369c6f9c49/pytest-sugar-0.7.1.tar.gz";
675 md5 = "7400f7c11f3d572b2c2a3b60352d35fe";
676 };
677 meta = {
678 license = [ pkgs.lib.licenses.bsdOriginal ];
679 };
680 };
681 termcolor = super.buildPythonPackage {
682 name = "termcolor-1.1.0";
683 buildInputs = with self; [];
684 doCheck = false;
685 propagatedBuildInputs = with self; [];
686 src = fetchurl {
687 url = "https://pypi.python.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz";
688 md5 = "043e89644f8909d462fbbfa511c768df";
689 };
690 meta = {
691 license = [ pkgs.lib.licenses.mit ];
692 };
693 };
471 }
694 }
@@ -3,6 +3,7 b' configobj==5.0.6'
3 dulwich==0.13.0
3 dulwich==0.13.0
4 hgsubversion==1.8.6
4 hgsubversion==1.8.6
5 infrae.cache==1.0.1
5 infrae.cache==1.0.1
6 ipdb==0.10.1
6 mercurial==3.8.4
7 mercurial==3.8.4
7 msgpack-python==0.4.6
8 msgpack-python==0.4.6
8 py==1.4.29
9 py==1.4.29
@@ -74,6 +74,7 b' setup('
74 tests_require=[
74 tests_require=[
75 'mock',
75 'mock',
76 'pytest',
76 'pytest',
77 'pytest-sugar',
77 'WebTest',
78 'WebTest',
78 ],
79 ],
79 install_requires=[
80 install_requires=[
@@ -3,16 +3,39 b''
3 }:
3 }:
4
4
5 let
5 let
6
6 vcsserver = import ./default.nix {
7 vcsserver = import ./default.nix {
7 inherit
8 inherit pkgs doCheck;
8 doCheck
9 pkgs;
10 };
9 };
11
10
11 vcs-pythonPackages = vcsserver.pythonPackages;
12
12 in vcsserver.override (attrs: {
13 in vcsserver.override (attrs: {
13
14
14 # Avoid that we dump any sources into the store when entering the shell and
15 # Avoid that we dump any sources into the store when entering the shell and
15 # make development a little bit more convenient.
16 # make development a little bit more convenient.
16 src = null;
17 src = null;
17
18
19 buildInputs =
20 attrs.buildInputs ++
21 (with vcs-pythonPackages; [
22 ipdb
23 ]);
24
25 # Somewhat snappier setup of the development environment
26 # TODO: think of supporting a stable path again, so that multiple shells
27 # can share it.
28 postShellHook = ''
29 # Set locale
30 export LC_ALL="en_US.UTF-8"
31
32 # Custom prompt to distinguish from other dev envs.
33 export PS1="\n\[\033[1;32m\][VCS-shell:\w]$\[\033[0m\] "
34
35 tmp_path=$(mktemp -d)
36 export PATH="$tmp_path/bin:$PATH"
37 export PYTHONPATH="$tmp_path/${vcs-pythonPackages.python.sitePackages}:$PYTHONPATH"
38 mkdir -p $tmp_path/${vcs-pythonPackages.python.sitePackages}
39 python setup.py develop --prefix $tmp_path --allow-hosts ""
40 '';
18 })
41 })
@@ -16,8 +16,10 b''
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18 import mock
18 import mock
19 import pytest
19
20
20 from vcsserver import main
21 from vcsserver import main
22 from vcsserver.base import obfuscate_qs
21
23
22
24
23 @mock.patch('vcsserver.main.VcsServerCommand', mock.Mock())
25 @mock.patch('vcsserver.main.VcsServerCommand', mock.Mock())
@@ -34,3 +36,22 b' def test_applies_largefiles_patch(patch_'
34 mock.Mock(side_effect=Exception("Must not be called")))
36 mock.Mock(side_effect=Exception("Must not be called")))
35 def test_applies_largefiles_patch_only_if_mercurial_is_available():
37 def test_applies_largefiles_patch_only_if_mercurial_is_available():
36 main.main([])
38 main.main([])
39
40
41 @pytest.mark.parametrize('given, expected', [
42 ('bad', 'bad'),
43 ('query&foo=bar', 'query&foo=bar'),
44 ('equery&auth_token=bar', 'equery&auth_token=*****'),
45 ('a;b;c;query&foo=bar&auth_token=secret',
46 'a&b&c&query&foo=bar&auth_token=*****'),
47 ('', ''),
48 (None, None),
49 ('foo=bar', 'foo=bar'),
50 ('auth_token=secret', 'auth_token=*****'),
51 ('auth_token=secret&api_key=secret2',
52 'auth_token=*****&api_key=*****'),
53 ('auth_token=secret&api_key=secret2&param=value',
54 'auth_token=*****&api_key=*****&param=value'),
55 ])
56 def test_obfuscate_qs(given, expected):
57 assert expected == obfuscate_qs(given)
@@ -1,1 +1,1 b''
1 4.4.2 No newline at end of file
1 4.5.0 No newline at end of file
@@ -16,7 +16,7 b''
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18 import logging
18 import logging
19
19 import urlparse
20
20
21 log = logging.getLogger(__name__)
21 log = logging.getLogger(__name__)
22
22
@@ -69,3 +69,17 b' class RepoFactory(object):'
69 'INIT %s@%s repo object based on wire %s. Context: %s',
69 'INIT %s@%s repo object based on wire %s. Context: %s',
70 self.__class__.__name__, wire['path'], wire, context)
70 self.__class__.__name__, wire['path'], wire, context)
71 return createfunc()
71 return createfunc()
72
73
74 def obfuscate_qs(query_string):
75 if query_string is None:
76 return None
77
78 parsed = []
79 for k, v in urlparse.parse_qsl(query_string, keep_blank_values=True):
80 if k in ['auth_token', 'api_key']:
81 v = "*****"
82 parsed.append((k, v))
83
84 return '&'.join('{}{}'.format(
85 k, '={}'.format(v) if v else '') for k, v in parsed)
@@ -25,6 +25,7 b' different error conditions.'
25 """
25 """
26
26
27 import functools
27 import functools
28 from pyramid.httpexceptions import HTTPLocked
28
29
29
30
30 def _make_exception(kind, *args):
31 def _make_exception(kind, *args):
@@ -54,3 +55,16 b' RequirementException = functools.partial'
54 UnhandledException = functools.partial(_make_exception, 'unhandled')
55 UnhandledException = functools.partial(_make_exception, 'unhandled')
55
56
56 URLError = functools.partial(_make_exception, 'url_error')
57 URLError = functools.partial(_make_exception, 'url_error')
58
59 SubrepoMergeException = functools.partial(_make_exception, 'subrepo_merge_error')
60
61
62 class HTTPRepoLocked(HTTPLocked):
63 """
64 Subclass of HTTPLocked response that allows to set the title and status
65 code via constructor arguments.
66 """
67 def __init__(self, title, status_code=None, **kwargs):
68 self.code = status_code or HTTPLocked.code
69 self.title = title
70 super(HTTPRepoLocked, self).__init__(**kwargs)
@@ -35,9 +35,9 b' from dulwich.server import update_server'
35
35
36 from vcsserver import exceptions, settings, subprocessio
36 from vcsserver import exceptions, settings, subprocessio
37 from vcsserver.utils import safe_str
37 from vcsserver.utils import safe_str
38 from vcsserver.base import RepoFactory
38 from vcsserver.base import RepoFactory, obfuscate_qs
39 from vcsserver.hgcompat import (
39 from vcsserver.hgcompat import (
40 hg_url, httpbasicauthhandler, httpdigestauthhandler)
40 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler)
41
41
42
42
43 DIR_STAT = stat.S_IFDIR
43 DIR_STAT = stat.S_IFDIR
@@ -152,7 +152,7 b' class GitRemote(object):'
152
152
153 def _build_opener(self, url):
153 def _build_opener(self, url):
154 handlers = []
154 handlers = []
155 url_obj = hg_url(url)
155 url_obj = url_parser(url)
156 _, authinfo = url_obj.authinfo()
156 _, authinfo = url_obj.authinfo()
157
157
158 if authinfo:
158 if authinfo:
@@ -167,10 +167,12 b' class GitRemote(object):'
167
167
168 @reraise_safe_exceptions
168 @reraise_safe_exceptions
169 def check_url(self, url, config):
169 def check_url(self, url, config):
170 url_obj = hg_url(url)
170 url_obj = url_parser(url)
171 test_uri, _ = url_obj.authinfo()
171 test_uri, _ = url_obj.authinfo()
172 url_obj.passwd = '*****'
172 url_obj.passwd = '*****'
173 url_obj.query = obfuscate_qs(url_obj.query)
173 cleaned_uri = str(url_obj)
174 cleaned_uri = str(url_obj)
175 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
174
176
175 if not test_uri.endswith('info/refs'):
177 if not test_uri.endswith('info/refs'):
176 test_uri = test_uri.rstrip('/') + '/info/refs'
178 test_uri = test_uri.rstrip('/') + '/info/refs'
@@ -184,12 +186,14 b' class GitRemote(object):'
184 req = urllib2.Request(cu, None, {})
186 req = urllib2.Request(cu, None, {})
185
187
186 try:
188 try:
189 log.debug("Trying to open URL %s", cleaned_uri)
187 resp = o.open(req)
190 resp = o.open(req)
188 if resp.code != 200:
191 if resp.code != 200:
189 raise Exception('Return Code is not 200')
192 raise exceptions.URLError('Return Code is not 200')
190 except Exception as e:
193 except Exception as e:
194 log.warning("URL cannot be opened: %s", cleaned_uri, exc_info=True)
191 # means it cannot be cloned
195 # means it cannot be cloned
192 raise urllib2.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
196 raise exceptions.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
193
197
194 # now detect if it's proper git repo
198 # now detect if it's proper git repo
195 gitdata = resp.read()
199 gitdata = resp.read()
@@ -199,7 +203,7 b' class GitRemote(object):'
199 # old style git can return some other format !
203 # old style git can return some other format !
200 pass
204 pass
201 else:
205 else:
202 raise urllib2.URLError(
206 raise exceptions.URLError(
203 "url [%s] does not look like an git" % (cleaned_uri,))
207 "url [%s] does not look like an git" % (cleaned_uri,))
204
208
205 return True
209 return True
@@ -327,7 +331,7 b' class GitRemote(object):'
327 if url != 'default' and '://' not in url:
331 if url != 'default' and '://' not in url:
328 client = LocalGitClient(url)
332 client = LocalGitClient(url)
329 else:
333 else:
330 url_obj = hg_url(url)
334 url_obj = url_parser(url)
331 o = self._build_opener(url)
335 o = self._build_opener(url)
332 url, _ = url_obj.authinfo()
336 url, _ = url_obj.authinfo()
333 client = HttpGitClient(base_url=url, opener=o)
337 client = HttpGitClient(base_url=url, opener=o)
@@ -521,7 +525,10 b' class GitRemote(object):'
521 def discover_git_version(self):
525 def discover_git_version(self):
522 stdout, _ = self.run_git_command(
526 stdout, _ = self.run_git_command(
523 {}, ['--version'], _bare=True, _safe=True)
527 {}, ['--version'], _bare=True, _safe=True)
524 return stdout
528 prefix = 'git version'
529 if stdout.startswith(prefix):
530 stdout = stdout[len(prefix):]
531 return stdout.strip()
525
532
526 @reraise_safe_exceptions
533 @reraise_safe_exceptions
527 def run_git_command(self, wire, cmd, **opts):
534 def run_git_command(self, wire, cmd, **opts):
@@ -28,13 +28,13 b' from mercurial import commands'
28 from mercurial import unionrepo
28 from mercurial import unionrepo
29
29
30 from vcsserver import exceptions
30 from vcsserver import exceptions
31 from vcsserver.base import RepoFactory
31 from vcsserver.base import RepoFactory, obfuscate_qs
32 from vcsserver.hgcompat import (
32 from vcsserver.hgcompat import (
33 archival, bin, clone, config as hgconfig, diffopts, hex, hg_url,
33 archival, bin, clone, config as hgconfig, diffopts, hex,
34 httpbasicauthhandler, httpdigestauthhandler, httppeer, localrepository,
34 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler,
35 match, memctx, exchange, memfilectx, nullrev, patch, peer, revrange, ui,
35 httppeer, localrepository, match, memctx, exchange, memfilectx, nullrev,
36 Abort, LookupError, RepoError, RepoLookupError, InterventionRequired,
36 patch, peer, revrange, ui, Abort, LookupError, RepoError, RepoLookupError,
37 RequirementError)
37 InterventionRequired, RequirementError)
38
38
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
@@ -142,6 +142,11 b' class HgRemote(object):'
142 }
142 }
143
143
144 @reraise_safe_exceptions
144 @reraise_safe_exceptions
145 def discover_hg_version(self):
146 from mercurial import util
147 return util.version()
148
149 @reraise_safe_exceptions
145 def archive_repo(self, archive_path, mtime, file_info, kind):
150 def archive_repo(self, archive_path, mtime, file_info, kind):
146 if kind == "tgz":
151 if kind == "tgz":
147 archiver = archival.tarit(archive_path, mtime, "gz")
152 archiver = archival.tarit(archive_path, mtime, "gz")
@@ -316,16 +321,18 b' class HgRemote(object):'
316
321
317 @reraise_safe_exceptions
322 @reraise_safe_exceptions
318 def check_url(self, url, config):
323 def check_url(self, url, config):
319 log.info("Checking URL for remote cloning/import: %s", url)
320 _proto = None
324 _proto = None
321 if '+' in url[:url.find('://')]:
325 if '+' in url[:url.find('://')]:
322 _proto = url[0:url.find('+')]
326 _proto = url[0:url.find('+')]
323 url = url[url.find('+') + 1:]
327 url = url[url.find('+') + 1:]
324 handlers = []
328 handlers = []
325 url_obj = hg_url(url)
329 url_obj = url_parser(url)
326 test_uri, authinfo = url_obj.authinfo()
330 test_uri, authinfo = url_obj.authinfo()
327 url_obj.passwd = '*****'
331 url_obj.passwd = '*****'
332 url_obj.query = obfuscate_qs(url_obj.query)
333
328 cleaned_uri = str(url_obj)
334 cleaned_uri = str(url_obj)
335 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
329
336
330 if authinfo:
337 if authinfo:
331 # create a password manager
338 # create a password manager
@@ -346,12 +353,12 b' class HgRemote(object):'
346 req = urllib2.Request(cu, None, {})
353 req = urllib2.Request(cu, None, {})
347
354
348 try:
355 try:
349 log.debug("Trying to open URL %s", url)
356 log.debug("Trying to open URL %s", cleaned_uri)
350 resp = o.open(req)
357 resp = o.open(req)
351 if resp.code != 200:
358 if resp.code != 200:
352 raise exceptions.URLError('Return Code is not 200')
359 raise exceptions.URLError('Return Code is not 200')
353 except Exception as e:
360 except Exception as e:
354 log.warning("URL cannot be opened: %s", url, exc_info=True)
361 log.warning("URL cannot be opened: %s", cleaned_uri, exc_info=True)
355 # means it cannot be cloned
362 # means it cannot be cloned
356 raise exceptions.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
363 raise exceptions.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
357
364
@@ -362,15 +369,17 b' class HgRemote(object):'
362 else:
369 else:
363 # check for pure hg repos
370 # check for pure hg repos
364 log.debug(
371 log.debug(
365 "Verifying if URL is a Mercurial repository: %s", url)
372 "Verifying if URL is a Mercurial repository: %s",
373 cleaned_uri)
366 httppeer(make_ui_from_config(config), url).lookup('tip')
374 httppeer(make_ui_from_config(config), url).lookup('tip')
367 except Exception as e:
375 except Exception as e:
368 log.warning("URL is not a valid Mercurial repository: %s", url)
376 log.warning("URL is not a valid Mercurial repository: %s",
377 cleaned_uri)
369 raise exceptions.URLError(
378 raise exceptions.URLError(
370 "url [%s] does not look like an hg repo org_exc: %s"
379 "url [%s] does not look like an hg repo org_exc: %s"
371 % (cleaned_uri, e))
380 % (cleaned_uri, e))
372
381
373 log.info("URL is a valid Mercurial repository: %s", url)
382 log.info("URL is a valid Mercurial repository: %s", cleaned_uri)
374 return True
383 return True
375
384
376 @reraise_safe_exceptions
385 @reraise_safe_exceptions
@@ -683,6 +692,13 b' class HgRemote(object):'
683 repo = self._factory.repo(wire)
692 repo = self._factory.repo(wire)
684 baseui = self._factory._create_config(wire['config'])
693 baseui = self._factory._create_config(wire['config'])
685 repo.ui.setconfig('ui', 'merge', 'internal:dump')
694 repo.ui.setconfig('ui', 'merge', 'internal:dump')
695
696 # In case of sub repositories are used mercurial prompts the user in
697 # case of merge conflicts or different sub repository sources. By
698 # setting the interactive flag to `False` mercurial doesn't prompt the
699 # used but instead uses a default value.
700 repo.ui.setconfig('ui', 'interactive', False)
701
686 commands.merge(baseui, repo, rev=revision)
702 commands.merge(baseui, repo, rev=revision)
687
703
688 @reraise_safe_exceptions
704 @reraise_safe_exceptions
@@ -35,6 +35,7 b' from mercurial import discovery'
35 from mercurial import unionrepo
35 from mercurial import unionrepo
36 from mercurial import localrepo
36 from mercurial import localrepo
37 from mercurial import merge as hg_merge
37 from mercurial import merge as hg_merge
38 from mercurial import subrepo
38
39
39 from mercurial.commands import clone, nullid, pull
40 from mercurial.commands import clone, nullid, pull
40 from mercurial.context import memctx, memfilectx
41 from mercurial.context import memctx, memfilectx
@@ -58,3 +58,77 b' def _dynamic_capabilities_wrapper(lfprot'
58 return calc_capabilities(repo, proto)
58 return calc_capabilities(repo, proto)
59
59
60 return _dynamic_capabilities
60 return _dynamic_capabilities
61
62
63 def patch_subrepo_type_mapping():
64 from collections import defaultdict
65 from hgcompat import subrepo
66 from exceptions import SubrepoMergeException
67
68 class NoOpSubrepo(subrepo.abstractsubrepo):
69
70 def __init__(self, ctx, path, *args, **kwargs):
71 """Initialize abstractsubrepo part
72
73 ``ctx`` is the context referring this subrepository in the
74 parent repository.
75
76 ``path`` is the path to this subrepository as seen from
77 innermost repository.
78 """
79 self.ui = ctx.repo().ui
80 self._ctx = ctx
81 self._path = path
82
83 def storeclean(self, path):
84 """
85 returns true if the repository has not changed since it was last
86 cloned from or pushed to a given repository.
87 """
88 return True
89
90 def dirty(self, ignoreupdate=False):
91 """returns true if the dirstate of the subrepo is dirty or does not
92 match current stored state. If ignoreupdate is true, only check
93 whether the subrepo has uncommitted changes in its dirstate.
94 """
95 return False
96
97 def basestate(self):
98 """current working directory base state, disregarding .hgsubstate
99 state and working directory modifications"""
100 substate = subrepo.state(self._ctx, self.ui)
101 file_system_path, rev, repotype = substate.get(self._path)
102 return rev
103
104 def remove(self):
105 """remove the subrepo
106
107 (should verify the dirstate is not dirty first)
108 """
109 pass
110
111 def get(self, state, overwrite=False):
112 """run whatever commands are needed to put the subrepo into
113 this state
114 """
115 pass
116
117 def merge(self, state):
118 """merge currently-saved state with the new state."""
119 raise SubrepoMergeException()
120
121 def push(self, opts):
122 """perform whatever action is analogous to 'hg push'
123
124 This may be a no-op on some systems.
125 """
126 pass
127
128 # Patch subrepo type mapping to always return our NoOpSubrepo class
129 # whenever a subrepo class is looked up.
130 subrepo.types = {
131 'hg': NoOpSubrepo,
132 'git': NoOpSubrepo,
133 'svn': NoOpSubrepo
134 }
@@ -31,6 +31,7 b' from pyramid.wsgi import wsgiapp'
31 from vcsserver import remote_wsgi, scm_app, settings, hgpatches
31 from vcsserver import remote_wsgi, scm_app, settings, hgpatches
32 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
32 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
33 from vcsserver.echo_stub.echo_app import EchoApp
33 from vcsserver.echo_stub.echo_app import EchoApp
34 from vcsserver.exceptions import HTTPRepoLocked
34 from vcsserver.server import VcsServer
35 from vcsserver.server import VcsServer
35
36
36 try:
37 try:
@@ -181,6 +182,7 b' class HTTPApplication(object):'
181 name='msgpack',
182 name='msgpack',
182 factory=self._msgpack_renderer_factory)
183 factory=self._msgpack_renderer_factory)
183
184
185 self.config.add_route('service', '/_service')
184 self.config.add_route('status', '/status')
186 self.config.add_route('status', '/status')
185 self.config.add_route('hg_proxy', '/proxy/hg')
187 self.config.add_route('hg_proxy', '/proxy/hg')
186 self.config.add_route('git_proxy', '/proxy/git')
188 self.config.add_route('git_proxy', '/proxy/git')
@@ -190,6 +192,9 b' class HTTPApplication(object):'
190
192
191 self.config.add_view(
193 self.config.add_view(
192 self.status_view, route_name='status', renderer='json')
194 self.status_view, route_name='status', renderer='json')
195 self.config.add_view(
196 self.service_view, route_name='service', renderer='msgpack')
197
193 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
198 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
194 self.config.add_view(self.git_proxy(), route_name='git_proxy')
199 self.config.add_view(self.git_proxy(), route_name='git_proxy')
195 self.config.add_view(
200 self.config.add_view(
@@ -197,6 +202,9 b' class HTTPApplication(object):'
197
202
198 self.config.add_view(self.hg_stream(), route_name='stream_hg')
203 self.config.add_view(self.hg_stream(), route_name='stream_hg')
199 self.config.add_view(self.git_stream(), route_name='stream_git')
204 self.config.add_view(self.git_stream(), route_name='stream_git')
205 self.config.add_view(
206 self.handle_vcs_exception, context=Exception,
207 custom_predicates=[self.is_vcs_exception])
200
208
201 def wsgi_app(self):
209 def wsgi_app(self):
202 return self.config.make_wsgi_app()
210 return self.config.make_wsgi_app()
@@ -245,6 +253,19 b' class HTTPApplication(object):'
245 def status_view(self, request):
253 def status_view(self, request):
246 return {'status': 'OK'}
254 return {'status': 'OK'}
247
255
256 def service_view(self, request):
257 import vcsserver
258 payload = msgpack.unpackb(request.body, use_list=True)
259 resp = {
260 'id': payload.get('id'),
261 'result': dict(
262 version=vcsserver.__version__,
263 config={},
264 payload=payload,
265 )
266 }
267 return resp
268
248 def _msgpack_renderer_factory(self, info):
269 def _msgpack_renderer_factory(self, info):
249 def _render(value, system):
270 def _render(value, system):
250 value = msgpack.packb(value)
271 value = msgpack.packb(value)
@@ -317,6 +338,23 b' class HTTPApplication(object):'
317 return app(environ, start_response)
338 return app(environ, start_response)
318 return _git_stream
339 return _git_stream
319
340
341 def is_vcs_exception(self, context, request):
342 """
343 View predicate that returns true if the context object is a VCS
344 exception.
345 """
346 return hasattr(context, '_vcs_kind')
347
348 def handle_vcs_exception(self, exception, request):
349 if exception._vcs_kind == 'repo_locked':
350 # Get custom repo-locked status code if present.
351 status_code = request.headers.get('X-RC-Locked-Status-Code')
352 return HTTPRepoLocked(
353 title=exception.message, status_code=status_code)
354
355 # Re-raise exception if we can not handle it.
356 raise exception
357
320
358
321 class ResponseFilter(object):
359 class ResponseFilter(object):
322
360
@@ -333,5 +371,6 b' class ResponseFilter(object):'
333 def main(global_config, **settings):
371 def main(global_config, **settings):
334 if MercurialFactory:
372 if MercurialFactory:
335 hgpatches.patch_largefiles_capabilities()
373 hgpatches.patch_largefiles_capabilities()
374 hgpatches.patch_subrepo_type_mapping()
336 app = HTTPApplication(settings=settings)
375 app = HTTPApplication(settings=settings)
337 return app.wsgi_app()
376 return app.wsgi_app()
@@ -503,5 +503,6 b' class VcsServerCommand(object):'
503 def main(argv=sys.argv, quiet=False):
503 def main(argv=sys.argv, quiet=False):
504 if MercurialFactory:
504 if MercurialFactory:
505 hgpatches.patch_largefiles_capabilities()
505 hgpatches.patch_largefiles_capabilities()
506 hgpatches.patch_subrepo_type_mapping()
506 command = VcsServerCommand(argv, quiet=quiet)
507 command = VcsServerCommand(argv, quiet=quiet)
507 return command.run()
508 return command.run()
@@ -32,6 +32,7 b' import svn.fs'
32 import svn.repos
32 import svn.repos
33
33
34 from vcsserver import svn_diff
34 from vcsserver import svn_diff
35 from vcsserver import exceptions
35 from vcsserver.base import RepoFactory
36 from vcsserver.base import RepoFactory
36
37
37
38
@@ -48,6 +49,30 b' svn_compatible_versions = set(['
48 ])
49 ])
49
50
50
51
52 def reraise_safe_exceptions(func):
53 """Decorator for converting svn exceptions to something neutral."""
54 def wrapper(*args, **kwargs):
55 try:
56 return func(*args, **kwargs)
57 except Exception as e:
58 if not hasattr(e, '_vcs_kind'):
59 log.exception("Unhandled exception in hg remote call")
60 raise_from_original(exceptions.UnhandledException)
61 raise
62 return wrapper
63
64
65 def raise_from_original(new_type):
66 """
67 Raise a new exception type with original args and traceback.
68 """
69 _, original, traceback = sys.exc_info()
70 try:
71 raise new_type(*original.args), None, traceback
72 finally:
73 del traceback
74
75
51 class SubversionFactory(RepoFactory):
76 class SubversionFactory(RepoFactory):
52
77
53 def _create_repo(self, wire, create, compatible_version):
78 def _create_repo(self, wire, create, compatible_version):
@@ -88,6 +113,15 b' class SvnRemote(object):'
88 # for subversion
113 # for subversion
89 self._hg_factory = hg_factory
114 self._hg_factory = hg_factory
90
115
116 @reraise_safe_exceptions
117 def discover_svn_version(self):
118 try:
119 import svn.core
120 svn_ver = svn.core.SVN_VERSION
121 except ImportError:
122 svn_ver = None
123 return svn_ver
124
91 def check_url(self, url, config_items):
125 def check_url(self, url, config_items):
92 # this can throw exception if not installed, but we detect this
126 # this can throw exception if not installed, but we detect this
93 from hgsubversion import svnrepo
127 from hgsubversion import svnrepo
@@ -163,13 +197,15 b' class SvnRemote(object):'
163 for path, change in editor.changes.iteritems():
197 for path, change in editor.changes.iteritems():
164 # TODO: Decide what to do with directory nodes. Subversion can add
198 # TODO: Decide what to do with directory nodes. Subversion can add
165 # empty directories.
199 # empty directories.
200
166 if change.item_kind == svn.core.svn_node_dir:
201 if change.item_kind == svn.core.svn_node_dir:
167 continue
202 continue
168 if change.action == svn.repos.CHANGE_ACTION_ADD:
203 if change.action in [svn.repos.CHANGE_ACTION_ADD]:
169 added.append(path)
204 added.append(path)
170 elif change.action == svn.repos.CHANGE_ACTION_MODIFY:
205 elif change.action in [svn.repos.CHANGE_ACTION_MODIFY,
206 svn.repos.CHANGE_ACTION_REPLACE]:
171 changed.append(path)
207 changed.append(path)
172 elif change.action == svn.repos.CHANGE_ACTION_DELETE:
208 elif change.action in [svn.repos.CHANGE_ACTION_DELETE]:
173 removed.append(path)
209 removed.append(path)
174 else:
210 else:
175 raise NotImplementedError(
211 raise NotImplementedError(
General Comments 0
You need to be logged in to leave comments. Login now