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. |
|
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 = |
|
12 | state = in_progress | |
15 |
version = 4. |
|
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 |
|
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.subversion |
|
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. |
|
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. |
|
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¶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 | # 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 = |
|
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 = |
|
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 |
|
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 |
|
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 |
|
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 = |
|
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, |
|
33 | archival, bin, clone, config as hgconfig, diffopts, hex, | |
34 |
httpbasicauthhandler, httpdigestauthhandler, |
|
34 | hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler, | |
35 |
match, memctx, exchange, memfilectx, nullrev, |
|
35 | httppeer, localrepository, match, memctx, exchange, memfilectx, nullrev, | |
36 |
Abort, LookupError, RepoError, RepoLookupError, |
|
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 = |
|
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", |
|
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", |
|
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", |
|
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", |
|
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", |
|
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 |
|
203 | if change.action in [svn.repos.CHANGE_ACTION_ADD]: | |
169 | added.append(path) |
|
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 | changed.append(path) |
|
207 | changed.append(path) | |
172 |
elif change.action |
|
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