Show More
@@ -1,360 +1,379 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | rhodecode.lib.compat |
|
3 | rhodecode.lib.compat | |
4 | ~~~~~~~~~~~~~~~~~~~~ |
|
4 | ~~~~~~~~~~~~~~~~~~~~ | |
5 |
|
5 | |||
6 | Python backward compatibility functions and common libs |
|
6 | Python backward compatibility functions and common libs | |
7 |
|
7 | |||
8 |
|
8 | |||
9 | :created_on: Oct 7, 2011 |
|
9 | :created_on: Oct 7, 2011 | |
10 | :author: marcink |
|
10 | :author: marcink | |
11 | :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> |
|
11 | :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> | |
12 | :license: GPLv3, see COPYING for more details. |
|
12 | :license: GPLv3, see COPYING for more details. | |
13 | """ |
|
13 | """ | |
14 | # This program is free software: you can redistribute it and/or modify |
|
14 | # This program is free software: you can redistribute it and/or modify | |
15 | # it under the terms of the GNU General Public License as published by |
|
15 | # it under the terms of the GNU General Public License as published by | |
16 | # the Free Software Foundation, either version 3 of the License, or |
|
16 | # the Free Software Foundation, either version 3 of the License, or | |
17 | # (at your option) any later version. |
|
17 | # (at your option) any later version. | |
18 | # |
|
18 | # | |
19 | # This program is distributed in the hope that it will be useful, |
|
19 | # This program is distributed in the hope that it will be useful, | |
20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | # GNU General Public License for more details. |
|
22 | # GNU General Public License for more details. | |
23 | # |
|
23 | # | |
24 | # You should have received a copy of the GNU General Public License |
|
24 | # You should have received a copy of the GNU General Public License | |
25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
26 |
|
26 | |||
|
27 | import os | |||
|
28 | from rhodecode import __platform__, PLATFORM_WIN | |||
|
29 | ||||
27 | #============================================================================== |
|
30 | #============================================================================== | |
28 | # json |
|
31 | # json | |
29 | #============================================================================== |
|
32 | #============================================================================== | |
30 | try: |
|
33 | try: | |
31 | import json |
|
34 | import json | |
32 | except ImportError: |
|
35 | except ImportError: | |
33 | import simplejson as json |
|
36 | import simplejson as json | |
34 |
|
37 | |||
35 |
|
38 | |||
36 | #============================================================================== |
|
39 | #============================================================================== | |
37 | # izip_longest |
|
40 | # izip_longest | |
38 | #============================================================================== |
|
41 | #============================================================================== | |
39 | try: |
|
42 | try: | |
40 | from itertools import izip_longest |
|
43 | from itertools import izip_longest | |
41 | except ImportError: |
|
44 | except ImportError: | |
42 | import itertools |
|
45 | import itertools | |
43 |
|
46 | |||
44 | def izip_longest(*args, **kwds): # noqa |
|
47 | def izip_longest(*args, **kwds): # noqa | |
45 | fillvalue = kwds.get("fillvalue") |
|
48 | fillvalue = kwds.get("fillvalue") | |
46 |
|
49 | |||
47 | def sentinel(counter=([fillvalue] * (len(args) - 1)).pop): |
|
50 | def sentinel(counter=([fillvalue] * (len(args) - 1)).pop): | |
48 | yield counter() # yields the fillvalue, or raises IndexError |
|
51 | yield counter() # yields the fillvalue, or raises IndexError | |
49 |
|
52 | |||
50 | fillers = itertools.repeat(fillvalue) |
|
53 | fillers = itertools.repeat(fillvalue) | |
51 | iters = [itertools.chain(it, sentinel(), fillers) |
|
54 | iters = [itertools.chain(it, sentinel(), fillers) | |
52 | for it in args] |
|
55 | for it in args] | |
53 | try: |
|
56 | try: | |
54 | for tup in itertools.izip(*iters): |
|
57 | for tup in itertools.izip(*iters): | |
55 | yield tup |
|
58 | yield tup | |
56 | except IndexError: |
|
59 | except IndexError: | |
57 | pass |
|
60 | pass | |
58 |
|
61 | |||
59 |
|
62 | |||
60 | #============================================================================== |
|
63 | #============================================================================== | |
61 | # OrderedDict |
|
64 | # OrderedDict | |
62 | #============================================================================== |
|
65 | #============================================================================== | |
63 |
|
66 | |||
64 | # Python Software Foundation License |
|
67 | # Python Software Foundation License | |
65 |
|
68 | |||
66 | # XXX: it feels like using the class with "is" and "is not" instead of "==" and |
|
69 | # XXX: it feels like using the class with "is" and "is not" instead of "==" and | |
67 | # "!=" should be faster. |
|
70 | # "!=" should be faster. | |
68 | class _Nil(object): |
|
71 | class _Nil(object): | |
69 |
|
72 | |||
70 | def __repr__(self): |
|
73 | def __repr__(self): | |
71 | return "nil" |
|
74 | return "nil" | |
72 |
|
75 | |||
73 | def __eq__(self, other): |
|
76 | def __eq__(self, other): | |
74 | if (isinstance(other, _Nil)): |
|
77 | if (isinstance(other, _Nil)): | |
75 | return True |
|
78 | return True | |
76 | else: |
|
79 | else: | |
77 | return NotImplemented |
|
80 | return NotImplemented | |
78 |
|
81 | |||
79 | def __ne__(self, other): |
|
82 | def __ne__(self, other): | |
80 | if (isinstance(other, _Nil)): |
|
83 | if (isinstance(other, _Nil)): | |
81 | return False |
|
84 | return False | |
82 | else: |
|
85 | else: | |
83 | return NotImplemented |
|
86 | return NotImplemented | |
84 |
|
87 | |||
85 | _nil = _Nil() |
|
88 | _nil = _Nil() | |
86 |
|
89 | |||
87 | class _odict(object): |
|
90 | class _odict(object): | |
88 | """Ordered dict data structure, with O(1) complexity for dict operations |
|
91 | """Ordered dict data structure, with O(1) complexity for dict operations | |
89 | that modify one element. |
|
92 | that modify one element. | |
90 |
|
93 | |||
91 | Overwriting values doesn't change their original sequential order. |
|
94 | Overwriting values doesn't change their original sequential order. | |
92 | """ |
|
95 | """ | |
93 |
|
96 | |||
94 | def _dict_impl(self): |
|
97 | def _dict_impl(self): | |
95 | return None |
|
98 | return None | |
96 |
|
99 | |||
97 | def __init__(self, data=(), **kwds): |
|
100 | def __init__(self, data=(), **kwds): | |
98 | """This doesn't accept keyword initialization as normal dicts to avoid |
|
101 | """This doesn't accept keyword initialization as normal dicts to avoid | |
99 | a trap - inside a function or method the keyword args are accessible |
|
102 | a trap - inside a function or method the keyword args are accessible | |
100 | only as a dict, without a defined order, so their original order is |
|
103 | only as a dict, without a defined order, so their original order is | |
101 | lost. |
|
104 | lost. | |
102 | """ |
|
105 | """ | |
103 | if kwds: |
|
106 | if kwds: | |
104 | raise TypeError("__init__() of ordered dict takes no keyword " |
|
107 | raise TypeError("__init__() of ordered dict takes no keyword " | |
105 | "arguments to avoid an ordering trap.") |
|
108 | "arguments to avoid an ordering trap.") | |
106 | self._dict_impl().__init__(self) |
|
109 | self._dict_impl().__init__(self) | |
107 | # If you give a normal dict, then the order of elements is undefined |
|
110 | # If you give a normal dict, then the order of elements is undefined | |
108 | if hasattr(data, "iteritems"): |
|
111 | if hasattr(data, "iteritems"): | |
109 | for key, val in data.iteritems(): |
|
112 | for key, val in data.iteritems(): | |
110 | self[key] = val |
|
113 | self[key] = val | |
111 | else: |
|
114 | else: | |
112 | for key, val in data: |
|
115 | for key, val in data: | |
113 | self[key] = val |
|
116 | self[key] = val | |
114 |
|
117 | |||
115 | # Double-linked list header |
|
118 | # Double-linked list header | |
116 | def _get_lh(self): |
|
119 | def _get_lh(self): | |
117 | dict_impl = self._dict_impl() |
|
120 | dict_impl = self._dict_impl() | |
118 | if not hasattr(self, '_lh'): |
|
121 | if not hasattr(self, '_lh'): | |
119 | dict_impl.__setattr__(self, '_lh', _nil) |
|
122 | dict_impl.__setattr__(self, '_lh', _nil) | |
120 | return dict_impl.__getattribute__(self, '_lh') |
|
123 | return dict_impl.__getattribute__(self, '_lh') | |
121 |
|
124 | |||
122 | def _set_lh(self, val): |
|
125 | def _set_lh(self, val): | |
123 | self._dict_impl().__setattr__(self, '_lh', val) |
|
126 | self._dict_impl().__setattr__(self, '_lh', val) | |
124 |
|
127 | |||
125 | lh = property(_get_lh, _set_lh) |
|
128 | lh = property(_get_lh, _set_lh) | |
126 |
|
129 | |||
127 | # Double-linked list tail |
|
130 | # Double-linked list tail | |
128 | def _get_lt(self): |
|
131 | def _get_lt(self): | |
129 | dict_impl = self._dict_impl() |
|
132 | dict_impl = self._dict_impl() | |
130 | if not hasattr(self, '_lt'): |
|
133 | if not hasattr(self, '_lt'): | |
131 | dict_impl.__setattr__(self, '_lt', _nil) |
|
134 | dict_impl.__setattr__(self, '_lt', _nil) | |
132 | return dict_impl.__getattribute__(self, '_lt') |
|
135 | return dict_impl.__getattribute__(self, '_lt') | |
133 |
|
136 | |||
134 | def _set_lt(self, val): |
|
137 | def _set_lt(self, val): | |
135 | self._dict_impl().__setattr__(self, '_lt', val) |
|
138 | self._dict_impl().__setattr__(self, '_lt', val) | |
136 |
|
139 | |||
137 | lt = property(_get_lt, _set_lt) |
|
140 | lt = property(_get_lt, _set_lt) | |
138 |
|
141 | |||
139 | def __getitem__(self, key): |
|
142 | def __getitem__(self, key): | |
140 | return self._dict_impl().__getitem__(self, key)[1] |
|
143 | return self._dict_impl().__getitem__(self, key)[1] | |
141 |
|
144 | |||
142 | def __setitem__(self, key, val): |
|
145 | def __setitem__(self, key, val): | |
143 | dict_impl = self._dict_impl() |
|
146 | dict_impl = self._dict_impl() | |
144 | try: |
|
147 | try: | |
145 | dict_impl.__getitem__(self, key)[1] = val |
|
148 | dict_impl.__getitem__(self, key)[1] = val | |
146 | except KeyError, e: |
|
149 | except KeyError, e: | |
147 | new = [dict_impl.__getattribute__(self, 'lt'), val, _nil] |
|
150 | new = [dict_impl.__getattribute__(self, 'lt'), val, _nil] | |
148 | dict_impl.__setitem__(self, key, new) |
|
151 | dict_impl.__setitem__(self, key, new) | |
149 | if dict_impl.__getattribute__(self, 'lt') == _nil: |
|
152 | if dict_impl.__getattribute__(self, 'lt') == _nil: | |
150 | dict_impl.__setattr__(self, 'lh', key) |
|
153 | dict_impl.__setattr__(self, 'lh', key) | |
151 | else: |
|
154 | else: | |
152 | dict_impl.__getitem__( |
|
155 | dict_impl.__getitem__( | |
153 | self, dict_impl.__getattribute__(self, 'lt'))[2] = key |
|
156 | self, dict_impl.__getattribute__(self, 'lt'))[2] = key | |
154 | dict_impl.__setattr__(self, 'lt', key) |
|
157 | dict_impl.__setattr__(self, 'lt', key) | |
155 |
|
158 | |||
156 | def __delitem__(self, key): |
|
159 | def __delitem__(self, key): | |
157 | dict_impl = self._dict_impl() |
|
160 | dict_impl = self._dict_impl() | |
158 | pred, _ , succ = self._dict_impl().__getitem__(self, key) |
|
161 | pred, _ , succ = self._dict_impl().__getitem__(self, key) | |
159 | if pred == _nil: |
|
162 | if pred == _nil: | |
160 | dict_impl.__setattr__(self, 'lh', succ) |
|
163 | dict_impl.__setattr__(self, 'lh', succ) | |
161 | else: |
|
164 | else: | |
162 | dict_impl.__getitem__(self, pred)[2] = succ |
|
165 | dict_impl.__getitem__(self, pred)[2] = succ | |
163 | if succ == _nil: |
|
166 | if succ == _nil: | |
164 | dict_impl.__setattr__(self, 'lt', pred) |
|
167 | dict_impl.__setattr__(self, 'lt', pred) | |
165 | else: |
|
168 | else: | |
166 | dict_impl.__getitem__(self, succ)[0] = pred |
|
169 | dict_impl.__getitem__(self, succ)[0] = pred | |
167 | dict_impl.__delitem__(self, key) |
|
170 | dict_impl.__delitem__(self, key) | |
168 |
|
171 | |||
169 | def __contains__(self, key): |
|
172 | def __contains__(self, key): | |
170 | return key in self.keys() |
|
173 | return key in self.keys() | |
171 |
|
174 | |||
172 | def __len__(self): |
|
175 | def __len__(self): | |
173 | return len(self.keys()) |
|
176 | return len(self.keys()) | |
174 |
|
177 | |||
175 | def __str__(self): |
|
178 | def __str__(self): | |
176 | pairs = ("%r: %r" % (k, v) for k, v in self.iteritems()) |
|
179 | pairs = ("%r: %r" % (k, v) for k, v in self.iteritems()) | |
177 | return "{%s}" % ", ".join(pairs) |
|
180 | return "{%s}" % ", ".join(pairs) | |
178 |
|
181 | |||
179 | def __repr__(self): |
|
182 | def __repr__(self): | |
180 | if self: |
|
183 | if self: | |
181 | pairs = ("(%r, %r)" % (k, v) for k, v in self.iteritems()) |
|
184 | pairs = ("(%r, %r)" % (k, v) for k, v in self.iteritems()) | |
182 | return "odict([%s])" % ", ".join(pairs) |
|
185 | return "odict([%s])" % ", ".join(pairs) | |
183 | else: |
|
186 | else: | |
184 | return "odict()" |
|
187 | return "odict()" | |
185 |
|
188 | |||
186 | def get(self, k, x=None): |
|
189 | def get(self, k, x=None): | |
187 | if k in self: |
|
190 | if k in self: | |
188 | return self._dict_impl().__getitem__(self, k)[1] |
|
191 | return self._dict_impl().__getitem__(self, k)[1] | |
189 | else: |
|
192 | else: | |
190 | return x |
|
193 | return x | |
191 |
|
194 | |||
192 | def __iter__(self): |
|
195 | def __iter__(self): | |
193 | dict_impl = self._dict_impl() |
|
196 | dict_impl = self._dict_impl() | |
194 | curr_key = dict_impl.__getattribute__(self, 'lh') |
|
197 | curr_key = dict_impl.__getattribute__(self, 'lh') | |
195 | while curr_key != _nil: |
|
198 | while curr_key != _nil: | |
196 | yield curr_key |
|
199 | yield curr_key | |
197 | curr_key = dict_impl.__getitem__(self, curr_key)[2] |
|
200 | curr_key = dict_impl.__getitem__(self, curr_key)[2] | |
198 |
|
201 | |||
199 | iterkeys = __iter__ |
|
202 | iterkeys = __iter__ | |
200 |
|
203 | |||
201 | def keys(self): |
|
204 | def keys(self): | |
202 | return list(self.iterkeys()) |
|
205 | return list(self.iterkeys()) | |
203 |
|
206 | |||
204 | def itervalues(self): |
|
207 | def itervalues(self): | |
205 | dict_impl = self._dict_impl() |
|
208 | dict_impl = self._dict_impl() | |
206 | curr_key = dict_impl.__getattribute__(self, 'lh') |
|
209 | curr_key = dict_impl.__getattribute__(self, 'lh') | |
207 | while curr_key != _nil: |
|
210 | while curr_key != _nil: | |
208 | _, val, curr_key = dict_impl.__getitem__(self, curr_key) |
|
211 | _, val, curr_key = dict_impl.__getitem__(self, curr_key) | |
209 | yield val |
|
212 | yield val | |
210 |
|
213 | |||
211 | def values(self): |
|
214 | def values(self): | |
212 | return list(self.itervalues()) |
|
215 | return list(self.itervalues()) | |
213 |
|
216 | |||
214 | def iteritems(self): |
|
217 | def iteritems(self): | |
215 | dict_impl = self._dict_impl() |
|
218 | dict_impl = self._dict_impl() | |
216 | curr_key = dict_impl.__getattribute__(self, 'lh') |
|
219 | curr_key = dict_impl.__getattribute__(self, 'lh') | |
217 | while curr_key != _nil: |
|
220 | while curr_key != _nil: | |
218 | _, val, next_key = dict_impl.__getitem__(self, curr_key) |
|
221 | _, val, next_key = dict_impl.__getitem__(self, curr_key) | |
219 | yield curr_key, val |
|
222 | yield curr_key, val | |
220 | curr_key = next_key |
|
223 | curr_key = next_key | |
221 |
|
224 | |||
222 | def items(self): |
|
225 | def items(self): | |
223 | return list(self.iteritems()) |
|
226 | return list(self.iteritems()) | |
224 |
|
227 | |||
225 | def sort(self, cmp=None, key=None, reverse=False): |
|
228 | def sort(self, cmp=None, key=None, reverse=False): | |
226 | items = [(k, v) for k, v in self.items()] |
|
229 | items = [(k, v) for k, v in self.items()] | |
227 | if cmp is not None: |
|
230 | if cmp is not None: | |
228 | items = sorted(items, cmp=cmp) |
|
231 | items = sorted(items, cmp=cmp) | |
229 | elif key is not None: |
|
232 | elif key is not None: | |
230 | items = sorted(items, key=key) |
|
233 | items = sorted(items, key=key) | |
231 | else: |
|
234 | else: | |
232 | items = sorted(items, key=lambda x: x[1]) |
|
235 | items = sorted(items, key=lambda x: x[1]) | |
233 | if reverse: |
|
236 | if reverse: | |
234 | items.reverse() |
|
237 | items.reverse() | |
235 | self.clear() |
|
238 | self.clear() | |
236 | self.__init__(items) |
|
239 | self.__init__(items) | |
237 |
|
240 | |||
238 | def clear(self): |
|
241 | def clear(self): | |
239 | dict_impl = self._dict_impl() |
|
242 | dict_impl = self._dict_impl() | |
240 | dict_impl.clear(self) |
|
243 | dict_impl.clear(self) | |
241 | dict_impl.__setattr__(self, 'lh', _nil) |
|
244 | dict_impl.__setattr__(self, 'lh', _nil) | |
242 | dict_impl.__setattr__(self, 'lt', _nil) |
|
245 | dict_impl.__setattr__(self, 'lt', _nil) | |
243 |
|
246 | |||
244 | def copy(self): |
|
247 | def copy(self): | |
245 | return self.__class__(self) |
|
248 | return self.__class__(self) | |
246 |
|
249 | |||
247 | def update(self, data=(), **kwds): |
|
250 | def update(self, data=(), **kwds): | |
248 | if kwds: |
|
251 | if kwds: | |
249 | raise TypeError("update() of ordered dict takes no keyword " |
|
252 | raise TypeError("update() of ordered dict takes no keyword " | |
250 | "arguments to avoid an ordering trap.") |
|
253 | "arguments to avoid an ordering trap.") | |
251 | if hasattr(data, "iteritems"): |
|
254 | if hasattr(data, "iteritems"): | |
252 | data = data.iteritems() |
|
255 | data = data.iteritems() | |
253 | for key, val in data: |
|
256 | for key, val in data: | |
254 | self[key] = val |
|
257 | self[key] = val | |
255 |
|
258 | |||
256 | def setdefault(self, k, x=None): |
|
259 | def setdefault(self, k, x=None): | |
257 | try: |
|
260 | try: | |
258 | return self[k] |
|
261 | return self[k] | |
259 | except KeyError: |
|
262 | except KeyError: | |
260 | self[k] = x |
|
263 | self[k] = x | |
261 | return x |
|
264 | return x | |
262 |
|
265 | |||
263 | def pop(self, k, x=_nil): |
|
266 | def pop(self, k, x=_nil): | |
264 | try: |
|
267 | try: | |
265 | val = self[k] |
|
268 | val = self[k] | |
266 | del self[k] |
|
269 | del self[k] | |
267 | return val |
|
270 | return val | |
268 | except KeyError: |
|
271 | except KeyError: | |
269 | if x == _nil: |
|
272 | if x == _nil: | |
270 | raise |
|
273 | raise | |
271 | return x |
|
274 | return x | |
272 |
|
275 | |||
273 | def popitem(self): |
|
276 | def popitem(self): | |
274 | try: |
|
277 | try: | |
275 | dict_impl = self._dict_impl() |
|
278 | dict_impl = self._dict_impl() | |
276 | key = dict_impl.__getattribute__(self, 'lt') |
|
279 | key = dict_impl.__getattribute__(self, 'lt') | |
277 | return key, self.pop(key) |
|
280 | return key, self.pop(key) | |
278 | except KeyError: |
|
281 | except KeyError: | |
279 | raise KeyError("'popitem(): ordered dictionary is empty'") |
|
282 | raise KeyError("'popitem(): ordered dictionary is empty'") | |
280 |
|
283 | |||
281 | def riterkeys(self): |
|
284 | def riterkeys(self): | |
282 | """To iterate on keys in reversed order. |
|
285 | """To iterate on keys in reversed order. | |
283 | """ |
|
286 | """ | |
284 | dict_impl = self._dict_impl() |
|
287 | dict_impl = self._dict_impl() | |
285 | curr_key = dict_impl.__getattribute__(self, 'lt') |
|
288 | curr_key = dict_impl.__getattribute__(self, 'lt') | |
286 | while curr_key != _nil: |
|
289 | while curr_key != _nil: | |
287 | yield curr_key |
|
290 | yield curr_key | |
288 | curr_key = dict_impl.__getitem__(self, curr_key)[0] |
|
291 | curr_key = dict_impl.__getitem__(self, curr_key)[0] | |
289 |
|
292 | |||
290 | __reversed__ = riterkeys |
|
293 | __reversed__ = riterkeys | |
291 |
|
294 | |||
292 | def rkeys(self): |
|
295 | def rkeys(self): | |
293 | """List of the keys in reversed order. |
|
296 | """List of the keys in reversed order. | |
294 | """ |
|
297 | """ | |
295 | return list(self.riterkeys()) |
|
298 | return list(self.riterkeys()) | |
296 |
|
299 | |||
297 | def ritervalues(self): |
|
300 | def ritervalues(self): | |
298 | """To iterate on values in reversed order. |
|
301 | """To iterate on values in reversed order. | |
299 | """ |
|
302 | """ | |
300 | dict_impl = self._dict_impl() |
|
303 | dict_impl = self._dict_impl() | |
301 | curr_key = dict_impl.__getattribute__(self, 'lt') |
|
304 | curr_key = dict_impl.__getattribute__(self, 'lt') | |
302 | while curr_key != _nil: |
|
305 | while curr_key != _nil: | |
303 | curr_key, val, _ = dict_impl.__getitem__(self, curr_key) |
|
306 | curr_key, val, _ = dict_impl.__getitem__(self, curr_key) | |
304 | yield val |
|
307 | yield val | |
305 |
|
308 | |||
306 | def rvalues(self): |
|
309 | def rvalues(self): | |
307 | """List of the values in reversed order. |
|
310 | """List of the values in reversed order. | |
308 | """ |
|
311 | """ | |
309 | return list(self.ritervalues()) |
|
312 | return list(self.ritervalues()) | |
310 |
|
313 | |||
311 | def riteritems(self): |
|
314 | def riteritems(self): | |
312 | """To iterate on (key, value) in reversed order. |
|
315 | """To iterate on (key, value) in reversed order. | |
313 | """ |
|
316 | """ | |
314 | dict_impl = self._dict_impl() |
|
317 | dict_impl = self._dict_impl() | |
315 | curr_key = dict_impl.__getattribute__(self, 'lt') |
|
318 | curr_key = dict_impl.__getattribute__(self, 'lt') | |
316 | while curr_key != _nil: |
|
319 | while curr_key != _nil: | |
317 | pred_key, val, _ = dict_impl.__getitem__(self, curr_key) |
|
320 | pred_key, val, _ = dict_impl.__getitem__(self, curr_key) | |
318 | yield curr_key, val |
|
321 | yield curr_key, val | |
319 | curr_key = pred_key |
|
322 | curr_key = pred_key | |
320 |
|
323 | |||
321 | def ritems(self): |
|
324 | def ritems(self): | |
322 | """List of the (key, value) in reversed order. |
|
325 | """List of the (key, value) in reversed order. | |
323 | """ |
|
326 | """ | |
324 | return list(self.riteritems()) |
|
327 | return list(self.riteritems()) | |
325 |
|
328 | |||
326 | def firstkey(self): |
|
329 | def firstkey(self): | |
327 | if self: |
|
330 | if self: | |
328 | return self._dict_impl().__getattribute__(self, 'lh') |
|
331 | return self._dict_impl().__getattribute__(self, 'lh') | |
329 | else: |
|
332 | else: | |
330 | raise KeyError("'firstkey(): ordered dictionary is empty'") |
|
333 | raise KeyError("'firstkey(): ordered dictionary is empty'") | |
331 |
|
334 | |||
332 | def lastkey(self): |
|
335 | def lastkey(self): | |
333 | if self: |
|
336 | if self: | |
334 | return self._dict_impl().__getattribute__(self, 'lt') |
|
337 | return self._dict_impl().__getattribute__(self, 'lt') | |
335 | else: |
|
338 | else: | |
336 | raise KeyError("'lastkey(): ordered dictionary is empty'") |
|
339 | raise KeyError("'lastkey(): ordered dictionary is empty'") | |
337 |
|
340 | |||
338 | def as_dict(self): |
|
341 | def as_dict(self): | |
339 | return self._dict_impl()(self.items()) |
|
342 | return self._dict_impl()(self.items()) | |
340 |
|
343 | |||
341 | def _repr(self): |
|
344 | def _repr(self): | |
342 | """_repr(): low level repr of the whole data contained in the odict. |
|
345 | """_repr(): low level repr of the whole data contained in the odict. | |
343 | Useful for debugging. |
|
346 | Useful for debugging. | |
344 | """ |
|
347 | """ | |
345 | dict_impl = self._dict_impl() |
|
348 | dict_impl = self._dict_impl() | |
346 | form = "odict low level repr lh,lt,data: %r, %r, %s" |
|
349 | form = "odict low level repr lh,lt,data: %r, %r, %s" | |
347 | return form % (dict_impl.__getattribute__(self, 'lh'), |
|
350 | return form % (dict_impl.__getattribute__(self, 'lh'), | |
348 | dict_impl.__getattribute__(self, 'lt'), |
|
351 | dict_impl.__getattribute__(self, 'lt'), | |
349 | dict_impl.__repr__(self)) |
|
352 | dict_impl.__repr__(self)) | |
350 |
|
353 | |||
351 | class OrderedDict(_odict, dict): |
|
354 | class OrderedDict(_odict, dict): | |
352 |
|
355 | |||
353 | def _dict_impl(self): |
|
356 | def _dict_impl(self): | |
354 | return dict |
|
357 | return dict | |
355 |
|
358 | |||
356 |
|
359 | |||
357 | #============================================================================== |
|
360 | #============================================================================== | |
358 | # OrderedSet |
|
361 | # OrderedSet | |
359 | #============================================================================== |
|
362 | #============================================================================== | |
360 | from sqlalchemy.util import OrderedSet |
|
363 | from sqlalchemy.util import OrderedSet | |
|
364 | ||||
|
365 | ||||
|
366 | #============================================================================== | |||
|
367 | # kill FUNCTIONS | |||
|
368 | #============================================================================== | |||
|
369 | if __platform__ in PLATFORM_WIN: | |||
|
370 | import ctypes | |||
|
371 | ||||
|
372 | def kill(pid, sig): | |||
|
373 | """kill function for Win32""" | |||
|
374 | kernel32 = ctypes.windll.kernel32 | |||
|
375 | handle = kernel32.OpenProcess(1, 0, pid) | |||
|
376 | return (0 != kernel32.TerminateProcess(handle, 0)) | |||
|
377 | ||||
|
378 | else: | |||
|
379 | kill = os.kill |
@@ -1,142 +1,129 b'' | |||||
1 | import os |
|
1 | import os | |
2 | import sys |
|
2 | import sys | |
3 | import time |
|
3 | import time | |
4 | import errno |
|
4 | import errno | |
5 |
|
5 | |||
6 | from warnings import warn |
|
6 | from warnings import warn | |
7 | from multiprocessing.util import Finalize |
|
7 | from multiprocessing.util import Finalize | |
8 |
|
8 | |||
9 | from rhodecode import __platform__, PLATFORM_WIN |
|
9 | from rhodecode.lib.compat import kill | |
10 |
|
||||
11 | if __platform__ in PLATFORM_WIN: |
|
|||
12 | import ctypes |
|
|||
13 |
|
||||
14 | def kill(pid, sig): |
|
|||
15 | """kill function for Win32""" |
|
|||
16 | kernel32 = ctypes.windll.kernel32 |
|
|||
17 | handle = kernel32.OpenProcess(1, 0, pid) |
|
|||
18 | return (0 != kernel32.TerminateProcess(handle, 0)) |
|
|||
19 |
|
||||
20 | else: |
|
|||
21 | kill = os.kill |
|
|||
22 |
|
||||
23 |
|
10 | |||
24 | class LockHeld(Exception): |
|
11 | class LockHeld(Exception): | |
25 | pass |
|
12 | pass | |
26 |
|
13 | |||
27 |
|
14 | |||
28 | class DaemonLock(object): |
|
15 | class DaemonLock(object): | |
29 | """daemon locking |
|
16 | """daemon locking | |
30 | USAGE: |
|
17 | USAGE: | |
31 | try: |
|
18 | try: | |
32 | l = DaemonLock(file_='/path/tolockfile',desc='test lock') |
|
19 | l = DaemonLock(file_='/path/tolockfile',desc='test lock') | |
33 | main() |
|
20 | main() | |
34 | l.release() |
|
21 | l.release() | |
35 | except LockHeld: |
|
22 | except LockHeld: | |
36 | sys.exit(1) |
|
23 | sys.exit(1) | |
37 | """ |
|
24 | """ | |
38 |
|
25 | |||
39 | def __init__(self, file_=None, callbackfn=None, |
|
26 | def __init__(self, file_=None, callbackfn=None, | |
40 | desc='daemon lock', debug=False): |
|
27 | desc='daemon lock', debug=False): | |
41 |
|
28 | |||
42 | self.pidfile = file_ if file_ else os.path.join( |
|
29 | self.pidfile = file_ if file_ else os.path.join( | |
43 | os.path.dirname(__file__), |
|
30 | os.path.dirname(__file__), | |
44 | 'running.lock') |
|
31 | 'running.lock') | |
45 | self.callbackfn = callbackfn |
|
32 | self.callbackfn = callbackfn | |
46 | self.desc = desc |
|
33 | self.desc = desc | |
47 | self.debug = debug |
|
34 | self.debug = debug | |
48 | self.held = False |
|
35 | self.held = False | |
49 | #run the lock automatically ! |
|
36 | #run the lock automatically ! | |
50 | self.lock() |
|
37 | self.lock() | |
51 | self._finalize = Finalize(self, DaemonLock._on_finalize, |
|
38 | self._finalize = Finalize(self, DaemonLock._on_finalize, | |
52 | args=(self, debug), exitpriority=10) |
|
39 | args=(self, debug), exitpriority=10) | |
53 |
|
40 | |||
54 | @staticmethod |
|
41 | @staticmethod | |
55 | def _on_finalize(lock, debug): |
|
42 | def _on_finalize(lock, debug): | |
56 | if lock.held: |
|
43 | if lock.held: | |
57 | if debug: |
|
44 | if debug: | |
58 | print 'leck held finilazing and running lock.release()' |
|
45 | print 'leck held finilazing and running lock.release()' | |
59 | lock.release() |
|
46 | lock.release() | |
60 |
|
47 | |||
61 | def lock(self): |
|
48 | def lock(self): | |
62 | """ |
|
49 | """ | |
63 | locking function, if lock is present it |
|
50 | locking function, if lock is present it | |
64 | will raise LockHeld exception |
|
51 | will raise LockHeld exception | |
65 | """ |
|
52 | """ | |
66 | lockname = '%s' % (os.getpid()) |
|
53 | lockname = '%s' % (os.getpid()) | |
67 | if self.debug: |
|
54 | if self.debug: | |
68 | print 'running lock' |
|
55 | print 'running lock' | |
69 | self.trylock() |
|
56 | self.trylock() | |
70 | self.makelock(lockname, self.pidfile) |
|
57 | self.makelock(lockname, self.pidfile) | |
71 | return True |
|
58 | return True | |
72 |
|
59 | |||
73 | def trylock(self): |
|
60 | def trylock(self): | |
74 | running_pid = False |
|
61 | running_pid = False | |
75 | if self.debug: |
|
62 | if self.debug: | |
76 | print 'checking for already running process' |
|
63 | print 'checking for already running process' | |
77 | try: |
|
64 | try: | |
78 | pidfile = open(self.pidfile, "r") |
|
65 | pidfile = open(self.pidfile, "r") | |
79 | pidfile.seek(0) |
|
66 | pidfile.seek(0) | |
80 | running_pid = int(pidfile.readline()) |
|
67 | running_pid = int(pidfile.readline()) | |
81 |
|
68 | |||
82 | pidfile.close() |
|
69 | pidfile.close() | |
83 |
|
70 | |||
84 | if self.debug: |
|
71 | if self.debug: | |
85 | print ('lock file present running_pid: %s, ' |
|
72 | print ('lock file present running_pid: %s, ' | |
86 | 'checking for execution') % running_pid |
|
73 | 'checking for execution') % running_pid | |
87 | # Now we check the PID from lock file matches to the current |
|
74 | # Now we check the PID from lock file matches to the current | |
88 | # process PID |
|
75 | # process PID | |
89 | if running_pid: |
|
76 | if running_pid: | |
90 | try: |
|
77 | try: | |
91 | kill(running_pid, 0) |
|
78 | kill(running_pid, 0) | |
92 | except OSError, exc: |
|
79 | except OSError, exc: | |
93 | if exc.errno in (errno.ESRCH, errno.EPERM): |
|
80 | if exc.errno in (errno.ESRCH, errno.EPERM): | |
94 | print ("Lock File is there but" |
|
81 | print ("Lock File is there but" | |
95 | " the program is not running") |
|
82 | " the program is not running") | |
96 | print "Removing lock file for the: %s" % running_pid |
|
83 | print "Removing lock file for the: %s" % running_pid | |
97 | self.release() |
|
84 | self.release() | |
98 | else: |
|
85 | else: | |
99 | raise |
|
86 | raise | |
100 | else: |
|
87 | else: | |
101 | print "You already have an instance of the program running" |
|
88 | print "You already have an instance of the program running" | |
102 | print "It is running as process %s" % running_pid |
|
89 | print "It is running as process %s" % running_pid | |
103 | raise LockHeld() |
|
90 | raise LockHeld() | |
104 |
|
91 | |||
105 | except IOError, e: |
|
92 | except IOError, e: | |
106 | if e.errno != 2: |
|
93 | if e.errno != 2: | |
107 | raise |
|
94 | raise | |
108 |
|
95 | |||
109 | def release(self): |
|
96 | def release(self): | |
110 | """releases the pid by removing the pidfile |
|
97 | """releases the pid by removing the pidfile | |
111 | """ |
|
98 | """ | |
112 | if self.debug: |
|
99 | if self.debug: | |
113 | print 'trying to release the pidlock' |
|
100 | print 'trying to release the pidlock' | |
114 |
|
101 | |||
115 | if self.callbackfn: |
|
102 | if self.callbackfn: | |
116 | #execute callback function on release |
|
103 | #execute callback function on release | |
117 | if self.debug: |
|
104 | if self.debug: | |
118 | print 'executing callback function %s' % self.callbackfn |
|
105 | print 'executing callback function %s' % self.callbackfn | |
119 | self.callbackfn() |
|
106 | self.callbackfn() | |
120 | try: |
|
107 | try: | |
121 | if self.debug: |
|
108 | if self.debug: | |
122 | print 'removing pidfile %s' % self.pidfile |
|
109 | print 'removing pidfile %s' % self.pidfile | |
123 | os.remove(self.pidfile) |
|
110 | os.remove(self.pidfile) | |
124 | self.held = False |
|
111 | self.held = False | |
125 | except OSError, e: |
|
112 | except OSError, e: | |
126 | if self.debug: |
|
113 | if self.debug: | |
127 | print 'removing pidfile failed %s' % e |
|
114 | print 'removing pidfile failed %s' % e | |
128 | pass |
|
115 | pass | |
129 |
|
116 | |||
130 | def makelock(self, lockname, pidfile): |
|
117 | def makelock(self, lockname, pidfile): | |
131 | """ |
|
118 | """ | |
132 | this function will make an actual lock |
|
119 | this function will make an actual lock | |
133 |
|
120 | |||
134 | :param lockname: acctual pid of file |
|
121 | :param lockname: acctual pid of file | |
135 | :param pidfile: the file to write the pid in |
|
122 | :param pidfile: the file to write the pid in | |
136 | """ |
|
123 | """ | |
137 | if self.debug: |
|
124 | if self.debug: | |
138 | print 'creating a file %s and pid: %s' % (pidfile, lockname) |
|
125 | print 'creating a file %s and pid: %s' % (pidfile, lockname) | |
139 | pidfile = open(self.pidfile, "wb") |
|
126 | pidfile = open(self.pidfile, "wb") | |
140 | pidfile.write(lockname) |
|
127 | pidfile.write(lockname) | |
141 | pidfile.close |
|
128 | pidfile.close | |
142 | self.held = True |
|
129 | self.held = True |
General Comments 0
You need to be logged in to leave comments.
Login now