Show More
@@ -0,0 +1,16 b'' | |||
|
1 | # RhodeCode VCSServer provides access to different vcs backends via network. | |
|
2 | # Copyright (C) 2014-2018 RhodeCode GmbH | |
|
3 | # | |
|
4 | # This program is free software; you can redistribute it and/or modify | |
|
5 | # it under the terms of the GNU General Public License as published by | |
|
6 | # the Free Software Foundation; either version 3 of the License, or | |
|
7 | # (at your option) any later version. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU General Public License | |
|
15 | # along with this program; if not, write to the Free Software Foundation, | |
|
16 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
@@ -0,0 +1,60 b'' | |||
|
1 | # RhodeCode VCSServer provides access to different vcs backends via network. | |
|
2 | # Copyright (C) 2014-2018 RhodeCode GmbH | |
|
3 | # | |
|
4 | # This program is free software; you can redistribute it and/or modify | |
|
5 | # it under the terms of the GNU General Public License as published by | |
|
6 | # the Free Software Foundation; either version 3 of the License, or | |
|
7 | # (at your option) any later version. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU General Public License | |
|
15 | # along with this program; if not, write to the Free Software Foundation, | |
|
16 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
|
17 | ||
|
18 | import logging | |
|
19 | from dogpile.cache import register_backend | |
|
20 | ||
|
21 | register_backend( | |
|
22 | "dogpile.cache.rc.memory_lru", "vcsserver.lib.rc_cache.backends", | |
|
23 | "LRUMemoryBackend") | |
|
24 | ||
|
25 | log = logging.getLogger(__name__) | |
|
26 | ||
|
27 | from . import region_meta | |
|
28 | from .util import key_generator, get_default_cache_settings, make_region | |
|
29 | ||
|
30 | ||
|
31 | def configure_dogpile_cache(settings): | |
|
32 | cache_dir = settings.get('cache_dir') | |
|
33 | if cache_dir: | |
|
34 | region_meta.dogpile_config_defaults['cache_dir'] = cache_dir | |
|
35 | ||
|
36 | rc_cache_data = get_default_cache_settings(settings, prefixes=['rc_cache.']) | |
|
37 | ||
|
38 | # inspect available namespaces | |
|
39 | avail_regions = set() | |
|
40 | for key in rc_cache_data.keys(): | |
|
41 | namespace_name = key.split('.', 1)[0] | |
|
42 | avail_regions.add(namespace_name) | |
|
43 | log.debug('dogpile: found following cache regions: %s', avail_regions) | |
|
44 | ||
|
45 | # register them into namespace | |
|
46 | for region_name in avail_regions: | |
|
47 | new_region = make_region( | |
|
48 | name=region_name, | |
|
49 | function_key_generator=key_generator | |
|
50 | ) | |
|
51 | ||
|
52 | new_region.configure_from_config(settings, 'rc_cache.{}.'.format(region_name)) | |
|
53 | ||
|
54 | log.debug('dogpile: registering a new region %s[%s]', | |
|
55 | region_name, new_region.__dict__) | |
|
56 | region_meta.dogpile_cache_regions[region_name] = new_region | |
|
57 | ||
|
58 | ||
|
59 | def includeme(config): | |
|
60 | configure_dogpile_cache(config.registry.settings) |
@@ -0,0 +1,51 b'' | |||
|
1 | # RhodeCode VCSServer provides access to different vcs backends via network. | |
|
2 | # Copyright (C) 2014-2018 RhodeCode GmbH | |
|
3 | # | |
|
4 | # This program is free software; you can redistribute it and/or modify | |
|
5 | # it under the terms of the GNU General Public License as published by | |
|
6 | # the Free Software Foundation; either version 3 of the License, or | |
|
7 | # (at your option) any later version. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU General Public License | |
|
15 | # along with this program; if not, write to the Free Software Foundation, | |
|
16 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
|
17 | ||
|
18 | import logging | |
|
19 | ||
|
20 | from dogpile.cache.backends import memory as memory_backend | |
|
21 | from lru import LRU as LRUDict | |
|
22 | ||
|
23 | ||
|
24 | _default_max_size = 1024 | |
|
25 | ||
|
26 | log = logging.getLogger(__name__) | |
|
27 | ||
|
28 | ||
|
29 | class LRUMemoryBackend(memory_backend.MemoryBackend): | |
|
30 | pickle_values = False | |
|
31 | ||
|
32 | def __init__(self, arguments): | |
|
33 | max_size = arguments.pop('max_size', _default_max_size) | |
|
34 | callback = None | |
|
35 | if arguments.pop('log_max_size_reached', None): | |
|
36 | def evicted(key, value): | |
|
37 | log.debug( | |
|
38 | 'LRU: evicting key `%s` due to max size %s reach', key, max_size) | |
|
39 | callback = evicted | |
|
40 | ||
|
41 | arguments['cache_dict'] = LRUDict(max_size, callback=callback) | |
|
42 | super(LRUMemoryBackend, self).__init__(arguments) | |
|
43 | ||
|
44 | def delete(self, key): | |
|
45 | if self._cache.has_key(key): | |
|
46 | del self._cache[key] | |
|
47 | ||
|
48 | def delete_multi(self, keys): | |
|
49 | for key in keys: | |
|
50 | if self._cache.has_key(key): | |
|
51 | del self._cache[key] |
@@ -0,0 +1,26 b'' | |||
|
1 | # RhodeCode VCSServer provides access to different vcs backends via network. | |
|
2 | # Copyright (C) 2014-2018 RhodeCode GmbH | |
|
3 | # | |
|
4 | # This program is free software; you can redistribute it and/or modify | |
|
5 | # it under the terms of the GNU General Public License as published by | |
|
6 | # the Free Software Foundation; either version 3 of the License, or | |
|
7 | # (at your option) any later version. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU General Public License | |
|
15 | # along with this program; if not, write to the Free Software Foundation, | |
|
16 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
|
17 | ||
|
18 | import os | |
|
19 | import tempfile | |
|
20 | ||
|
21 | dogpile_config_defaults = { | |
|
22 | 'cache_dir': os.path.join(tempfile.gettempdir(), 'rc_cache') | |
|
23 | } | |
|
24 | ||
|
25 | # GLOBAL TO STORE ALL REGISTERED REGIONS | |
|
26 | dogpile_cache_regions = {} |
@@ -0,0 +1,136 b'' | |||
|
1 | # RhodeCode VCSServer provides access to different vcs backends via network. | |
|
2 | # Copyright (C) 2014-2018 RhodeCode GmbH | |
|
3 | # | |
|
4 | # This program is free software; you can redistribute it and/or modify | |
|
5 | # it under the terms of the GNU General Public License as published by | |
|
6 | # the Free Software Foundation; either version 3 of the License, or | |
|
7 | # (at your option) any later version. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU General Public License | |
|
15 | # along with this program; if not, write to the Free Software Foundation, | |
|
16 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
|
17 | ||
|
18 | import os | |
|
19 | import logging | |
|
20 | import functools | |
|
21 | ||
|
22 | from vcsserver.utils import safe_str, sha1 | |
|
23 | from dogpile.cache import CacheRegion | |
|
24 | from dogpile.cache.util import compat | |
|
25 | ||
|
26 | log = logging.getLogger(__name__) | |
|
27 | ||
|
28 | ||
|
29 | class RhodeCodeCacheRegion(CacheRegion): | |
|
30 | ||
|
31 | def conditional_cache_on_arguments( | |
|
32 | self, namespace=None, | |
|
33 | expiration_time=None, | |
|
34 | should_cache_fn=None, | |
|
35 | to_str=compat.string_type, | |
|
36 | function_key_generator=None, | |
|
37 | condition=True): | |
|
38 | """ | |
|
39 | Custom conditional decorator, that will not touch any dogpile internals if | |
|
40 | condition isn't meet. This works a bit different than should_cache_fn | |
|
41 | And it's faster in cases we don't ever want to compute cached values | |
|
42 | """ | |
|
43 | expiration_time_is_callable = compat.callable(expiration_time) | |
|
44 | ||
|
45 | if function_key_generator is None: | |
|
46 | function_key_generator = self.function_key_generator | |
|
47 | ||
|
48 | def decorator(fn): | |
|
49 | if to_str is compat.string_type: | |
|
50 | # backwards compatible | |
|
51 | key_generator = function_key_generator(namespace, fn) | |
|
52 | else: | |
|
53 | key_generator = function_key_generator(namespace, fn, to_str=to_str) | |
|
54 | ||
|
55 | @functools.wraps(fn) | |
|
56 | def decorate(*arg, **kw): | |
|
57 | key = key_generator(*arg, **kw) | |
|
58 | ||
|
59 | @functools.wraps(fn) | |
|
60 | def creator(): | |
|
61 | return fn(*arg, **kw) | |
|
62 | ||
|
63 | if not condition: | |
|
64 | return creator() | |
|
65 | ||
|
66 | timeout = expiration_time() if expiration_time_is_callable \ | |
|
67 | else expiration_time | |
|
68 | ||
|
69 | return self.get_or_create(key, creator, timeout, should_cache_fn) | |
|
70 | ||
|
71 | def invalidate(*arg, **kw): | |
|
72 | key = key_generator(*arg, **kw) | |
|
73 | self.delete(key) | |
|
74 | ||
|
75 | def set_(value, *arg, **kw): | |
|
76 | key = key_generator(*arg, **kw) | |
|
77 | self.set(key, value) | |
|
78 | ||
|
79 | def get(*arg, **kw): | |
|
80 | key = key_generator(*arg, **kw) | |
|
81 | return self.get(key) | |
|
82 | ||
|
83 | def refresh(*arg, **kw): | |
|
84 | key = key_generator(*arg, **kw) | |
|
85 | value = fn(*arg, **kw) | |
|
86 | self.set(key, value) | |
|
87 | return value | |
|
88 | ||
|
89 | decorate.set = set_ | |
|
90 | decorate.invalidate = invalidate | |
|
91 | decorate.refresh = refresh | |
|
92 | decorate.get = get | |
|
93 | decorate.original = fn | |
|
94 | decorate.key_generator = key_generator | |
|
95 | ||
|
96 | return decorate | |
|
97 | ||
|
98 | return decorator | |
|
99 | ||
|
100 | ||
|
101 | def make_region(*arg, **kw): | |
|
102 | return RhodeCodeCacheRegion(*arg, **kw) | |
|
103 | ||
|
104 | ||
|
105 | def get_default_cache_settings(settings, prefixes=None): | |
|
106 | prefixes = prefixes or [] | |
|
107 | cache_settings = {} | |
|
108 | for key in settings.keys(): | |
|
109 | for prefix in prefixes: | |
|
110 | if key.startswith(prefix): | |
|
111 | name = key.split(prefix)[1].strip() | |
|
112 | val = settings[key] | |
|
113 | if isinstance(val, basestring): | |
|
114 | val = val.strip() | |
|
115 | cache_settings[name] = val | |
|
116 | return cache_settings | |
|
117 | ||
|
118 | ||
|
119 | def compute_key_from_params(*args): | |
|
120 | """ | |
|
121 | Helper to compute key from given params to be used in cache manager | |
|
122 | """ | |
|
123 | return sha1("_".join(map(safe_str, args))) | |
|
124 | ||
|
125 | ||
|
126 | def key_generator(namespace, fn): | |
|
127 | fname = fn.__name__ | |
|
128 | ||
|
129 | def generate_key(*args): | |
|
130 | namespace_pref = namespace or 'default' | |
|
131 | arg_key = compute_key_from_params(*args) | |
|
132 | final_key = "{}:{}_{}".format(namespace_pref, fname, arg_key) | |
|
133 | ||
|
134 | return final_key | |
|
135 | ||
|
136 | return generate_key |
@@ -1,1 +1,79 b'' | |||
|
1 | development_http.ini No newline at end of file | |
|
1 | ################################################################################ | |
|
2 | # RhodeCode VCSServer with HTTP Backend - configuration # | |
|
3 | # # | |
|
4 | ################################################################################ | |
|
5 | ||
|
6 | ||
|
7 | [server:main] | |
|
8 | ## COMMON ## | |
|
9 | host = 0.0.0.0 | |
|
10 | port = 9900 | |
|
11 | ||
|
12 | use = egg:waitress#main | |
|
13 | ||
|
14 | ||
|
15 | [app:main] | |
|
16 | use = egg:rhodecode-vcsserver | |
|
17 | ||
|
18 | pyramid.default_locale_name = en | |
|
19 | pyramid.includes = | |
|
20 | ||
|
21 | ## default locale used by VCS systems | |
|
22 | locale = en_US.UTF-8 | |
|
23 | ||
|
24 | ||
|
25 | ## path to binaries for vcsserver, it should be set by the installer | |
|
26 | ## at installation time, e.g /home/user/vcsserver-1/profile/bin | |
|
27 | core.binary_dir = "" | |
|
28 | ||
|
29 | ## cache region for storing repo_objects cache | |
|
30 | rc_cache.repo_object.backend = dogpile.cache.rc.memory_lru | |
|
31 | ## cache auto-expires after N seconds | |
|
32 | rc_cache.repo_object.expiration_time = 300 | |
|
33 | ## max size of LRU, old values will be discarded if the size of cache reaches max_size | |
|
34 | rc_cache.repo_object.max_size = 100 | |
|
35 | ||
|
36 | ||
|
37 | ################################ | |
|
38 | ### LOGGING CONFIGURATION #### | |
|
39 | ################################ | |
|
40 | [loggers] | |
|
41 | keys = root, vcsserver | |
|
42 | ||
|
43 | [handlers] | |
|
44 | keys = console | |
|
45 | ||
|
46 | [formatters] | |
|
47 | keys = generic | |
|
48 | ||
|
49 | ############# | |
|
50 | ## LOGGERS ## | |
|
51 | ############# | |
|
52 | [logger_root] | |
|
53 | level = NOTSET | |
|
54 | handlers = console | |
|
55 | ||
|
56 | [logger_vcsserver] | |
|
57 | level = DEBUG | |
|
58 | handlers = | |
|
59 | qualname = vcsserver | |
|
60 | propagate = 1 | |
|
61 | ||
|
62 | ||
|
63 | ############## | |
|
64 | ## HANDLERS ## | |
|
65 | ############## | |
|
66 | ||
|
67 | [handler_console] | |
|
68 | class = StreamHandler | |
|
69 | args = (sys.stderr,) | |
|
70 | level = DEBUG | |
|
71 | formatter = generic | |
|
72 | ||
|
73 | ################ | |
|
74 | ## FORMATTERS ## | |
|
75 | ################ | |
|
76 | ||
|
77 | [formatter_generic] | |
|
78 | format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | |
|
79 | datefmt = %Y-%m-%d %H:%M:%S |
@@ -1,1 +1,100 b'' | |||
|
1 | production_http.ini No newline at end of file | |
|
1 | ################################################################################ | |
|
2 | # RhodeCode VCSServer with HTTP Backend - configuration # | |
|
3 | # # | |
|
4 | ################################################################################ | |
|
5 | ||
|
6 | ||
|
7 | [server:main] | |
|
8 | ## COMMON ## | |
|
9 | host = 127.0.0.1 | |
|
10 | port = 9900 | |
|
11 | ||
|
12 | ||
|
13 | ########################## | |
|
14 | ## GUNICORN WSGI SERVER ## | |
|
15 | ########################## | |
|
16 | ## run with gunicorn --log-config vcsserver.ini --paste vcsserver.ini | |
|
17 | use = egg:gunicorn#main | |
|
18 | ## Sets the number of process workers. Recommended | |
|
19 | ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers | |
|
20 | workers = 2 | |
|
21 | ## process name | |
|
22 | proc_name = rhodecode_vcsserver | |
|
23 | ## type of worker class, currently `sync` is the only option allowed. | |
|
24 | worker_class = sync | |
|
25 | ## The maximum number of simultaneous clients. Valid only for Gevent | |
|
26 | #worker_connections = 10 | |
|
27 | ## max number of requests that worker will handle before being gracefully | |
|
28 | ## restarted, could prevent memory leaks | |
|
29 | max_requests = 1000 | |
|
30 | max_requests_jitter = 30 | |
|
31 | ## amount of time a worker can spend with handling a request before it | |
|
32 | ## gets killed and restarted. Set to 6hrs | |
|
33 | timeout = 21600 | |
|
34 | ||
|
35 | ||
|
36 | [app:main] | |
|
37 | use = egg:rhodecode-vcsserver | |
|
38 | ||
|
39 | pyramid.default_locale_name = en | |
|
40 | pyramid.includes = | |
|
41 | ||
|
42 | ## default locale used by VCS systems | |
|
43 | locale = en_US.UTF-8 | |
|
44 | ||
|
45 | ||
|
46 | ## path to binaries for vcsserver, it should be set by the installer | |
|
47 | ## at installation time, e.g /home/user/vcsserver-1/profile/bin | |
|
48 | core.binary_dir = "" | |
|
49 | ||
|
50 | ## cache region for storing repo_objects cache | |
|
51 | rc_cache.repo_object.backend = dogpile.cache.rc.memory_lru | |
|
52 | ## cache auto-expires after N seconds | |
|
53 | rc_cache.repo_object.expiration_time = 300 | |
|
54 | ## max size of LRU, old values will be discarded if the size of cache reaches max_size | |
|
55 | rc_cache.repo_object.max_size = 100 | |
|
56 | ||
|
57 | ||
|
58 | ################################ | |
|
59 | ### LOGGING CONFIGURATION #### | |
|
60 | ################################ | |
|
61 | [loggers] | |
|
62 | keys = root, vcsserver | |
|
63 | ||
|
64 | [handlers] | |
|
65 | keys = console | |
|
66 | ||
|
67 | [formatters] | |
|
68 | keys = generic | |
|
69 | ||
|
70 | ############# | |
|
71 | ## LOGGERS ## | |
|
72 | ############# | |
|
73 | [logger_root] | |
|
74 | level = NOTSET | |
|
75 | handlers = console | |
|
76 | ||
|
77 | [logger_vcsserver] | |
|
78 | level = DEBUG | |
|
79 | handlers = | |
|
80 | qualname = vcsserver | |
|
81 | propagate = 1 | |
|
82 | ||
|
83 | ||
|
84 | ############## | |
|
85 | ## HANDLERS ## | |
|
86 | ############## | |
|
87 | ||
|
88 | [handler_console] | |
|
89 | class = StreamHandler | |
|
90 | args = (sys.stderr,) | |
|
91 | level = DEBUG | |
|
92 | formatter = generic | |
|
93 | ||
|
94 | ################ | |
|
95 | ## FORMATTERS ## | |
|
96 | ################ | |
|
97 | ||
|
98 | [formatter_generic] | |
|
99 | format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | |
|
100 | datefmt = %Y-%m-%d %H:%M:%S |
@@ -15,13 +15,6 b' in' | |||
|
15 | 15 | |
|
16 | 16 | self: super: { |
|
17 | 17 | |
|
18 | "beaker" = super."beaker".override (attrs: { | |
|
19 | patches = [ | |
|
20 | ./patch_beaker/patch-beaker-lock-func-debug.diff | |
|
21 | ./patch_beaker/patch-beaker-metadata-reuse.diff | |
|
22 | ]; | |
|
23 | }); | |
|
24 | ||
|
25 | 18 | "gevent" = super."gevent".override (attrs: { |
|
26 | 19 | propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ |
|
27 | 20 | # NOTE: (marcink) odd requirements from gevent aren't set properly, |
@@ -37,20 +37,6 b' self: super: {' | |||
|
37 | 37 | license = [ pkgs.lib.licenses.mit ]; |
|
38 | 38 | }; |
|
39 | 39 | }; |
|
40 | "beaker" = super.buildPythonPackage { | |
|
41 | name = "beaker-1.9.1"; | |
|
42 | doCheck = false; | |
|
43 | propagatedBuildInputs = [ | |
|
44 | self."funcsigs" | |
|
45 | ]; | |
|
46 | src = fetchurl { | |
|
47 | url = "https://files.pythonhosted.org/packages/ca/14/a626188d0d0c7b55dd7cf1902046c2743bd392a7078bb53073e13280eb1e/Beaker-1.9.1.tar.gz"; | |
|
48 | sha256 = "08arsn61r255lhz6hcpn2lsiqpg30clla805ysx06wmbhvb6w9rj"; | |
|
49 | }; | |
|
50 | meta = { | |
|
51 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
52 | }; | |
|
53 | }; | |
|
54 | 40 | "beautifulsoup4" = super.buildPythonPackage { |
|
55 | 41 | name = "beautifulsoup4-4.6.0"; |
|
56 | 42 | doCheck = false; |
@@ -112,6 +98,28 b' self: super: {' | |||
|
112 | 98 | license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ]; |
|
113 | 99 | }; |
|
114 | 100 | }; |
|
101 | "dogpile.cache" = super.buildPythonPackage { | |
|
102 | name = "dogpile.cache-0.6.6"; | |
|
103 | doCheck = false; | |
|
104 | src = fetchurl { | |
|
105 | url = "https://files.pythonhosted.org/packages/48/ca/604154d835c3668efb8a31bd979b0ea4bf39c2934a40ffecc0662296cb51/dogpile.cache-0.6.6.tar.gz"; | |
|
106 | sha256 = "1h8n1lxd4l2qvahfkiinljkqz7pww7w3sgag0j8j9ixbl2h4wk84"; | |
|
107 | }; | |
|
108 | meta = { | |
|
109 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
110 | }; | |
|
111 | }; | |
|
112 | "dogpile.core" = super.buildPythonPackage { | |
|
113 | name = "dogpile.core-0.4.1"; | |
|
114 | doCheck = false; | |
|
115 | src = fetchurl { | |
|
116 | url = "https://files.pythonhosted.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz"; | |
|
117 | sha256 = "0xpdvg4kr1isfkrh1rfsh7za4q5a5s6l2kf9wpvndbwf3aqjyrdy"; | |
|
118 | }; | |
|
119 | meta = { | |
|
120 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
121 | }; | |
|
122 | }; | |
|
115 | 123 | "dulwich" = super.buildPythonPackage { |
|
116 | 124 | name = "dulwich-0.13.0"; |
|
117 | 125 | doCheck = false; |
@@ -229,21 +237,6 b' self: super: {' | |||
|
229 | 237 | license = [ pkgs.lib.licenses.mit ]; |
|
230 | 238 | }; |
|
231 | 239 | }; |
|
232 | "infrae.cache" = super.buildPythonPackage { | |
|
233 | name = "infrae.cache-1.0.1"; | |
|
234 | doCheck = false; | |
|
235 | propagatedBuildInputs = [ | |
|
236 | self."beaker" | |
|
237 | self."repoze.lru" | |
|
238 | ]; | |
|
239 | src = fetchurl { | |
|
240 | url = "https://files.pythonhosted.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz"; | |
|
241 | sha256 = "1dvqsjn8vw253wz9d1pz17j79mf4bs53dvp2qxck2qdp1am1njw4"; | |
|
242 | }; | |
|
243 | meta = { | |
|
244 | license = [ pkgs.lib.licenses.zpl21 ]; | |
|
245 | }; | |
|
246 | }; | |
|
247 | 240 | "ipdb" = super.buildPythonPackage { |
|
248 | 241 | name = "ipdb-0.11"; |
|
249 | 242 | doCheck = false; |
@@ -294,6 +287,17 b' self: super: {' | |||
|
294 | 287 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
295 | 288 | }; |
|
296 | 289 | }; |
|
290 | "lru-dict" = super.buildPythonPackage { | |
|
291 | name = "lru-dict-1.1.6"; | |
|
292 | doCheck = false; | |
|
293 | src = fetchurl { | |
|
294 | url = "https://files.pythonhosted.org/packages/00/a5/32ed6e10246cd341ca8cc205acea5d208e4053f48a4dced2b1b31d45ba3f/lru-dict-1.1.6.tar.gz"; | |
|
295 | sha256 = "1k2lhd4dpl6xa6iialbwx4l6bkdzxmzhygms39pvf19x1rk5fm1n"; | |
|
296 | }; | |
|
297 | meta = { | |
|
298 | license = [ pkgs.lib.licenses.mit ]; | |
|
299 | }; | |
|
300 | }; | |
|
297 | 301 | "mako" = super.buildPythonPackage { |
|
298 | 302 | name = "mako-1.0.7"; |
|
299 | 303 | doCheck = false; |
@@ -680,13 +684,14 b' self: super: {' | |||
|
680 | 684 | ]; |
|
681 | 685 | doCheck = true; |
|
682 | 686 | propagatedBuildInputs = [ |
|
683 | self."beaker" | |
|
684 | 687 | self."configobj" |
|
688 | self."dogpile.cache" | |
|
689 | self."dogpile.core" | |
|
685 | 690 | self."decorator" |
|
686 | 691 | self."dulwich" |
|
687 | 692 | self."hgsubversion" |
|
688 | 693 | self."hg-evolve" |
|
689 |
self."i |
|
|
694 | self."lru-dict" | |
|
690 | 695 | self."mako" |
|
691 | 696 | self."markupsafe" |
|
692 | 697 | self."mercurial" |
@@ -1,12 +1,13 b'' | |||
|
1 | 1 | ## dependencies |
|
2 | 2 | |
|
3 | beaker==1.9.1 | |
|
4 | 3 | configobj==5.0.6 |
|
4 | dogpile.cache==0.6.6 | |
|
5 | dogpile.core==0.4.1 | |
|
5 | 6 | decorator==4.1.2 |
|
6 | 7 | dulwich==0.13.0 |
|
7 | 8 | hgsubversion==1.9.2 |
|
8 | 9 | hg-evolve==8.0.1 |
|
9 | infrae.cache==1.0.1 | |
|
10 | lru-dict==1.1.6 | |
|
10 | 11 | mako==1.0.7 |
|
11 | 12 | markupsafe==1.0.0 |
|
12 | 13 | mercurial==4.6.1 |
@@ -20,6 +20,7 b' import traceback' | |||
|
20 | 20 | import logging |
|
21 | 21 | import urlparse |
|
22 | 22 | |
|
23 | from vcsserver.lib.rc_cache import region_meta | |
|
23 | 24 | log = logging.getLogger(__name__) |
|
24 | 25 | |
|
25 | 26 | |
@@ -30,9 +31,10 b' class RepoFactory(object):' | |||
|
30 | 31 | It provides internal caching of the `repo` object based on |
|
31 | 32 | the :term:`call context`. |
|
32 | 33 | """ |
|
34 | repo_type = None | |
|
33 | 35 | |
|
34 |
def __init__(self |
|
|
35 | self._cache = repo_cache | |
|
36 | def __init__(self): | |
|
37 | self._cache_region = region_meta.dogpile_cache_regions['repo_object'] | |
|
36 | 38 | |
|
37 | 39 | def _create_config(self, path, config): |
|
38 | 40 | config = {} |
@@ -48,26 +50,19 b' class RepoFactory(object):' | |||
|
48 | 50 | Uses internally the low level beaker API since the decorators introduce |
|
49 | 51 | significant overhead. |
|
50 | 52 | """ |
|
51 | def create_new_repo(): | |
|
53 | region = self._cache_region | |
|
54 | context = wire.get('context', None) | |
|
55 | repo_path = wire.get('path', '') | |
|
56 | context_uid = '{}'.format(context) | |
|
57 | cache = wire.get('cache', True) | |
|
58 | cache_on = context and cache | |
|
59 | ||
|
60 | @region.conditional_cache_on_arguments(condition=cache_on) | |
|
61 | def create_new_repo(_repo_type, _repo_path, _context_uid): | |
|
52 | 62 | return self._create_repo(wire, create) |
|
53 | 63 | |
|
54 | return self._repo(wire, create_new_repo) | |
|
55 | ||
|
56 | def _repo(self, wire, createfunc): | |
|
57 | context = wire.get('context', None) | |
|
58 | cache = wire.get('cache', True) | |
|
59 | ||
|
60 | if context and cache: | |
|
61 | cache_key = (context, wire['path']) | |
|
62 | log.debug( | |
|
63 | 'FETCH %s@%s repo object from cache. Context: %s', | |
|
64 | self.__class__.__name__, wire['path'], context) | |
|
65 | return self._cache.get(key=cache_key, createfunc=createfunc) | |
|
66 | else: | |
|
67 | log.debug( | |
|
68 | 'INIT %s@%s repo object based on wire %s. Context: %s', | |
|
69 | self.__class__.__name__, wire['path'], wire, context) | |
|
70 | return createfunc() | |
|
64 | repo = create_new_repo(self.repo_type, repo_path, context_uid) | |
|
65 | return repo | |
|
71 | 66 | |
|
72 | 67 | |
|
73 | 68 | def obfuscate_qs(query_string): |
@@ -87,6 +87,7 b' class Repo(DulwichRepo):' | |||
|
87 | 87 | |
|
88 | 88 | |
|
89 | 89 | class GitFactory(RepoFactory): |
|
90 | repo_type = 'git' | |
|
90 | 91 | |
|
91 | 92 | def _create_repo(self, wire, create): |
|
92 | 93 | repo_path = str_to_dulwich(wire['path']) |
@@ -93,6 +93,7 b' def reraise_safe_exceptions(func):' | |||
|
93 | 93 | |
|
94 | 94 | |
|
95 | 95 | class MercurialFactory(RepoFactory): |
|
96 | repo_type = 'hg' | |
|
96 | 97 | |
|
97 | 98 | def _create_config(self, config, hooks=True): |
|
98 | 99 | if not hooks: |
@@ -26,9 +26,8 b' from itertools import chain' | |||
|
26 | 26 | |
|
27 | 27 | import simplejson as json |
|
28 | 28 | import msgpack |
|
29 | from beaker.cache import CacheManager | |
|
30 | from beaker.util import parse_cache_config_options | |
|
31 | 29 | from pyramid.config import Configurator |
|
30 | from pyramid.settings import asbool, aslist | |
|
32 | 31 | from pyramid.wsgi import wsgiapp |
|
33 | 32 | from pyramid.compat import configparser |
|
34 | 33 | |
@@ -65,48 +64,60 b' def _is_request_chunked(environ):' | |||
|
65 | 64 | return stream |
|
66 | 65 | |
|
67 | 66 | |
|
67 | def _int_setting(settings, name, default): | |
|
68 | settings[name] = int(settings.get(name, default)) | |
|
69 | ||
|
70 | ||
|
71 | def _bool_setting(settings, name, default): | |
|
72 | input_val = settings.get(name, default) | |
|
73 | if isinstance(input_val, unicode): | |
|
74 | input_val = input_val.encode('utf8') | |
|
75 | settings[name] = asbool(input_val) | |
|
76 | ||
|
77 | ||
|
78 | def _list_setting(settings, name, default): | |
|
79 | raw_value = settings.get(name, default) | |
|
80 | ||
|
81 | # Otherwise we assume it uses pyramids space/newline separation. | |
|
82 | settings[name] = aslist(raw_value) | |
|
83 | ||
|
84 | ||
|
85 | def _string_setting(settings, name, default, lower=True): | |
|
86 | value = settings.get(name, default) | |
|
87 | if lower: | |
|
88 | value = value.lower() | |
|
89 | settings[name] = value | |
|
90 | ||
|
91 | ||
|
68 | 92 | class VCS(object): |
|
69 | 93 | def __init__(self, locale=None, cache_config=None): |
|
70 | 94 | self.locale = locale |
|
71 | 95 | self.cache_config = cache_config |
|
72 | 96 | self._configure_locale() |
|
73 | self._initialize_cache() | |
|
74 | 97 | |
|
75 | 98 | if GitFactory and GitRemote: |
|
76 | git_repo_cache = self.cache.get_cache_region( | |
|
77 | 'git', region='repo_object') | |
|
78 | git_factory = GitFactory(git_repo_cache) | |
|
99 | git_factory = GitFactory() | |
|
79 | 100 | self._git_remote = GitRemote(git_factory) |
|
80 | 101 | else: |
|
81 | 102 | log.info("Git client import failed") |
|
82 | 103 | |
|
83 | 104 | if MercurialFactory and HgRemote: |
|
84 | hg_repo_cache = self.cache.get_cache_region( | |
|
85 | 'hg', region='repo_object') | |
|
86 | hg_factory = MercurialFactory(hg_repo_cache) | |
|
105 | hg_factory = MercurialFactory() | |
|
87 | 106 | self._hg_remote = HgRemote(hg_factory) |
|
88 | 107 | else: |
|
89 | 108 | log.info("Mercurial client import failed") |
|
90 | 109 | |
|
91 | 110 | if SubversionFactory and SvnRemote: |
|
92 | svn_repo_cache = self.cache.get_cache_region( | |
|
93 | 'svn', region='repo_object') | |
|
94 | svn_factory = SubversionFactory(svn_repo_cache) | |
|
111 | svn_factory = SubversionFactory() | |
|
112 | ||
|
95 | 113 | # hg factory is used for svn url validation |
|
96 | hg_repo_cache = self.cache.get_cache_region( | |
|
97 | 'hg', region='repo_object') | |
|
98 | hg_factory = MercurialFactory(hg_repo_cache) | |
|
114 | hg_factory = MercurialFactory() | |
|
99 | 115 | self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory) |
|
100 | 116 | else: |
|
101 | 117 | log.info("Subversion client import failed") |
|
102 | 118 | |
|
103 | 119 | self._vcsserver = VcsServer() |
|
104 | 120 | |
|
105 | def _initialize_cache(self): | |
|
106 | cache_config = parse_cache_config_options(self.cache_config) | |
|
107 | log.info('Initializing beaker cache: %s' % cache_config) | |
|
108 | self.cache = CacheManager(**cache_config) | |
|
109 | ||
|
110 | 121 | def _configure_locale(self): |
|
111 | 122 | if self.locale: |
|
112 | 123 | log.info('Settings locale: `LC_ALL` to %s' % self.locale) |
@@ -169,8 +180,11 b' class HTTPApplication(object):' | |||
|
169 | 180 | _use_echo_app = False |
|
170 | 181 | |
|
171 | 182 | def __init__(self, settings=None, global_config=None): |
|
183 | self._sanitize_settings_and_apply_defaults(settings) | |
|
184 | ||
|
172 | 185 | self.config = Configurator(settings=settings) |
|
173 | 186 | self.global_config = global_config |
|
187 | self.config.include('vcsserver.lib.rc_cache') | |
|
174 | 188 | |
|
175 | 189 | locale = settings.get('locale', '') or 'en_US.UTF-8' |
|
176 | 190 | vcs = VCS(locale=locale, cache_config=settings) |
@@ -198,6 +212,21 b' class HTTPApplication(object):' | |||
|
198 | 212 | if binary_dir: |
|
199 | 213 | settings.BINARY_DIR = binary_dir |
|
200 | 214 | |
|
215 | def _sanitize_settings_and_apply_defaults(self, settings): | |
|
216 | # repo_object cache | |
|
217 | _string_setting( | |
|
218 | settings, | |
|
219 | 'rc_cache.repo_object.backend', | |
|
220 | 'dogpile.cache.rc.memory_lru') | |
|
221 | _int_setting( | |
|
222 | settings, | |
|
223 | 'rc_cache.repo_object.expiration_time', | |
|
224 | 300) | |
|
225 | _int_setting( | |
|
226 | settings, | |
|
227 | 'rc_cache.repo_object.max_size', | |
|
228 | 1024) | |
|
229 | ||
|
201 | 230 | def _configure(self): |
|
202 | 231 | self.config.add_renderer( |
|
203 | 232 | name='msgpack', |
@@ -246,14 +275,17 b' class HTTPApplication(object):' | |||
|
246 | 275 | wire = params.get('wire') |
|
247 | 276 | args = params.get('args') |
|
248 | 277 | kwargs = params.get('kwargs') |
|
278 | context_uid = None | |
|
279 | ||
|
249 | 280 | if wire: |
|
250 | 281 | try: |
|
251 | wire['context'] = uuid.UUID(wire['context']) | |
|
282 | wire['context'] = context_uid = uuid.UUID(wire['context']) | |
|
252 | 283 | except KeyError: |
|
253 | 284 | pass |
|
254 | 285 | args.insert(0, wire) |
|
255 | 286 | |
|
256 |
log.debug('method called:%s with kwargs:%s', |
|
|
287 | log.debug('method called:%s with kwargs:%s context_uid: %s', | |
|
288 | method, kwargs, context_uid) | |
|
257 | 289 | try: |
|
258 | 290 | resp = getattr(remote, method)(*args, **kwargs) |
|
259 | 291 | except Exception as e: |
@@ -272,7 +304,7 b' class HTTPApplication(object):' | |||
|
272 | 304 | } |
|
273 | 305 | } |
|
274 | 306 | try: |
|
275 |
resp['error']['_vcs_kind'] = e |
|
|
307 | resp['error']['_vcs_kind'] = getattr(e, '_vcs_kind', None) | |
|
276 | 308 | except AttributeError: |
|
277 | 309 | pass |
|
278 | 310 | else: |
@@ -486,5 +518,6 b' def main(global_config, **settings):' | |||
|
486 | 518 | if MercurialFactory: |
|
487 | 519 | hgpatches.patch_largefiles_capabilities() |
|
488 | 520 | hgpatches.patch_subrepo_type_mapping() |
|
521 | ||
|
489 | 522 | app = HTTPApplication(settings=settings, global_config=global_config) |
|
490 | 523 | return app.wsgi_app() |
@@ -40,13 +40,13 b' log = logging.getLogger(__name__)' | |||
|
40 | 40 | |
|
41 | 41 | # Set of svn compatible version flags. |
|
42 | 42 | # Compare with subversion/svnadmin/svnadmin.c |
|
43 |
svn_compatible_versions = |
|
|
43 | svn_compatible_versions = { | |
|
44 | 44 | 'pre-1.4-compatible', |
|
45 | 45 | 'pre-1.5-compatible', |
|
46 | 46 | 'pre-1.6-compatible', |
|
47 | 47 | 'pre-1.8-compatible', |
|
48 |
'pre-1.9-compatible' |
|
|
49 | ]) | |
|
48 | 'pre-1.9-compatible' | |
|
49 | } | |
|
50 | 50 | |
|
51 | 51 | svn_compatible_versions_map = { |
|
52 | 52 | 'pre-1.4-compatible': '1.3', |
@@ -71,6 +71,7 b' def reraise_safe_exceptions(func):' | |||
|
71 | 71 | |
|
72 | 72 | |
|
73 | 73 | class SubversionFactory(RepoFactory): |
|
74 | repo_type = 'svn' | |
|
74 | 75 | |
|
75 | 76 | def _create_repo(self, wire, create, compatible_version): |
|
76 | 77 | path = svn.core.svn_path_canonicalize(wire['path']) |
@@ -92,10 +93,25 b' class SubversionFactory(RepoFactory):' | |||
|
92 | 93 | return repo |
|
93 | 94 | |
|
94 | 95 | def repo(self, wire, create=False, compatible_version=None): |
|
95 | def create_new_repo(): | |
|
96 | """ | |
|
97 | Get a repository instance for the given path. | |
|
98 | ||
|
99 | Uses internally the low level beaker API since the decorators introduce | |
|
100 | significant overhead. | |
|
101 | """ | |
|
102 | region = self._cache_region | |
|
103 | context = wire.get('context', None) | |
|
104 | repo_path = wire.get('path', '') | |
|
105 | context_uid = '{}'.format(context) | |
|
106 | cache = wire.get('cache', True) | |
|
107 | cache_on = context and cache | |
|
108 | ||
|
109 | @region.conditional_cache_on_arguments(condition=cache_on) | |
|
110 | def create_new_repo(_repo_type, _repo_path, _context_uid, compatible_version_id): | |
|
96 | 111 | return self._create_repo(wire, create, compatible_version) |
|
97 | 112 | |
|
98 | return self._repo(wire, create_new_repo) | |
|
113 | return create_new_repo(self.repo_type, repo_path, context_uid, | |
|
114 | compatible_version) | |
|
99 | 115 | |
|
100 | 116 | |
|
101 | 117 | NODE_TYPE_MAPPING = { |
@@ -40,7 +40,7 b' def repeat(request):' | |||
|
40 | 40 | @pytest.fixture(scope='session') |
|
41 | 41 | def vcsserver_port(request): |
|
42 | 42 | port = get_available_port() |
|
43 |
print |
|
|
43 | print('Using vcsserver port %s' % (port, )) | |
|
44 | 44 | return port |
|
45 | 45 | |
|
46 | 46 | |
@@ -55,4 +55,3 b' def get_available_port():' | |||
|
55 | 55 | mysocket.close() |
|
56 | 56 | del mysocket |
|
57 | 57 | return port |
|
58 |
@@ -152,11 +152,14 b' class TestDulwichRepoWrapper(object):' | |||
|
152 | 152 | |
|
153 | 153 | class TestGitFactory(object): |
|
154 | 154 | def test_create_repo_returns_dulwich_wrapper(self): |
|
155 | factory = git.GitFactory(repo_cache=Mock()) | |
|
156 | wire = { | |
|
157 | 'path': '/tmp/abcde' | |
|
158 | } | |
|
159 | isdir_patcher = patch('dulwich.repo.os.path.isdir', return_value=True) | |
|
160 | with isdir_patcher: | |
|
161 | result = factory._create_repo(wire, True) | |
|
162 | assert isinstance(result, git.Repo) | |
|
155 | ||
|
156 | with patch('vcsserver.lib.rc_cache.region_meta.dogpile_cache_regions') as mock: | |
|
157 | mock.side_effect = {'repo_objects': ''} | |
|
158 | factory = git.GitFactory() | |
|
159 | wire = { | |
|
160 | 'path': '/tmp/abcde' | |
|
161 | } | |
|
162 | isdir_patcher = patch('dulwich.repo.os.path.isdir', return_value=True) | |
|
163 | with isdir_patcher: | |
|
164 | result = factory._create_repo(wire, True) | |
|
165 | assert isinstance(result, git.Repo) |
@@ -12,11 +12,6 b' from vcsserver.http_main import main' | |||
|
12 | 12 | def vcs_app(): |
|
13 | 13 | stub_settings = { |
|
14 | 14 | 'dev.use_echo_app': 'true', |
|
15 | 'beaker.cache.regions': 'repo_object', | |
|
16 | 'beaker.cache.repo_object.type': 'memorylru', | |
|
17 | 'beaker.cache.repo_object.max_items': '100', | |
|
18 | 'beaker.cache.repo_object.expire': '300', | |
|
19 | 'beaker.cache.repo_object.enabled': 'true', | |
|
20 | 15 | 'locale': 'en_US.UTF-8', |
|
21 | 16 | } |
|
22 | 17 | vcs_app = main({}, **stub_settings) |
@@ -15,6 +15,7 b'' | |||
|
15 | 15 | # along with this program; if not, write to the Free Software Foundation, |
|
16 | 16 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
17 | 17 | import logging |
|
18 | import hashlib | |
|
18 | 19 | |
|
19 | 20 | log = logging.getLogger(__name__) |
|
20 | 21 | |
@@ -80,3 +81,9 b' class AttributeDict(dict):' | |||
|
80 | 81 | return self.get(attr, None) |
|
81 | 82 | __setattr__ = dict.__setitem__ |
|
82 | 83 | __delattr__ = dict.__delitem__ |
|
84 | ||
|
85 | ||
|
86 | def sha1(val): | |
|
87 | return hashlib.sha1(val).hexdigest() | |
|
88 | ||
|
89 |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now