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. |
|
|
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 = |
|
|
15 |
version = 4. |
|
|
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 |
|
|
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.subversion |
|
|
21 | httpSupport = true; | |
|
22 | pythonBindings = true; | |
|
23 | python = self.python27Packages.python; | |
|
24 | }; | |
|
19 | subversion = let | |
|
20 | subversionWithPython = super.subversion.override { | |
|
21 | httpSupport = true; | |
|
22 | pythonBindings = true; | |
|
23 | python = self.python27Packages.python; | |
|
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. |
|
|
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. |
|
|
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=[ |
@@ -1,18 +1,41 b'' | |||
|
1 | 1 | { pkgs ? import <nixpkgs> {} |
|
2 |
, |
|
|
2 | , doCheck ? false | |
|
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¶m=value', | |
|
54 | 'auth_token=*****&api_key=*****¶m=value'), | |
|
55 | ]) | |
|
56 | def test_obfuscate_qs(given, expected): | |
|
57 | assert expected == obfuscate_qs(given) |
@@ -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 = |
|
|
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 = |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 = |
|
|
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, |
|
|
34 |
httpbasicauthhandler, httpdigestauthhandler, |
|
|
35 |
match, memctx, exchange, memfilectx, nullrev, |
|
|
36 |
Abort, LookupError, RepoError, RepoLookupError, |
|
|
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 = |
|
|
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", |
|
|
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", |
|
|
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", |
|
|
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", |
|
|
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", |
|
|
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 |
|
|
203 | if change.action in [svn.repos.CHANGE_ACTION_ADD]: | |
|
169 | 204 | added.append(path) |
|
170 |
elif change.action |
|
|
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 |
|
|
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