Package entropy :: Package client :: Package services :: Package ugc :: Module interfaces

Source Code for Module entropy.client.services.ugc.interfaces

  1  # -*- coding: utf-8 -*- 
  2  """ 
  3   
  4      @author: Fabio Erculiani <lxnay@sabayonlinux.org> 
  5      @contact: lxnay@sabayonlinux.org 
  6      @copyright: Fabio Erculiani 
  7      @license: GPL-2 
  8   
  9      B{Entropy Client Services UGC Base Interfaces}. 
 10   
 11  """ 
 12   
 13  import os 
 14  from entropy.core import Singleton 
 15  from entropy.exceptions import * 
 16  from entropy.const import etpConst, etpCache, const_setup_file, const_setup_perms 
 17  from entropy.i18n import _ 
 18   
19 -class Client:
20 21 ssl_connection = True
22 - def __init__(self, EquoInstance, quiet = True, show_progress = False):
23 24 from entropy.client.interfaces import Client as Cl 25 if not isinstance(EquoInstance, Cl): 26 mytxt = _("A valid Client based instance is needed") 27 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,)) 28 29 import socket, threading 30 self.socket, self.threading = socket, threading 31 import struct 32 self.struct = struct 33 self.Entropy = EquoInstance 34 self.store = AuthStore() 35 self.quiet = quiet 36 self.show_progress = show_progress 37 self.UGCCache = Cache(self) 38 self.TxLocks = {}
39
40 - def connect_to_service(self, repository, timeout = None):
41 42 avail_data = self.Entropy.SystemSettings['repositories']['available'] 43 if repository not in avail_data: 44 raise RepositoryError("RepositoryError: %s" % ( 45 _('repository is not available'),)) 46 47 url = avail_data[repository]['service_uri'] 48 port = avail_data[repository]['service_port'] 49 if self.ssl_connection: 50 port = avail_data[repository]['ssl_service_port'] 51 52 from entropy.services.ugc.interfaces import Client 53 from entropy.client.services.ugc.commands import Client as CommandsClient 54 args = [self.Entropy, CommandsClient] 55 kwargs = { 56 'ssl': self.ssl_connection, 57 'quiet': self.quiet, 58 'show_progress': self.show_progress 59 } 60 if timeout is not None: 61 kwargs['socket_timeout'] = timeout 62 63 srv = Client(*args,**kwargs) 64 srv.connect(url, port) 65 return srv
66
67 - def get_service_connection(self, repository, check = True, timeout = None):
68 if check: 69 if not self.is_repository_eapi3_aware(repository): 70 return None 71 try: 72 srv = self.connect_to_service(repository, timeout = timeout) 73 except (RepositoryError, ConnectionError,): 74 return None 75 except (self.socket.error, self.struct.error,): 76 return None 77 return srv
78
79 - def is_repository_eapi3_aware(self, repository):
80 81 aware = self.UGCCache._get_live_cache_item(repository, 'is_repository_eapi3_aware') 82 if aware != None: 83 return aware 84 85 srv = self.get_service_connection(repository, check = False, 86 timeout = 6) 87 if srv == None: 88 aware = False 89 else: 90 session = srv.open_session() 91 if session != None: 92 srv.close_session(session) 93 srv.disconnect() 94 aware = True 95 else: 96 aware = False 97 98 self.UGCCache._set_live_cache_item(repository, 'is_repository_eapi3_aware', aware) 99 return aware
100
101 - def read_login(self, repository):
102 return self.store.read_login(repository)
103
104 - def remove_login(self, repository):
105 return self.store.remove_login(repository)
106
107 - def do_login(self, repository, force = False):
108 109 login_data = self.read_login(repository) 110 if (login_data != None) and not force: 111 return True, _('ok') 112 113 aware = self.is_repository_eapi3_aware(repository) 114 if not aware: 115 return False, _('repository does not support EAPI3') 116 117 def fake_callback(*args,**kwargs): 118 return True
119 120 attempts = 3 121 while attempts: 122 123 # use input box to read login 124 input_params = [ 125 ('username', _('Username'), fake_callback, False), 126 ('password', _('Password'), fake_callback, True) 127 ] 128 login_data = self.Entropy.inputBox( 129 "%s %s %s" % (_('Please login against'), repository, _('repository'),), 130 input_params, 131 cancel_button = True 132 ) 133 if not login_data: 134 return False, _('login abort') 135 136 # now verify 137 srv = self.get_service_connection(repository) 138 if srv == None: 139 return False, _('connection issues') 140 session = srv.open_session() 141 login_status, login_msg = srv.CmdInterface.service_login(login_data['username'], login_data['password'], session) 142 if not login_status: 143 srv.close_session(session) 144 srv.disconnect() 145 self.Entropy.askQuestion("%s: %s" % ( 146 _("Access denied. Login failed"), login_msg,), 147 responses = [_("Ok")]) 148 attempts -= 1 149 continue 150 151 # login accepted, store it? 152 srv.close_session(session) 153 srv.disconnect() 154 rc = self.Entropy.askQuestion( 155 _("Login successful. Do you want to save these credentials ?")) 156 save = False 157 if rc == _("Yes"): 158 save = True 159 self.store.store_login(login_data['username'], 160 login_data['password'], repository, save = save) 161 return True, _('ok')
162 163
164 - def login(self, repository, force = False):
165 166 if repository not in self.TxLocks: 167 self.TxLocks[repository] = self.threading.Lock() 168 169 with self.TxLocks[repository]: 170 return self.do_login(repository, force = force)
171 172
173 - def logout(self, repository):
174 return self.store.remove_login(repository)
175
176 - def do_cmd(self, repository, login_required, func, args, kwargs):
177 178 if repository not in self.TxLocks: 179 self.TxLocks[repository] = self.threading.Lock() 180 181 with self.TxLocks[repository]: 182 183 if login_required: 184 status, err_msg = self.do_login(repository) 185 if not status: 186 return False, err_msg 187 188 srv = self.get_service_connection(repository) 189 if srv == None: 190 return False, 'no connection' 191 session = srv.open_session() 192 if session == None: 193 return False, 'no session' 194 args.insert(0, session) 195 196 if login_required: 197 stored_pass = False 198 while True: 199 # login 200 login_data = self.read_login(repository) 201 if login_data == None: 202 status, msg = self.login(repository) 203 if not status: return status, msg 204 username, password = self.read_login(repository) 205 else: 206 stored_pass = True 207 username, password = login_data 208 logged, error = srv.CmdInterface.service_login(username, password, session) 209 if not logged: 210 if stored_pass: 211 stored_pass = False 212 self.remove_login(repository) 213 continue 214 srv.close_session(session) 215 srv.disconnect() 216 return logged, error 217 break 218 219 try: 220 cmd_func = getattr(srv.CmdInterface, func) 221 except AttributeError: 222 return False, 'local function not available' 223 rslt = cmd_func(*args,**kwargs) 224 try: 225 srv.close_session(session) 226 srv.disconnect() 227 except ConnectionError: 228 return False, 'no connection' 229 230 return rslt
231
232 - def get_comments(self, repository, pkgkey):
233 return self.do_cmd(repository, False, "ugc_get_textdocs", [pkgkey], {})
234
235 - def get_comments_by_identifiers(self, repository, identifiers):
236 return self.do_cmd(repository, False, "ugc_get_textdocs_by_identifiers", [identifiers], {})
237
238 - def get_documents_by_identifiers(self, repository, identifiers):
239 return self.do_cmd(repository, False, "ugc_get_documents_by_identifiers", [identifiers], {})
240
241 - def add_comment(self, repository, pkgkey, comment, title, keywords):
242 self.UGCCache.clear_alldocs_cache(repository) 243 return self.do_cmd(repository, True, "ugc_add_comment", [pkgkey, comment, title, keywords], {})
244
245 - def edit_comment(self, repository, iddoc, new_comment, new_title, new_keywords):
246 self.UGCCache.clear_alldocs_cache(repository) 247 return self.do_cmd(repository, True, "ugc_edit_comment", [iddoc, new_comment, new_title, new_keywords], {})
248
249 - def remove_comment(self, repository, iddoc):
250 self.UGCCache.clear_alldocs_cache(repository) 251 return self.do_cmd(repository, True, "ugc_remove_comment", [iddoc], {})
252
253 - def add_vote(self, repository, pkgkey, vote):
254 data = self.do_cmd(repository, True, "ugc_do_vote", [pkgkey, vote], {}) 255 if isinstance(data, tuple): voted, add_err_msg = data 256 else: return False, 'wrong server answer' 257 if voted: self.get_vote(repository, pkgkey) 258 return voted, add_err_msg
259
260 - def get_vote(self, repository, pkgkey):
261 vote, err_msg = self.do_cmd(repository, False, "ugc_get_vote", [pkgkey], {}) 262 if isinstance(vote, float): 263 mydict = {pkgkey: vote} 264 self.UGCCache.update_vote_cache(repository, mydict) 265 return vote, err_msg
266
267 - def get_all_votes(self, repository):
268 votes_dict, err_msg = self.do_cmd(repository, False, "ugc_get_allvotes", [], {}) 269 if isinstance(votes_dict, dict): 270 self.UGCCache.update_vote_cache(repository, votes_dict) 271 return votes_dict, err_msg
272
273 - def add_downloads(self, repository, pkgkeys):
274 return self.do_cmd(repository, False, "ugc_do_downloads", [pkgkeys], {})
275
276 - def get_downloads(self, repository, pkgkey):
277 data = self.do_cmd(repository, False, "ugc_get_downloads", [pkgkey], {}) 278 if isinstance(data, tuple): downloads, err_msg = data 279 else: return False, 'wrong server answer' 280 if downloads: 281 mydict = {pkgkey: downloads} 282 self.UGCCache.update_downloads_cache(repository, mydict) 283 return downloads, err_msg
284
285 - def get_all_downloads(self, repository):
286 down_dict, err_msg = self.do_cmd(repository, False, "ugc_get_alldownloads", [], {}) 287 if isinstance(down_dict, dict): 288 self.UGCCache.update_downloads_cache(repository, down_dict) 289 return down_dict, err_msg
290
291 - def add_download_stats(self, repository, pkgkeys):
292 return self.do_cmd(repository, False, "ugc_do_download_stats", [pkgkeys], {})
293
294 - def send_file(self, repository, pkgkey, file_path, title, description, keywords):
295 self.UGCCache.clear_alldocs_cache(repository) 296 return self.do_cmd(repository, True, "ugc_send_file", [pkgkey, file_path, etpConst['ugc_doctypes']['generic_file'], title, description, keywords], {})
297
298 - def remove_file(self, repository, iddoc):
299 self.UGCCache.clear_alldocs_cache(repository) 300 return self.do_cmd(repository, True, "ugc_remove_file", [iddoc], {})
301
302 - def send_image(self, repository, pkgkey, image_path, title, description, keywords):
303 self.UGCCache.clear_alldocs_cache(repository) 304 return self.do_cmd(repository, True, "ugc_send_file", [pkgkey, image_path, etpConst['ugc_doctypes']['image'], title, description, keywords], {})
305
306 - def remove_image(self, repository, iddoc):
307 self.UGCCache.clear_alldocs_cache(repository) 308 return self.do_cmd(repository, True, "ugc_remove_image", [iddoc], {})
309
310 - def send_youtube_video(self, repository, pkgkey, video_path, title, description, keywords):
311 self.UGCCache.clear_alldocs_cache(repository) 312 return self.do_cmd(repository, True, "ugc_send_file", [pkgkey, video_path, etpConst['ugc_doctypes']['youtube_video'], title, description, keywords], {})
313
314 - def remove_youtube_video(self, repository, iddoc):
315 self.UGCCache.clear_alldocs_cache(repository) 316 return self.do_cmd(repository, True, "ugc_remove_youtube_video", [iddoc], {})
317
318 - def get_docs(self, repository, pkgkey):
319 data = self.do_cmd(repository, False, "ugc_get_docs", [pkgkey], {}) 320 if isinstance(data, tuple): docs_data, err_msg = data 321 else: return False, 'wrong server answer' 322 if err_msg == 'ok': 323 self.UGCCache.update_alldocs_cache(pkgkey, repository, docs_data) 324 return docs_data, err_msg
325
326 - def send_document_autosense(self, repository, pkgkey, ugc_type, data, title, description, keywords):
327 if ugc_type == etpConst['ugc_doctypes']['generic_file']: 328 return self.send_file(repository, pkgkey, data, title, description, keywords) 329 elif ugc_type == etpConst['ugc_doctypes']['image']: 330 return self.send_image(repository, pkgkey, data, title, description, keywords) 331 elif ugc_type == etpConst['ugc_doctypes']['youtube_video']: 332 return self.send_youtube_video(repository, pkgkey, data, title, description, keywords) 333 elif ugc_type == etpConst['ugc_doctypes']['comments']: 334 return self.add_comment(repository, pkgkey, description, title, keywords) 335 return None, 'type not supported locally'
336
337 - def remove_document_autosense(self, repository, iddoc, ugc_type):
338 if ugc_type == etpConst['ugc_doctypes']['generic_file']: 339 return self.remove_file(repository, iddoc) 340 elif ugc_type == etpConst['ugc_doctypes']['image']: 341 return self.remove_image(repository, iddoc) 342 elif ugc_type == etpConst['ugc_doctypes']['youtube_video']: 343 return self.remove_youtube_video(repository, iddoc) 344 elif ugc_type == etpConst['ugc_doctypes']['comments']: 345 return self.remove_comment(repository, iddoc) 346 return None, 'type not supported locally'
347
348 - def report_error(self, repository, error_data):
349 return self.do_cmd(repository, False, "report_error", [error_data], {})
350 351
352 -class AuthStore(Singleton):
353 354 access_file = etpConst['ugc_accessfile']
355 - def init_singleton(self):
356 357 from xml.dom import minidom 358 from xml.parsers import expat 359 self.expat = expat 360 self.minidom = minidom 361 self.setup_store_paths() 362 try: 363 self.setup_permissions() 364 except IOError: 365 pass 366 self.store = {} 367 try: 368 self.xmldoc = self.minidom.parse(self.access_file) 369 except (self.expat.ExpatError, IOError,): 370 self.xmldoc = None 371 if self.xmldoc != None: 372 try: 373 self.parse_document() 374 except self.expat.ExpatError: 375 self.xmldoc = None 376 self.store = {}
377
378 - def setup_store_paths(self):
379 myhome = os.getenv("HOME") 380 if myhome != None: 381 if os.path.isdir(myhome) and os.access(myhome, os.W_OK): 382 self.access_file = os.path.join(myhome, ".config/entropy", 383 os.path.basename(self.access_file)) 384 self.access_dir = os.path.dirname(self.access_file)
385
386 - def setup_permissions(self):
387 if not os.path.isdir(self.access_dir): 388 os.makedirs(self.access_dir) 389 if not os.path.isfile(self.access_file): 390 f = open(self.access_file, "w") 391 f.close() 392 gid = etpConst['entropygid'] 393 if gid is None: 394 gid = 0 395 396 try: 397 const_setup_file(self.access_dir, gid, 0o700) 398 except OSError: 399 pass 400 try: 401 const_setup_file(self.access_file, gid, 0o600) 402 except OSError: 403 pass
404
405 - def parse_document(self):
406 self.store.clear() 407 store = self.xmldoc.getElementsByTagName("store")[0] 408 repositories = store.getElementsByTagName("repository") 409 for repository in repositories: 410 repoid = repository.getAttribute("id") 411 if not repoid: continue 412 username = repository.getElementsByTagName("username")[0].firstChild.data.strip() 413 password = repository.getElementsByTagName("password")[0].firstChild.data.strip() 414 self.store[repoid] = {'username': username, 'password': password}
415
416 - def store_login(self, username, password, repository, save = True):
417 self.store[repository] = {'username': username, 'password': password} 418 if save: 419 self.save_store()
420
421 - def save_store(self):
422 423 self.xmldoc = self.minidom.Document() 424 store = self.xmldoc.createElement("store") 425 426 for repository in self.store: 427 repo = self.xmldoc.createElement("repository") 428 repo.setAttribute('id', repository) 429 # username 430 username = self.xmldoc.createElement("username") 431 username_value = self.xmldoc.createTextNode(self.store[repository]['username']) 432 username.appendChild(username_value) 433 repo.appendChild(username) 434 # password 435 password = self.xmldoc.createElement("password") 436 password_value = self.xmldoc.createTextNode(self.store[repository]['password']) 437 password.appendChild(password_value) 438 repo.appendChild(password) 439 store.appendChild(repo) 440 441 self.xmldoc.appendChild(store) 442 f = open(self.access_file, "w") 443 f.writelines(self.xmldoc.toprettyxml(indent=" ")) 444 f.flush() 445 f.close() 446 self.setup_permissions() 447 self.parse_document()
448
449 - def remove_login(self, repository, save = True):
450 if repository in self.store: 451 del self.store[repository] 452 if save: 453 self.save_store()
454
455 - def read_login(self, repository):
456 if repository in self.store: 457 return self.store[repository]['username'], self.store[repository]['password']
458
459 -class Cache:
460
461 - def __init__(self, UGCClientInstance):
462 463 if not isinstance(UGCClientInstance, Client): 464 mytxt = _("A valid UGC Client interface based instance is needed") 465 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,)) 466 467 import threading 468 import entropy.dump as dumpTools 469 self.CacheLock = threading.Lock() 470 self.dumpTools = dumpTools 471 self.Service = UGCClientInstance 472 self.xcache = {}
473
474 - def _get_live_cache_item(self, repository, item):
475 if repository not in self.xcache: 476 return None 477 return self.xcache[repository].get(item)
478
479 - def _set_live_cache_item(self, repository, item, obj):
480 if repository not in self.xcache: 481 self.xcache[repository] = {} 482 if type(obj) in (list, tuple,): 483 my_obj = obj[:] 484 elif type(obj) in (set, frozenset, dict,): 485 my_obj = obj.copy() 486 else: 487 my_obj = obj 488 self.xcache[repository][item] = my_obj
489
490 - def _clear_live_cache_item(self, repository, item):
491 if repository not in self.xcache: 492 return 493 if item not in self.xcache[repository]: 494 return 495 del self.xcache[repository][item]
496
497 - def _get_store_cache_file(self, iddoc, repository, doc_url):
498 return "%s/%s/iddoc_%s/%s" % (etpCache['ugc_docs'], repository, iddoc, doc_url,)
499
500 - def _get_vote_cache_file(self, repository):
501 return self._get_vote_cache_dir(repository)
502
503 - def _get_downloads_cache_file(self, repository):
504 return self._get_downloads_cache_dir(repository)
505
506 - def _get_alldocs_cache_file(self, pkgkey, repository):
507 return self._get_alldocs_cache_dir(repository)+"/"+pkgkey
508
509 - def _get_alldocs_cache_dir(self, repository):
510 return etpCache['ugc_docs']+"/"+repository
511
512 - def _get_downloads_cache_dir(self, repository):
513 return etpCache['ugc_downloads']+"/"+repository
514
515 - def _get_vote_cache_dir(self, repository):
516 return etpCache['ugc_votes']+"/"+repository
517
518 - def _get_vote_cache_key(self, repository):
519 return 'get_vote_cache_'+repository
520
521 - def _get_downloads_cache_key(self, repository):
522 return 'get_downloads_cache_'+repository
523
524 - def _get_alldocs_cache_key(self, repository):
525 return 'get_package_alldocs_cache_'+repository
526
527 - def store_document(self, iddoc, repository, doc_url):
528 cache_file = os.path.join(etpConst['dumpstoragedir'], self._get_store_cache_file(iddoc, repository, doc_url)) 529 cache_dir = os.path.dirname(cache_file) 530 531 try: 532 if not os.path.isdir(cache_dir): 533 os.makedirs(cache_dir, 0o775) 534 if etpConst['entropygid'] != None: 535 const_setup_perms(cache_dir, etpConst['entropygid']) 536 except OSError: 537 raise PermissionDenied("PermissionDenied: %s %s" % (_("Cannot setup cache directory"), cache_dir,)) 538 if not os.access(cache_dir, os.W_OK): 539 raise PermissionDenied("PermissionDenied: %s %s" % (_("Cannot write to cache directory"), cache_dir,)) 540 541 if os.path.isfile(cache_file) or os.path.islink(cache_file): 542 try: 543 os.remove(cache_file) 544 except OSError: 545 raise PermissionDenied("PermissionDenied: %s %s" % (_("Cannot remove cache file"), cache_file,)) 546 547 fetcher = self.Service.Entropy.urlFetcher(doc_url, cache_file, resume = False) 548 rc = fetcher.download() 549 if rc in ("-1", "-2", "-3", "-4"): return None 550 if not os.path.isfile(cache_file): return None 551 552 try: 553 os.chmod(cache_file, 0o664) 554 if etpConst['entropygid'] != None: 555 os.chown(cache_file, -1, etpConst['entropygid']) 556 except OSError: 557 raise PermissionDenied("PermissionDenied: %s %s" % (_("Cannot write to cache file"), cache_file,)) 558 559 del fetcher 560 return cache_file
561
562 - def get_stored_document(self, iddoc, repository, doc_url):
563 cache_file = os.path.join(etpConst['dumpstoragedir'], self._get_store_cache_file(iddoc, repository, doc_url)) 564 if os.path.isfile(cache_file) and os.access(cache_file, os.R_OK): 565 return cache_file
566
567 - def update_vote_cache(self, repository, vote_dict):
568 cached = self.get_vote_cache(repository) 569 if cached == None: 570 cached = vote_dict.copy() 571 else: 572 cached.update(vote_dict) 573 self.save_vote_cache(repository, cached)
574
575 - def update_downloads_cache(self, repository, down_dict):
576 cached = self.get_downloads_cache(repository) 577 if cached == None: 578 cached = down_dict.copy() 579 else: 580 cached.update(down_dict) 581 self.save_downloads_cache(repository, cached)
582
583 - def update_alldocs_cache(self, pkgkey, repository, alldocs_dict):
584 self.save_alldocs_cache(pkgkey, repository, alldocs_dict)
585
586 - def clear_alldocs_cache(self, repository):
587 with self.CacheLock: 588 self.Service.Entropy.clear_dump_cache(self._get_alldocs_cache_dir(repository)) 589 self._clear_live_cache_item(repository, self._get_alldocs_cache_key(repository))
590
591 - def clear_downloads_cache(self, repository):
592 with self.CacheLock: 593 self.Service.Entropy.clear_dump_cache(self._get_alldocs_cache_dir(repository)) 594 self._clear_live_cache_item(repository, self._get_downloads_cache_key(repository))
595
596 - def clear_vote_cache(self, repository):
597 with self.CacheLock: 598 self.Service.Entropy.clear_dump_cache(self._get_vote_cache_dir(repository)) 599 self._clear_live_cache_item(repository, self._get_vote_cache_key(repository))
600
601 - def clear_cache(self, repository):
606
607 - def get_vote_cache(self, repository):
608 cache_key = self._get_vote_cache_key(repository) 609 cached = self._get_live_cache_item(repository, cache_key) 610 if cached != None: 611 return cached 612 with self.CacheLock: 613 cache_file = self._get_vote_cache_file(repository) 614 try: 615 data = self.dumpTools.loadobj(cache_file) 616 if data != None: 617 self._set_live_cache_item(repository, cache_key, data) 618 except (IOError, EOFError, OSError): 619 data = None 620 return data
621
622 - def get_downloads_cache(self, repository):
623 cache_key = self._get_downloads_cache_key(repository) 624 cached = self._get_live_cache_item(repository, cache_key) 625 if cached != None: 626 return cached 627 with self.CacheLock: 628 cache_file = self._get_downloads_cache_file(repository) 629 try: 630 data = self.dumpTools.loadobj(cache_file) 631 if data != None: 632 self._set_live_cache_item(repository, cache_key, data) 633 except (IOError, EOFError, OSError): 634 data = None 635 return data
636
637 - def get_alldocs_cache(self, pkgkey, repository):
638 cache_key = self._get_alldocs_cache_key(repository) 639 cached = self._get_live_cache_item(repository, cache_key) 640 if isinstance(cached, dict): 641 if pkgkey in cached: return cached[pkgkey] 642 else: 643 cached = {} 644 with self.CacheLock: 645 cache_file = self._get_alldocs_cache_file(pkgkey, repository) 646 try: 647 data = self.dumpTools.loadobj(cache_file) 648 if data != None: 649 cached[pkgkey] = data 650 self._set_live_cache_item(repository, cache_key, cached) 651 except (IOError, EOFError, OSError): 652 data = None 653 return data
654
655 - def save_vote_cache(self, repository, vote_dict):
656 with self.CacheLock: 657 self._clear_live_cache_item(repository, self._get_vote_cache_key(repository)) 658 self.dumpTools.dumpobj(self._get_vote_cache_file(repository), vote_dict)
659
660 - def save_downloads_cache(self, repository, down_dict):
661 with self.CacheLock: 662 self._clear_live_cache_item(repository, self._get_downloads_cache_key(repository)) 663 self.dumpTools.dumpobj(self._get_downloads_cache_file(repository), down_dict)
664
665 - def save_alldocs_cache(self, pkgkey, repository, alldocs_dict):
666 with self.CacheLock: 667 self._clear_live_cache_item(repository, self._get_alldocs_cache_key(repository)) 668 self.dumpTools.dumpobj(self._get_alldocs_cache_file(pkgkey, repository), alldocs_dict)
669
670 - def get_package_vote(self, repository, pkgkey):
671 cache = self.get_vote_cache(repository) 672 if not cache: 673 return 0.0 674 elif not isinstance(cache, dict): 675 return 0.0 676 elif pkgkey not in cache: 677 return 0.0 678 return cache[pkgkey]
679
680 - def get_package_downloads(self, repository, pkgkey):
681 cache = self.get_downloads_cache(repository) 682 if not cache: 683 return 0 684 elif not isinstance(cache, dict): 685 return 0 686 elif pkgkey not in cache: 687 return 0 688 try: 689 return int(cache[pkgkey]) 690 except ValueError: 691 return 0
692