##// END OF EJS Templates
vcs-lib: code cleanup
marcink -
r2928:ee7f8502 default
parent child Browse files
Show More
@@ -1,191 +1,186 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2014-2018 RhodeCode GmbH
3 # Copyright (C) 2014-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Various version Control System version lib (vcs) management abstraction layer
22 Various version Control System version lib (vcs) management abstraction layer
23 for Python. Build with server client architecture.
23 for Python. Build with server client architecture.
24 """
24 """
25 import atexit
26 import logging
27 import urlparse
28 from cStringIO import StringIO
25
29
30 from rhodecode.lib.vcs.conf import settings
31 from rhodecode.lib.vcs.backends import get_vcs_instance, get_backend
32 from rhodecode.lib.vcs.exceptions import (
33 VCSError, RepositoryError, CommitError, VCSCommunicationError)
26
34
27 VERSION = (0, 5, 0, 'dev')
35 VERSION = (0, 5, 0, 'dev')
28
36
29 __version__ = '.'.join((str(each) for each in VERSION[:4]))
37 __version__ = '.'.join((str(each) for each in VERSION[:4]))
30
38
31 __all__ = [
39 __all__ = [
32 'get_version', 'get_vcs_instance', 'get_backend',
40 'get_version', 'get_vcs_instance', 'get_backend',
33 'VCSError', 'RepositoryError', 'CommitError'
41 'VCSError', 'RepositoryError', 'CommitError', 'VCSCommunicationError'
34 ]
42 ]
35
36 import atexit
37 import logging
38 import subprocess32
39 import time
40 import urlparse
41 from cStringIO import StringIO
42
43
44 from rhodecode.lib.vcs.conf import settings
45 from rhodecode.lib.vcs.backends import get_vcs_instance, get_backend
46 from rhodecode.lib.vcs.exceptions import (
47 VCSError, RepositoryError, CommitError, VCSCommunicationError)
48
43
49 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
50
45
51 # The pycurl library directly accesses C API functions and is not patched by
46 # The pycurl library directly accesses C API functions and is not patched by
52 # gevent. This will potentially lead to deadlocks due to incompatibility to
47 # gevent. This will potentially lead to deadlocks due to incompatibility to
53 # gevent. Therefore we check if gevent is active and import a gevent compatible
48 # gevent. Therefore we check if gevent is active and import a gevent compatible
54 # wrapper in that case.
49 # wrapper in that case.
55 try:
50 try:
56 from gevent import monkey
51 from gevent import monkey
57 if monkey.is_module_patched('__builtin__'):
52 if monkey.is_module_patched('__builtin__'):
58 import geventcurl as pycurl
53 import geventcurl as pycurl
59 log.debug('Using gevent comapatible pycurl: %s', pycurl)
54 log.debug('Using gevent comapatible pycurl: %s', pycurl)
60 else:
55 else:
61 import pycurl
56 import pycurl
62 except ImportError:
57 except ImportError:
63 import pycurl
58 import pycurl
64
59
65
60
66 def get_version():
61 def get_version():
67 """
62 """
68 Returns shorter version (digit parts only) as string.
63 Returns shorter version (digit parts only) as string.
69 """
64 """
70 return '.'.join((str(each) for each in VERSION[:3]))
65 return '.'.join((str(each) for each in VERSION[:3]))
71
66
72
67
73 def connect_http(server_and_port):
68 def connect_http(server_and_port):
74 from rhodecode.lib.vcs import connection, client_http
69 from rhodecode.lib.vcs import connection, client_http
75 from rhodecode.lib.middleware.utils import scm_app
70 from rhodecode.lib.middleware.utils import scm_app
76
71
77 session_factory = client_http.ThreadlocalSessionFactory()
72 session_factory = client_http.ThreadlocalSessionFactory()
78
73
79 connection.Git = client_http.RepoMaker(
74 connection.Git = client_http.RepoMaker(
80 server_and_port, '/git', 'git', session_factory)
75 server_and_port, '/git', 'git', session_factory)
81 connection.Hg = client_http.RepoMaker(
76 connection.Hg = client_http.RepoMaker(
82 server_and_port, '/hg', 'hg', session_factory)
77 server_and_port, '/hg', 'hg', session_factory)
83 connection.Svn = client_http.RepoMaker(
78 connection.Svn = client_http.RepoMaker(
84 server_and_port, '/svn', 'svn', session_factory)
79 server_and_port, '/svn', 'svn', session_factory)
85 connection.Service = client_http.ServiceConnection(
80 connection.Service = client_http.ServiceConnection(
86 server_and_port, '/_service', session_factory)
81 server_and_port, '/_service', session_factory)
87
82
88 scm_app.HG_REMOTE_WSGI = client_http.VcsHttpProxy(
83 scm_app.HG_REMOTE_WSGI = client_http.VcsHttpProxy(
89 server_and_port, '/proxy/hg')
84 server_and_port, '/proxy/hg')
90 scm_app.GIT_REMOTE_WSGI = client_http.VcsHttpProxy(
85 scm_app.GIT_REMOTE_WSGI = client_http.VcsHttpProxy(
91 server_and_port, '/proxy/git')
86 server_and_port, '/proxy/git')
92
87
93 @atexit.register
88 @atexit.register
94 def free_connection_resources():
89 def free_connection_resources():
95 connection.Git = None
90 connection.Git = None
96 connection.Hg = None
91 connection.Hg = None
97 connection.Svn = None
92 connection.Svn = None
98 connection.Service = None
93 connection.Service = None
99
94
100
95
101 def connect_vcs(server_and_port, protocol):
96 def connect_vcs(server_and_port, protocol):
102 """
97 """
103 Initializes the connection to the vcs server.
98 Initializes the connection to the vcs server.
104
99
105 :param server_and_port: str, e.g. "localhost:9900"
100 :param server_and_port: str, e.g. "localhost:9900"
106 :param protocol: str or "http"
101 :param protocol: str or "http"
107 """
102 """
108 if protocol == 'http':
103 if protocol == 'http':
109 connect_http(server_and_port)
104 connect_http(server_and_port)
110 else:
105 else:
111 raise Exception('Invalid vcs server protocol "{}"'.format(protocol))
106 raise Exception('Invalid vcs server protocol "{}"'.format(protocol))
112
107
113
108
114 def create_vcsserver_proxy(server_and_port, protocol):
109 def create_vcsserver_proxy(server_and_port, protocol):
115 if protocol == 'http':
110 if protocol == 'http':
116 return _create_vcsserver_proxy_http(server_and_port)
111 return _create_vcsserver_proxy_http(server_and_port)
117 else:
112 else:
118 raise Exception('Invalid vcs server protocol "{}"'.format(protocol))
113 raise Exception('Invalid vcs server protocol "{}"'.format(protocol))
119
114
120
115
121 def _create_vcsserver_proxy_http(server_and_port):
116 def _create_vcsserver_proxy_http(server_and_port):
122 from rhodecode.lib.vcs import client_http
117 from rhodecode.lib.vcs import client_http
123
118
124 session = _create_http_rpc_session()
119 session = _create_http_rpc_session()
125 url = urlparse.urljoin('http://%s' % server_and_port, '/server')
120 url = urlparse.urljoin('http://%s' % server_and_port, '/server')
126 return client_http.RemoteObject(url, session)
121 return client_http.RemoteObject(url, session)
127
122
128
123
129 class CurlSession(object):
124 class CurlSession(object):
130 """
125 """
131 Modeled so that it provides a subset of the requests interface.
126 Modeled so that it provides a subset of the requests interface.
132
127
133 This has been created so that it does only provide a minimal API for our
128 This has been created so that it does only provide a minimal API for our
134 needs. The parts which it provides are based on the API of the library
129 needs. The parts which it provides are based on the API of the library
135 `requests` which allows us to easily benchmark against it.
130 `requests` which allows us to easily benchmark against it.
136
131
137 Please have a look at the class :class:`requests.Session` when you extend
132 Please have a look at the class :class:`requests.Session` when you extend
138 it.
133 it.
139 """
134 """
140
135
141 def __init__(self):
136 def __init__(self):
142 curl = pycurl.Curl()
137 curl = pycurl.Curl()
143 # TODO: johbo: I did test with 7.19 of libcurl. This version has
138 # TODO: johbo: I did test with 7.19 of libcurl. This version has
144 # trouble with 100 - continue being set in the expect header. This
139 # trouble with 100 - continue being set in the expect header. This
145 # can lead to massive performance drops, switching it off here.
140 # can lead to massive performance drops, switching it off here.
146 curl.setopt(curl.HTTPHEADER, ["Expect:"])
141 curl.setopt(curl.HTTPHEADER, ["Expect:"])
147 curl.setopt(curl.TCP_NODELAY, True)
142 curl.setopt(curl.TCP_NODELAY, True)
148 curl.setopt(curl.PROTOCOLS, curl.PROTO_HTTP)
143 curl.setopt(curl.PROTOCOLS, curl.PROTO_HTTP)
149 self._curl = curl
144 self._curl = curl
150
145
151 def post(self, url, data, allow_redirects=False):
146 def post(self, url, data, allow_redirects=False):
152 response_buffer = StringIO()
147 response_buffer = StringIO()
153
148
154 curl = self._curl
149 curl = self._curl
155 curl.setopt(curl.URL, url)
150 curl.setopt(curl.URL, url)
156 curl.setopt(curl.POST, True)
151 curl.setopt(curl.POST, True)
157 curl.setopt(curl.POSTFIELDS, data)
152 curl.setopt(curl.POSTFIELDS, data)
158 curl.setopt(curl.FOLLOWLOCATION, allow_redirects)
153 curl.setopt(curl.FOLLOWLOCATION, allow_redirects)
159 curl.setopt(curl.WRITEDATA, response_buffer)
154 curl.setopt(curl.WRITEDATA, response_buffer)
160 curl.perform()
155 curl.perform()
161
156
162 status_code = curl.getinfo(pycurl.HTTP_CODE)
157 status_code = curl.getinfo(pycurl.HTTP_CODE)
163
158
164 return CurlResponse(response_buffer, status_code)
159 return CurlResponse(response_buffer, status_code)
165
160
166
161
167 class CurlResponse(object):
162 class CurlResponse(object):
168 """
163 """
169 The response of a request, modeled after the requests API.
164 The response of a request, modeled after the requests API.
170
165
171 This class provides a subset of the response interface known from the
166 This class provides a subset of the response interface known from the
172 library `requests`. It is intentionally kept similar, so that we can use
167 library `requests`. It is intentionally kept similar, so that we can use
173 `requests` as a drop in replacement for benchmarking purposes.
168 `requests` as a drop in replacement for benchmarking purposes.
174 """
169 """
175
170
176 def __init__(self, response_buffer, status_code):
171 def __init__(self, response_buffer, status_code):
177 self._response_buffer = response_buffer
172 self._response_buffer = response_buffer
178 self._status_code = status_code
173 self._status_code = status_code
179
174
180 @property
175 @property
181 def content(self):
176 def content(self):
182 return self._response_buffer.getvalue()
177 return self._response_buffer.getvalue()
183
178
184 @property
179 @property
185 def status_code(self):
180 def status_code(self):
186 return self._status_code
181 return self._status_code
187
182
188
183
189 def _create_http_rpc_session():
184 def _create_http_rpc_session():
190 session = CurlSession()
185 session = CurlSession()
191 return session
186 return session
General Comments 0
You need to be logged in to leave comments. Login now