##// 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 1 [bumpversion]
2 current_version = 4.4.2
2 current_version = 4.5.0
3 3 message = release: Bump version {current_version} to {new_version}
4 4
5 5 [bumpversion:file:vcsserver/VERSION]
@@ -5,12 +5,10 b' done = false'
5 5 done = true
6 6
7 7 [task:fixes_on_stable]
8 done = true
9 8
10 9 [task:pip2nix_generated]
11 done = true
12 10
13 11 [release]
14 state = prepared
15 version = 4.4.2
12 state = in_progress
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 7 [server:main]
24 8 ## COMMON ##
@@ -29,7 +13,7 b' port = 9900'
29 13 ##########################
30 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 17 use = egg:gunicorn#main
34 18 ## Sets the number of process workers. You must set `instance_id = *`
35 19 ## when this option is set to more than one worker, recommended
@@ -52,6 +36,22 b' max_requests_jitter = 30'
52 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 16 pkgs = pkgs_.overridePackages (self: super: {
17 17 # Override subversion derivation to
18 18 # - activate python bindings
19 # - set version to 1.8
20 subversion = super.subversion18.override {
19 subversion = let
20 subversionWithPython = super.subversion.override {
21 21 httpSupport = true;
22 22 pythonBindings = true;
23 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 34 inherit (pkgs.lib) fix extends;
@@ -86,21 +93,6 b' let'
86 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 96 # Add VCSServer bin directory to path so that tests can find 'vcsserver'.
105 97 preCheck = ''
106 98 export PATH="$out/bin:$PATH"
@@ -13,7 +13,8 b' in'
13 13 self: super: {
14 14
15 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 18 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
18 19 pkgs.aprutil
19 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 5 Beaker = super.buildPythonPackage {
3 6 name = "Beaker-1.7.0";
@@ -26,13 +29,13 b''
26 29 };
27 30 };
28 31 Mako = super.buildPythonPackage {
29 name = "Mako-1.0.4";
32 name = "Mako-1.0.6";
30 33 buildInputs = with self; [];
31 34 doCheck = false;
32 35 propagatedBuildInputs = with self; [MarkupSafe];
33 36 src = fetchurl {
34 url = "https://pypi.python.org/packages/7a/ae/925434246ee90b42e8ef57d3b30a0ab7caf9a2de3e449b876c56dcb48155/Mako-1.0.4.tar.gz";
35 md5 = "c5fc31a323dd4990683d2f2da02d4e20";
37 url = "https://pypi.python.org/packages/56/4b/cb75836863a6382199aefb3d3809937e21fa4cb0db15a4f4ba0ecc2e7e8e/Mako-1.0.6.tar.gz";
38 md5 = "a28e22a339080316b2acc352b9ee631c";
36 39 };
37 40 meta = {
38 41 license = [ pkgs.lib.licenses.mit ];
@@ -103,6 +106,19 b''
103 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 122 configobj = super.buildPythonPackage {
107 123 name = "configobj-5.0.6";
108 124 buildInputs = with self; [];
@@ -116,6 +132,19 b''
116 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 148 dulwich = super.buildPythonPackage {
120 149 name = "dulwich-0.13.0";
121 150 buildInputs = with self; [];
@@ -129,6 +158,19 b''
129 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 174 greenlet = super.buildPythonPackage {
133 175 name = "greenlet-0.4.7";
134 176 buildInputs = with self; [];
@@ -181,6 +223,45 b''
181 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 265 mercurial = super.buildPythonPackage {
185 266 name = "mercurial-3.8.4";
186 267 buildInputs = with self; [];
@@ -220,6 +301,71 b''
220 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 369 py = super.buildPythonPackage {
224 370 name = "py-1.4.29";
225 371 buildInputs = with self; [];
@@ -233,6 +379,19 b''
233 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 395 pyramid = super.buildPythonPackage {
237 396 name = "pyramid-1.6.1";
238 397 buildInputs = with self; [];
@@ -299,8 +458,8 b''
299 458 };
300 459 };
301 460 rhodecode-vcsserver = super.buildPythonPackage {
302 name = "rhodecode-vcsserver-4.4.2";
303 buildInputs = with self; [mock pytest WebTest];
461 name = "rhodecode-vcsserver-4.5.0";
462 buildInputs = with self; [mock pytest pytest-sugar WebTest];
304 463 doCheck = true;
305 464 propagatedBuildInputs = with self; [configobj dulwich hgsubversion infrae.cache mercurial msgpack-python pyramid Pyro4 simplejson subprocess32 waitress WebOb];
306 465 src = ./.;
@@ -334,6 +493,19 b''
334 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 509 simplejson = super.buildPythonPackage {
338 510 name = "simplejson-3.7.2";
339 511 buildInputs = with self; [];
@@ -344,7 +516,7 b''
344 516 md5 = "a5fc7d05d4cb38492285553def5d4b46";
345 517 };
346 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 522 six = super.buildPythonPackage {
@@ -386,6 +558,19 b''
386 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 574 translationstring = super.buildPythonPackage {
390 575 name = "translationstring-1.3";
391 576 buildInputs = with self; [];
@@ -425,6 +610,19 b''
425 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 626 wheel = super.buildPythonPackage {
429 627 name = "wheel-0.29.0";
430 628 buildInputs = with self; [];
@@ -467,5 +665,30 b''
467 665
468 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 3 dulwich==0.13.0
4 4 hgsubversion==1.8.6
5 5 infrae.cache==1.0.1
6 ipdb==0.10.1
6 7 mercurial==3.8.4
7 8 msgpack-python==0.4.6
8 9 py==1.4.29
@@ -74,6 +74,7 b' setup('
74 74 tests_require=[
75 75 'mock',
76 76 'pytest',
77 'pytest-sugar',
77 78 'WebTest',
78 79 ],
79 80 install_requires=[
@@ -3,16 +3,39 b''
3 3 }:
4 4
5 5 let
6
6 7 vcsserver = import ./default.nix {
7 inherit
8 doCheck
9 pkgs;
8 inherit pkgs doCheck;
10 9 };
11 10
11 vcs-pythonPackages = vcsserver.pythonPackages;
12
12 13 in vcsserver.override (attrs: {
13 14
14 15 # Avoid that we dump any sources into the store when entering the shell and
15 16 # make development a little bit more convenient.
16 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 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18 18 import mock
19 import pytest
19 20
20 21 from vcsserver import main
22 from vcsserver.base import obfuscate_qs
21 23
22 24
23 25 @mock.patch('vcsserver.main.VcsServerCommand', mock.Mock())
@@ -34,3 +36,22 b' def test_applies_largefiles_patch(patch_'
34 36 mock.Mock(side_effect=Exception("Must not be called")))
35 37 def test_applies_largefiles_patch_only_if_mercurial_is_available():
36 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 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18 18 import logging
19
19 import urlparse
20 20
21 21 log = logging.getLogger(__name__)
22 22
@@ -69,3 +69,17 b' class RepoFactory(object):'
69 69 'INIT %s@%s repo object based on wire %s. Context: %s',
70 70 self.__class__.__name__, wire['path'], wire, context)
71 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 27 import functools
28 from pyramid.httpexceptions import HTTPLocked
28 29
29 30
30 31 def _make_exception(kind, *args):
@@ -54,3 +55,16 b' RequirementException = functools.partial'
54 55 UnhandledException = functools.partial(_make_exception, 'unhandled')
55 56
56 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 36 from vcsserver import exceptions, settings, subprocessio
37 37 from vcsserver.utils import safe_str
38 from vcsserver.base import RepoFactory
38 from vcsserver.base import RepoFactory, obfuscate_qs
39 39 from vcsserver.hgcompat import (
40 hg_url, httpbasicauthhandler, httpdigestauthhandler)
40 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler)
41 41
42 42
43 43 DIR_STAT = stat.S_IFDIR
@@ -152,7 +152,7 b' class GitRemote(object):'
152 152
153 153 def _build_opener(self, url):
154 154 handlers = []
155 url_obj = hg_url(url)
155 url_obj = url_parser(url)
156 156 _, authinfo = url_obj.authinfo()
157 157
158 158 if authinfo:
@@ -167,10 +167,12 b' class GitRemote(object):'
167 167
168 168 @reraise_safe_exceptions
169 169 def check_url(self, url, config):
170 url_obj = hg_url(url)
170 url_obj = url_parser(url)
171 171 test_uri, _ = url_obj.authinfo()
172 172 url_obj.passwd = '*****'
173 url_obj.query = obfuscate_qs(url_obj.query)
173 174 cleaned_uri = str(url_obj)
175 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
174 176
175 177 if not test_uri.endswith('info/refs'):
176 178 test_uri = test_uri.rstrip('/') + '/info/refs'
@@ -184,12 +186,14 b' class GitRemote(object):'
184 186 req = urllib2.Request(cu, None, {})
185 187
186 188 try:
189 log.debug("Trying to open URL %s", cleaned_uri)
187 190 resp = o.open(req)
188 191 if resp.code != 200:
189 raise Exception('Return Code is not 200')
192 raise exceptions.URLError('Return Code is not 200')
190 193 except Exception as e:
194 log.warning("URL cannot be opened: %s", cleaned_uri, exc_info=True)
191 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 198 # now detect if it's proper git repo
195 199 gitdata = resp.read()
@@ -199,7 +203,7 b' class GitRemote(object):'
199 203 # old style git can return some other format !
200 204 pass
201 205 else:
202 raise urllib2.URLError(
206 raise exceptions.URLError(
203 207 "url [%s] does not look like an git" % (cleaned_uri,))
204 208
205 209 return True
@@ -327,7 +331,7 b' class GitRemote(object):'
327 331 if url != 'default' and '://' not in url:
328 332 client = LocalGitClient(url)
329 333 else:
330 url_obj = hg_url(url)
334 url_obj = url_parser(url)
331 335 o = self._build_opener(url)
332 336 url, _ = url_obj.authinfo()
333 337 client = HttpGitClient(base_url=url, opener=o)
@@ -521,7 +525,10 b' class GitRemote(object):'
521 525 def discover_git_version(self):
522 526 stdout, _ = self.run_git_command(
523 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 533 @reraise_safe_exceptions
527 534 def run_git_command(self, wire, cmd, **opts):
@@ -28,13 +28,13 b' from mercurial import commands'
28 28 from mercurial import unionrepo
29 29
30 30 from vcsserver import exceptions
31 from vcsserver.base import RepoFactory
31 from vcsserver.base import RepoFactory, obfuscate_qs
32 32 from vcsserver.hgcompat import (
33 archival, bin, clone, config as hgconfig, diffopts, hex, hg_url,
34 httpbasicauthhandler, httpdigestauthhandler, httppeer, localrepository,
35 match, memctx, exchange, memfilectx, nullrev, patch, peer, revrange, ui,
36 Abort, LookupError, RepoError, RepoLookupError, InterventionRequired,
37 RequirementError)
33 archival, bin, clone, config as hgconfig, diffopts, hex,
34 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler,
35 httppeer, localrepository, match, memctx, exchange, memfilectx, nullrev,
36 patch, peer, revrange, ui, Abort, LookupError, RepoError, RepoLookupError,
37 InterventionRequired, RequirementError)
38 38
39 39 log = logging.getLogger(__name__)
40 40
@@ -142,6 +142,11 b' class HgRemote(object):'
142 142 }
143 143
144 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 150 def archive_repo(self, archive_path, mtime, file_info, kind):
146 151 if kind == "tgz":
147 152 archiver = archival.tarit(archive_path, mtime, "gz")
@@ -316,16 +321,18 b' class HgRemote(object):'
316 321
317 322 @reraise_safe_exceptions
318 323 def check_url(self, url, config):
319 log.info("Checking URL for remote cloning/import: %s", url)
320 324 _proto = None
321 325 if '+' in url[:url.find('://')]:
322 326 _proto = url[0:url.find('+')]
323 327 url = url[url.find('+') + 1:]
324 328 handlers = []
325 url_obj = hg_url(url)
329 url_obj = url_parser(url)
326 330 test_uri, authinfo = url_obj.authinfo()
327 331 url_obj.passwd = '*****'
332 url_obj.query = obfuscate_qs(url_obj.query)
333
328 334 cleaned_uri = str(url_obj)
335 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
329 336
330 337 if authinfo:
331 338 # create a password manager
@@ -346,12 +353,12 b' class HgRemote(object):'
346 353 req = urllib2.Request(cu, None, {})
347 354
348 355 try:
349 log.debug("Trying to open URL %s", url)
356 log.debug("Trying to open URL %s", cleaned_uri)
350 357 resp = o.open(req)
351 358 if resp.code != 200:
352 359 raise exceptions.URLError('Return Code is not 200')
353 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 362 # means it cannot be cloned
356 363 raise exceptions.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
357 364
@@ -362,15 +369,17 b' class HgRemote(object):'
362 369 else:
363 370 # check for pure hg repos
364 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 374 httppeer(make_ui_from_config(config), url).lookup('tip')
367 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 378 raise exceptions.URLError(
370 379 "url [%s] does not look like an hg repo org_exc: %s"
371 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 383 return True
375 384
376 385 @reraise_safe_exceptions
@@ -683,6 +692,13 b' class HgRemote(object):'
683 692 repo = self._factory.repo(wire)
684 693 baseui = self._factory._create_config(wire['config'])
685 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 702 commands.merge(baseui, repo, rev=revision)
687 703
688 704 @reraise_safe_exceptions
@@ -35,6 +35,7 b' from mercurial import discovery'
35 35 from mercurial import unionrepo
36 36 from mercurial import localrepo
37 37 from mercurial import merge as hg_merge
38 from mercurial import subrepo
38 39
39 40 from mercurial.commands import clone, nullid, pull
40 41 from mercurial.context import memctx, memfilectx
@@ -58,3 +58,77 b' def _dynamic_capabilities_wrapper(lfprot'
58 58 return calc_capabilities(repo, proto)
59 59
60 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 31 from vcsserver import remote_wsgi, scm_app, settings, hgpatches
32 32 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
33 33 from vcsserver.echo_stub.echo_app import EchoApp
34 from vcsserver.exceptions import HTTPRepoLocked
34 35 from vcsserver.server import VcsServer
35 36
36 37 try:
@@ -181,6 +182,7 b' class HTTPApplication(object):'
181 182 name='msgpack',
182 183 factory=self._msgpack_renderer_factory)
183 184
185 self.config.add_route('service', '/_service')
184 186 self.config.add_route('status', '/status')
185 187 self.config.add_route('hg_proxy', '/proxy/hg')
186 188 self.config.add_route('git_proxy', '/proxy/git')
@@ -190,6 +192,9 b' class HTTPApplication(object):'
190 192
191 193 self.config.add_view(
192 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 198 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
194 199 self.config.add_view(self.git_proxy(), route_name='git_proxy')
195 200 self.config.add_view(
@@ -197,6 +202,9 b' class HTTPApplication(object):'
197 202
198 203 self.config.add_view(self.hg_stream(), route_name='stream_hg')
199 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 209 def wsgi_app(self):
202 210 return self.config.make_wsgi_app()
@@ -245,6 +253,19 b' class HTTPApplication(object):'
245 253 def status_view(self, request):
246 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 269 def _msgpack_renderer_factory(self, info):
249 270 def _render(value, system):
250 271 value = msgpack.packb(value)
@@ -317,6 +338,23 b' class HTTPApplication(object):'
317 338 return app(environ, start_response)
318 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 359 class ResponseFilter(object):
322 360
@@ -333,5 +371,6 b' class ResponseFilter(object):'
333 371 def main(global_config, **settings):
334 372 if MercurialFactory:
335 373 hgpatches.patch_largefiles_capabilities()
374 hgpatches.patch_subrepo_type_mapping()
336 375 app = HTTPApplication(settings=settings)
337 376 return app.wsgi_app()
@@ -503,5 +503,6 b' class VcsServerCommand(object):'
503 503 def main(argv=sys.argv, quiet=False):
504 504 if MercurialFactory:
505 505 hgpatches.patch_largefiles_capabilities()
506 hgpatches.patch_subrepo_type_mapping()
506 507 command = VcsServerCommand(argv, quiet=quiet)
507 508 return command.run()
@@ -32,6 +32,7 b' import svn.fs'
32 32 import svn.repos
33 33
34 34 from vcsserver import svn_diff
35 from vcsserver import exceptions
35 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 76 class SubversionFactory(RepoFactory):
52 77
53 78 def _create_repo(self, wire, create, compatible_version):
@@ -88,6 +113,15 b' class SvnRemote(object):'
88 113 # for subversion
89 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 125 def check_url(self, url, config_items):
92 126 # this can throw exception if not installed, but we detect this
93 127 from hgsubversion import svnrepo
@@ -163,13 +197,15 b' class SvnRemote(object):'
163 197 for path, change in editor.changes.iteritems():
164 198 # TODO: Decide what to do with directory nodes. Subversion can add
165 199 # empty directories.
200
166 201 if change.item_kind == svn.core.svn_node_dir:
167 202 continue
168 if change.action == svn.repos.CHANGE_ACTION_ADD:
203 if change.action in [svn.repos.CHANGE_ACTION_ADD]:
169 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 207 changed.append(path)
172 elif change.action == svn.repos.CHANGE_ACTION_DELETE:
208 elif change.action in [svn.repos.CHANGE_ACTION_DELETE]:
173 209 removed.append(path)
174 210 else:
175 211 raise NotImplementedError(
General Comments 0
You need to be logged in to leave comments. Login now