diff --git a/sulfur/Makefile b/sulfur/Makefile
index 50946764d..7a962d651 100644
--- a/sulfur/Makefile
+++ b/sulfur/Makefile
@@ -38,6 +38,7 @@ install:
install -m755 $(MISCDIR)/sulfur-uri-handler $(DESTDIR)$(BINDIR)/.
install -m644 $(MISCDIR)/entropy-handler.schemas $(DESTDIR)/etc/gconf/schemas/.
install -m644 $(PIXDIR)/*.png $(DESTDIR)/usr/share/pixmaps/sulfur/.
+ install -m644 $(PIXDIR)/*.gif $(DESTDIR)/usr/share/pixmaps/sulfur/.
install -m644 $(PIXDIR)/packages/*.png $(DESTDIR)/usr/share/pixmaps/sulfur/packages/.
install -m644 $(PIXDIR)/ugc/*.png $(DESTDIR)/usr/share/pixmaps/sulfur/ugc/.
install -m644 $(MISCDIR)/kde_x-sulfur.desktop $(DESTDIR)/usr/share/mimelnk/application/.
diff --git a/sulfur/src/sulfur/__init__.py b/sulfur/src/sulfur/__init__.py
index 0c3b04539..ec9226b11 100644
--- a/sulfur/src/sulfur/__init__.py
+++ b/sulfur/src/sulfur/__init__.py
@@ -43,13 +43,14 @@ from entropy.services.exceptions import EntropyServicesError
import entropy.tools
from entropy.const import etpConst, const_get_stringtype, \
initconfig_entropy_constants, const_convert_to_unicode, \
- const_drop_privileges, const_regain_privileges
+ const_debug_write
from entropy.i18n import _
from entropy.misc import ParallelTask
from entropy.cache import EntropyCacher, MtimePingus
from entropy.output import print_generic
from entropy.db.exceptions import ProgrammingError, OperationalError
from entropy.core.settings.base import SystemSettings
+from entropy.services.client import WebService
# Sulfur Imports
import gtk, gobject
@@ -59,7 +60,7 @@ from sulfur.setup import SulfurConf, const, fakeoutfile, fakeinfile, \
cleanMarkupString
from sulfur.widgets import SulfurConsole
from sulfur.core import UI, Controller, FORK_PIDS, fork_function, \
- busy_cursor, normal_cursor
+ busy_cursor, normal_cursor, get_entropy_webservice, Privileges
from sulfur.views import *
from sulfur.filters import Filter
from sulfur.dialogs import *
@@ -67,59 +68,14 @@ from sulfur.progress import Base as BaseProgress
from sulfur.events import SulfurApplicationEventsMixin
from sulfur.event import SulfurSignals
-
class SulfurApplication(Controller, SulfurApplicationEventsMixin):
- class Privileges:
-
- def __init__(self, drop_privs = True):
- self.__drop_privs = drop_privs
- self.__drop_privs_lock = threading.RLock()
- self.__with_stmt = 0
-
- def __enter__(self):
- """
- Hold the lock.
- """
- self.__drop_privs_lock.acquire()
- if self.__with_stmt < 1:
- self.regain()
- self.__with_stmt += 1
-
- def __exit__(self, exc_type, exc_value, traceback):
- """
- Drop the lock.
- """
- if self.__with_stmt == 1:
- self.drop()
- self.__with_stmt -= 1
- self.__drop_privs_lock.release()
-
- def drop(self):
- """
- Drop process privileges. Setting unpriv_gid to etpConst['entropygid']
- makes Entropy UGC/Data cache handling working.
- """
- if self.__drop_privs:
- with self.__drop_privs_lock:
- const_drop_privileges(unpriv_gid = etpConst['entropygid'])
- const.setup()
-
- def regain(self):
- """
- Regain previously dropped process privileges.
- """
- if self.__drop_privs:
- with self.__drop_privs_lock:
- const_regain_privileges()
- const.setup()
-
- def __init__(self, drop_privs = True):
+ def __init__(self):
self.do_debug = False
self._ugc_status = "--nougc" not in sys.argv
- self._privileges = self.Privileges(drop_privs = drop_privs)
+ self._privileges = Privileges()
# Use this lock when you want to make sure that no other asynchronous
# executions are being run.
self._async_event_execution_lock = threading.Lock()
@@ -127,6 +83,7 @@ class SulfurApplication(Controller, SulfurApplicationEventsMixin):
self._entropy = Equo()
self._cacher = EntropyCacher()
self._settings = SystemSettings()
+ self._webserv_map = {}
# support for packages installation on startup
packages_install, atoms_install, do_fetch = \
@@ -187,6 +144,40 @@ class SulfurApplication(Controller, SulfurApplicationEventsMixin):
# init the Controller Class to connect signals.
Controller.__init__( self, ui )
+ def _get_webservice(self, repository_id):
+ webserv = self._webserv_map.get(repository_id)
+ if webserv == -1:
+ # not available
+ return None
+ if webserv is not None:
+ return webserv
+
+ with self._privileges:
+ # so that the correct auth store file is fetched
+ # NOTE: other areas don't do the same, be careful
+ try:
+ webserv = get_entropy_webservice(self._entropy, repository_id)
+ except WebService.UnsupportedService as err:
+ webserv = None
+
+ if webserv is None:
+ self._webserv_map[repository_id] = -1
+ # not available
+ return
+
+ try:
+ available = webserv.service_available()
+ except WebService.WebServiceException:
+ available = False
+
+ if not available:
+ self._webserv_map[repository_id] = -1
+ # not available
+ return
+
+ self._webserv_map[repository_id] = webserv
+ return webserv
+
def __scan_packages_install(self):
packages_install = os.environ.get("SULFUR_PACKAGES", '').split(";")
atoms_install = []
@@ -896,23 +887,38 @@ class SulfurApplication(Controller, SulfurApplicationEventsMixin):
if self.do_debug:
print_generic("entering UGC")
- if self._entropy.UGC is None:
- return
-
if self._spawning_ugc or self.disable_ugc:
return
if not force:
- eapi3_repos = []
+ webserv_repos = []
for repoid in self._entropy.repositories():
- aware = self._entropy.UGC.is_repository_eapi3_aware(repoid)
+ webserv = self._get_webservice(repoid)
+ if webserv is None:
+ continue
+ try:
+ aware = webserv.service_available()
+ except WebService.WebServiceException:
+ continue
if aware:
- eapi3_repos.append(repoid)
+ webserv_repos.append((webserv, repoid))
cache_available = True
- for repoid in eapi3_repos:
- if not self._entropy.is_ugc_cached(repoid):
+ for webserv, repoid in webserv_repos:
+ cache_available = True
+ try:
+ webserv.get_available_votes(cache = True, cached = True)
+ except WebService.CacheMiss:
cache_available = False
+ if cache_available:
+ # also check downloads
+ try:
+ webserv.get_available_downloads(cache = True,
+ cached = True)
+ except WebService.CacheMiss:
+ cache_available = False
+ if not cache_available:
+ break
pingus_id = "sulfur_ugc_content_spawn"
# check if at least 2 hours are passed since last check
@@ -936,9 +942,11 @@ class SulfurApplication(Controller, SulfurApplicationEventsMixin):
self._ugc_update()
self._cacher.sync()
print_generic("UGC child process done")
+ emit_ugc_update()
self._spawning_ugc = True
- fork_function(do_ugc_sync, emit_ugc_update)
+ th = ParallelTask(do_ugc_sync)
+ th.start()
if self.do_debug:
print_generic("quitting UGC")
@@ -947,15 +955,46 @@ class SulfurApplication(Controller, SulfurApplicationEventsMixin):
def _ugc_update(self):
+ def _update_available_cache(repository_id):
+ webserv = self._get_webservice(repository_id)
+ if webserv is None:
+ return
+
+ # fetch vote cache first
+ try:
+ webserv.get_available_votes(cache = False)
+ except WebService.WebServiceException as err:
+ const_debug_write(__name__,
+ "_ugc_update.get_available_votes: ouch %s" % (err,))
+ return
+ # drop get_votes cache completely
+ # this enforces EntropyPackage.vote* to use available_votes cache
+ webserv._drop_cached("get_votes")
+
+ try:
+ webserv.get_available_downloads(cache = False)
+ except WebService.WebServiceException as err:
+ const_debug_write(__name__,
+ "_ugc_update.get_available_downloads: ouch %s" % (err,))
+ return
+ # drop get_downloads cache completely
+ # this enforces EntropyPackage.down* to use available_downloads
+ # cache
+ webserv._drop_cached("get_downloads")
+
+
for repo in self._entropy.repositories():
- if self.do_debug:
- t1 = time.time()
- print_generic("working UGC update for", repo)
- self._entropy.update_ugc_cache(repo)
- if self.do_debug:
- t2 = time.time()
- td = t2 - t1
- print_generic("completed UGC update for", repo, "took", td)
+ t1 = time.time()
+ const_debug_write(__name__,
+ "working UGC update for %s" % (repo,))
+
+ _update_available_cache(repo)
+
+ t2 = time.time()
+ td = t2 - t1
+ const_debug_write(__name__,
+ "completed UGC update for %s, took %s" % (
+ repo, td,))
def fill_pref_db_backup_page(self):
self.dbBackupStore.clear()
@@ -1030,22 +1069,31 @@ class SulfurApplication(Controller, SulfurApplicationEventsMixin):
obj = model.get_value( myiter, 0 )
if obj:
t = "%s" % (_("Not logged in"),)
- if self._entropy.UGC != None:
- logged_data = self._entropy.UGC.read_login(obj['repoid'])
- if logged_data != None:
- t = "%s" % (logged_data[0],)
+ webserv = self._get_webservice(obj['repoid'])
+ if webserv is None:
+ t = "%s" % (_("Not available"),)
+ else:
+ with self._privileges:
+ username = webserv.get_credentials()
+ if username is not None:
+ t = "%s" % (username,)
cell.set_property('markup', t)
def get_ugc_status_pix( column, cell, model, myiter ):
- if self._entropy.UGC == None:
- cell.set_property('icon-name', 'gtk-cancel')
- return
if not self._ugc_status:
cell.set_property('icon-name', 'gtk-cancel')
return
obj = model.get_value( myiter, 0 )
if obj:
- if self._entropy.UGC.is_repository_eapi3_aware(obj['repoid']):
+ webserv = self._get_webservice(obj['repoid'])
+ if webserv is None:
+ cell.set_property( 'icon-name', 'gtk-cancel' )
+ return
+ try:
+ available = webserv.service_available()
+ except WebService.WebServiceException:
+ available = False
+ if available:
cell.set_property( 'icon-name', 'gtk-apply' )
else:
cell.set_property( 'icon-name', 'gtk-cancel' )
@@ -1436,11 +1484,20 @@ class SulfurApplication(Controller, SulfurApplicationEventsMixin):
for repo in repos:
# inform UGC that we are syncing this repo
- if self._entropy.UGC is not None:
- try:
- self._entropy.UGC.add_download_stats(repo, [repo])
- except EntropyServicesError:
- continue
+ webserv = self._get_webservice(repository)
+ if webserv is None:
+ continue
+ try:
+ available = webserv.service_available()
+ except WebService.WebServiceException:
+ continue
+ if not available:
+ continue
+ try:
+ webserv.add_downloads([repo])
+ except WebService.WebServiceException as err:
+ const_debug_write(__name__, repr(err))
+ continue
if repoConn.sync_errors or (rc != 0):
self.progress.set_mainLabel(_('Errors updating repositories.'))
diff --git a/sulfur/src/sulfur/core.py b/sulfur/src/sulfur/core.py
index 114611cf6..dffda77ac 100644
--- a/sulfur/src/sulfur/core.py
+++ b/sulfur/src/sulfur/core.py
@@ -19,12 +19,16 @@
import os
import sys
import shutil
+import threading
import gtk
import gtk.glade
import gobject
-from entropy.const import const_debug_write
+from entropy.const import const_debug_write, const_drop_privileges, \
+ const_regain_privileges, etpConst
from entropy.misc import ParallelTask
+from entropy.core import Singleton
+from sulfur.setup import const
FORK_PIDS = []
@@ -164,6 +168,26 @@ def resize_image(max_width, image_path, new_image_path):
del img_buf
del img
+def resize_image_height(max_height, image_path, new_image_path):
+ shutil.copy2(image_path, new_image_path)
+ img = gtk.Image()
+ img.set_from_file(new_image_path)
+ img_buf = img.get_pixbuf()
+ w, h = img_buf.get_width(), img_buf.get_height()
+ if h > max_height:
+ # resize pix
+ new_h = max_height
+ new_w = new_h*w/h
+ img_buf = img_buf.scale_simple(int(new_w),
+ int(new_h), gtk.gdk.INTERP_BILINEAR)
+ try:
+ img_buf.save(new_image_path, "png")
+ except gobject.GError:
+ # libpng issue? try jpeg
+ img_buf.save(new_image_path, "jpeg")
+ del img_buf
+ del img
+
def load_url(url):
xdg_open = '/usr/bin/xdg-open'
if os.access(xdg_open, os.X_OK):
@@ -172,3 +196,66 @@ def load_url(url):
# child
os.execv(xdg_open, [xdg_open, url])
os._exit(0)
+
+def get_entropy_webservice(entropy_client, repository_id, tx_cb = None):
+ """
+ Get Entropy Web Services service object (ClientWebService).
+
+ @param entropy_client: Entropy Client interface
+ @type entropy_client: entropy.client.interfaces.Client
+ @param repository_id: repository identifier
+ @type repository_id: string
+ @return: the ClientWebService instance
+ @rtype: entropy.client.services.interfaces.ClientWebService
+ @raise WebService.UnsupportedService: if service is unsupported by
+ repository
+ """
+ factory = entropy_client.WebServices()
+ webserv = factory.new(repository_id)
+ if tx_cb is not None:
+ webserv._set_transfer_callback(tx_cb)
+ return webserv
+
+class Privileges(Singleton):
+
+ def init_singleton(self):
+ self.__drop_privs = True
+ self.__drop_privs_lock = threading.RLock()
+ self.__with_stmt = 0
+
+ def __enter__(self):
+ """
+ Hold the lock.
+ """
+ self.__drop_privs_lock.acquire()
+ if self.__with_stmt < 1:
+ self.regain()
+ self.__with_stmt += 1
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ """
+ Drop the lock.
+ """
+ if self.__with_stmt == 1:
+ self.drop()
+ self.__with_stmt -= 1
+ self.__drop_privs_lock.release()
+
+ def drop(self):
+ """
+ Drop process privileges. Setting unpriv_gid to etpConst['entropygid']
+ makes Entropy UGC/Data cache handling working.
+ """
+ if self.__drop_privs:
+ with self.__drop_privs_lock:
+ const_drop_privileges(unpriv_gid = etpConst['entropygid'])
+ const.setup()
+
+ def regain(self):
+ """
+ Regain previously dropped process privileges.
+ """
+ if self.__drop_privs:
+ with self.__drop_privs_lock:
+ const_regain_privileges()
+ const.setup()
diff --git a/sulfur/src/sulfur/dialogs.py b/sulfur/src/sulfur/dialogs.py
index 0c4127d33..d86d97961 100644
--- a/sulfur/src/sulfur/dialogs.py
+++ b/sulfur/src/sulfur/dialogs.py
@@ -31,12 +31,17 @@ from entropy.exceptions import *
from entropy.services.exceptions import TimeoutError
from entropy.const import *
from entropy.misc import ParallelTask
+from entropy.services.client import WebService
+from entropy.client.services.interfaces import Document, DocumentList, \
+ DocumentFactory, ClientWebService
+
import entropy.dep
import entropy.tools
from sulfur.event import SulfurSignals
from sulfur.core import UI, busy_cursor, normal_cursor, fork_function, \
- resize_image, load_url
+ resize_image, resize_image_height, load_url, get_entropy_webservice, \
+ Privileges
from sulfur.setup import const, cleanMarkupString, SulfurConf
class MenuSkel:
@@ -548,6 +553,7 @@ class PkgInfoMenu(MenuSkel):
self.star_selected_pixmap = const.star_selected_pixmap
self.star_empty_pixmap = const.star_empty_pixmap
+ self._ugc_row_height = 48
self._ugc_icon_store_path = None
self.ugc_update_event_handler_id = None
self.loading_pix = gtk.image_new_from_file(const.loading_pix)
@@ -559,6 +565,7 @@ class PkgInfoMenu(MenuSkel):
self.Entropy = Entropy
self.repository = None
self.pkgkey = None
+ self.__webserv = None
self._page_tabs_map = {
1: "details",
@@ -602,6 +609,42 @@ class PkgInfoMenu(MenuSkel):
SulfurSignals.connect('pkg_properties__ugc_tab_clicked',
self._ugc_tab_clicked)
+ @property
+ def _webserv(self):
+ if self.repository is None:
+ # cannot load !
+ return None
+
+ if self.__webserv == -1:
+ # unsupported
+ return None
+ if self.__webserv is not None:
+ return self.__webserv
+
+ with Privileges():
+ try:
+ webserv = get_entropy_webservice(self.Entropy, self.repository)
+ except WebService.UnsupportedService as err:
+ webserv = None
+
+ if webserv is None:
+ self.__webserv = -1
+ # not available
+ return None
+
+ try:
+ available = webserv.service_available()
+ except WebService.WebServiceException:
+ available = False
+
+ if not available:
+ self.__webserv = -1
+ # not available
+ return
+
+ self.__webserv = webserv
+ return webserv
+
def _set_pixbuf_to_cell(self, cell, path):
try:
pixbuf = gtk.gdk.pixbuf_new_from_file(path)
@@ -614,68 +657,74 @@ class PkgInfoMenu(MenuSkel):
if isinstance(obj, dict):
if obj.get('preview_path') is not None:
self._set_pixbuf_to_cell(cell, obj['preview_path'])
- else:
+ elif obj['image_path']:
self._set_pixbuf_to_cell(cell, obj['image_path'])
self._set_colors_to_cell(cell, obj)
- def ugc_content( self, column, cell, model, myiter ):
- obj = model.get_value( myiter, 0 )
- if isinstance(obj, dict):
- self._set_colors_to_cell(cell, obj)
+ def ugc_content(self, column, cell, model, myiter):
+ obj = model.get_value(myiter, 0)
+ if obj is None:
+ return
- if 'is_cat' in obj:
- cell.set_property('markup', "%s\n%s" % (
- obj['parent_desc'], _("Expand to browse"),))
- else:
+ self._set_colors_to_cell(cell, obj)
- title = _("N/A")
- if obj['title']:
- title = const_convert_to_unicode(obj['title'])
- description = _("N/A")
+ if 'is_cat' in obj:
+ cell.set_property('markup', "%s\n%s" % (
+ obj['parent_desc'], _("Expand to browse"),))
+ else:
- if obj['description']:
- description = obj['description']
+ document_id = obj.document_id()
+ document_type = obj.document_type()
- if obj['iddoctype'] in (
- etpConst['ugc_doctypes']['comments'],
- etpConst['ugc_doctypes']['bbcode_doc'],):
+ title = _("N/A")
+ title_s = obj.get(Document.DOCUMENT_TITLE_ID)
+ if title_s:
+ title = const_convert_to_unicode(title_s).rstrip()
- myddata = obj['ddata']
- if not isinstance(obj['ddata'], const_get_stringtype()):
- myddata = myddata.tostring()
- description = const_convert_to_unicode(myddata)
- if len(description) > 100:
- description = description[:100].strip()+"..."
+ description = _("N/A")
+ description_s = obj.get(Document.DOCUMENT_DESCRIPTION_ID)
+ if description_s:
+ description = description_s
- first_txt = "%s: %s, %s: %s\n" % (
- _("Identifier"),
- obj['iddoc'],
- _("Size"),
- entropy.tools.bytes_into_human(obj['size']),
- )
- second_txt = "%s: %s, %s\n" % (
- _("Author"),
- obj['username'],
- obj['ts'],
- )
- third_txt = "%s: %s\n%s: %s\n" % (
- _("Title"),
- title,
- _("Description"),
- description,
- )
- fourth_txt = "%s: %s" % (
+ desc_t = _("Description") + ": "
+ if obj.is_comment():
+ description = obj.document_data()
+ description = cleanMarkupString(
+ const_convert_to_unicode(description))
+ desc_t = "\n"
+
+ first_txt = ""
+ username = obj.get(DocumentFactory.DOCUMENT_USERNAME_ID) or _("N/A")
+ ts = obj.document_timestamp()
+ ts = entropy.tools.convert_unix_time_to_human_time(ts)
+ second_txt = "%s: %s, %s\n" % (
+ _("Author"),
+ username,
+ ts,
+ )
+ third_txt = "%s: %s\n%s%s" % (
+ _("Title"),
+ title,
+ desc_t,
+ description,
+ )
+ doc_keywords = obj.document_keywords().strip()
+ if doc_keywords:
+ keywords = doc_keywords.split()
+ fourth_txt = "\n%s: %s" % (
_("Keywords"),
- ', '.join(obj['keywords']),
+ ', '.join(keywords),
)
+ else:
+ fourth_txt = ""
- mytxt = first_txt + second_txt + third_txt + fourth_txt
- cell.set_property('markup', mytxt)
+ mytxt = first_txt + second_txt + third_txt + fourth_txt
+ cell.set_property('markup', mytxt)
def _set_colors_to_cell(self, cell, obj):
odd = 0
if 'counter' in obj:
- odd = obj['counter']%2
+ odd = obj['counter'] % 2
if 'background' in obj:
cell.set_property('cell-background', obj['background'][odd])
else:
@@ -704,12 +753,12 @@ class PkgInfoMenu(MenuSkel):
def on_closeInfo_clicked(self, widget):
self.disconnect_event_signals()
- self.reset_ugc_data()
+ self.ugc_data = None
self.pkginfo_ui.pkgInfo.hide()
def on_pkgInfo_delete_event(self, widget, path):
self.disconnect_event_signals()
- self.reset_ugc_data()
+ self.ugc_data = None
self.pkginfo_ui.pkgInfo.hide()
if isinstance(self._pkg_meta, dict):
self._pkg_meta.clear()
@@ -719,54 +768,62 @@ class PkgInfoMenu(MenuSkel):
self.spawn_ugc_load(force = force)
def on_ugcRemoveButton_released(self, widget):
- if self.Entropy.UGC is None:
- return
if self.repository is None:
return
+ if self._webserv is None:
+ return
model, myiter = self.ugcView.get_selection().get_selected()
if myiter is None:
return
- obj = model.get_value( myiter, 0 )
- if not isinstance(obj, dict):
- return
- if 'is_cat' in obj:
+ doc = model.get_value( myiter, 0 )
+ if not isinstance(doc, Document):
return
+
+ document_id = doc.document_id()
self.show_loading()
- self.Entropy.UGC.remove_document_autosense(
- self.repository, int(obj['iddoc']), obj['iddoctype'])
- self.hide_loading()
- self.reset_ugc_data()
- self.spawn_ugc_load(force = True)
- SulfurSignals.emit('ugc_cache_clear')
- self.refresh_ugc_view()
+ with Privileges():
+ try:
+ # requires authentication
+ removed = self._webserv.remove_document(document_id)
+ except WebService.AuthenticationRequired:
+ gobject.idle_add(self._ugc_login)
+ removed = False
+ except WebService.WebServiceException:
+ removed = False
+ finally:
+ self.hide_loading()
+
+ if removed:
+ self.ugc_data = None
+ self.spawn_ugc_load(force = True)
+ SulfurSignals.emit('ugc_cache_clear')
+ self.refresh_ugc_view()
def on_ugc_doubleclick(self, widget, path, view):
self.on_ugcShowButton_clicked(widget)
def on_ugcShowButton_clicked(self, widget):
- if self.Entropy.UGC is None:
- return
if self.repository is None:
return
+ if self._webserv is None:
+ return
model, myiter = self.ugcView.get_selection().get_selected()
if myiter is None:
return
obj = model.get_value( myiter, 0 )
- if not isinstance(obj, dict):
+ if not isinstance(obj, Document):
return
- if 'is_cat' in obj:
- return
- my = UGCInfoMenu(self.Entropy, obj, self.repository,
+ my = UGCInfoMenu(self.Entropy, obj, self.pkgkey, self.repository,
self.pkginfo_ui.pkgInfo)
my.load()
def on_ugcAddButton_clicked(self, widget):
- if self.Entropy.UGC is None:
- return
if self.repository is None:
return
if self.pkgkey is None:
return
+ if self._webserv is None:
+ return
my = UGCAddMenu(self.Entropy, self.pkgkey, self.repository,
self.pkginfo_ui.pkgInfo, self.refresh_view_cb)
my.load()
@@ -775,10 +832,6 @@ class PkgInfoMenu(MenuSkel):
self.spawn_ugc_load(force = True)
SulfurSignals.emit('ugc_cache_clear')
- def reset_ugc_data(self):
- del self.ugc_data
- self.ugc_data = None
-
def show_loading(self):
self.pkginfo_ui.ugcButtonBox.hide()
self.pkginfo_ui.loadUgcButton.set_sensitive(False)
@@ -797,132 +850,159 @@ class PkgInfoMenu(MenuSkel):
self.pkginfo_ui.loadUgcButton.set_sensitive(True)
self.pkginfo_ui.ugcButtonBox.show_all()
- def ugc_metadata_fetch(self, force = False):
- if self.Entropy.UGC is None:
- return
+ def __get_docs_loop(self, force):
+ docs = []
+ docs_offset = 0
+ with Privileges():
+ while True:
+ try:
+ docs_list = self._webserv.get_documents([self.pkgkey],
+ cache = not force, cached = not force,
+ offset = docs_offset)[self.pkgkey]
+ except WebService.CacheMiss:
+ return None
+ except WebService.WebServiceException:
+ return None
+ if docs_list is None:
+ # wtf!
+ return None
+ docs.extend(docs_list)
+ if not docs_list.has_more():
+ break
+ docs_offset += len(docs_list)
+ return docs
- docs_data = None
+ def ugc_metadata_fetch(self, force = False):
+ if self._webserv is None:
+ return []
+
+ docs = None
if not force:
- docs_data = self.Entropy.UGC.UGCCache.get_alldocs_cache(
- self.pkgkey, self.repository)
- if docs_data is None:
- docs_data, err_msg = self.Entropy.UGC.get_docs(
- self.repository, self.pkgkey)
- return docs_data
+ docs = self.__get_docs_loop(False)
+ if docs is None:
+ docs = self.__get_docs_loop(True)
+ return docs
def spawn_ugc_load(self, force = False):
if (self.ugc_data != None) and (not force):
return
- if self.Entropy.UGC is None:
- return
if not (self.pkgkey and self.repository):
return
self.show_loading()
-
try:
- docs_data = self.ugc_metadata_fetch(force = force)
- except TimeoutError:
- dialog_title = _("Timeout Error")
- err_msg = _("Connection timed out, sorry!")
- docs_data = None
- okDialog(self.window, err_msg, title = dialog_title)
+ docs = self.ugc_metadata_fetch(force = force)
+ if docs is None:
+ self.ugc_data = None
+ else:
+ doc_map = {}
+ for doc in docs:
+ doc_type = doc.document_type()
+ obj = doc_map.setdefault(doc_type, [])
+ obj.append(doc)
+ self.ugc_data = doc_map
- if not isinstance(docs_data, (list, tuple)):
- self.ugc_data = {}
- else:
- self.ugc_data = self.digest_remote_docs_data(docs_data)
-
- self.refresh_ugc_view()
- self.setup_ugc_icon()
- self.hide_loading()
-
- def digest_remote_docs_data(self, data):
- newdata = {}
- for mydict in data:
- if not mydict:
- continue
- if mydict['iddoctype'] not in newdata:
- newdata[mydict['iddoctype']] = []
- newdata[mydict['iddoctype']].append(mydict)
- return newdata
+ self.refresh_ugc_view()
+ th = ParallelTask(self.setup_ugc_icon)
+ th.start()
+ finally:
+ self.hide_loading()
def refresh_ugc_view(self):
self.ugcModel.clear()
if self.ugc_data is None:
return
self.populate_ugc_view()
- #self.ugcView.expand_all()
def prefetch_ugc_icon(self):
- def update_ugc_icon():
- self.setup_ugc_icon()
- return False
def do_ugc_fetch():
- try:
- self.ugc_metadata_fetch()
- except TimeoutError:
- return
- fork_function(do_ugc_fetch, update_ugc_icon)
+ self.ugc_metadata_fetch()
+ self.setup_ugc_icon()
+ th = ParallelTask(do_ugc_fetch)
+ th.start()
def setup_ugc_icon(self):
"""
Setup UGC icon for package if UGC data has been already downloaded
and prepared by this class.
"""
-
- if self.Entropy.UGC is None:
+ if not (self.pkgkey and self.repository):
return
- const_debug_write(__name__, "setup_ugc_icon, UGC available")
- icon_doc = self.Entropy.UGC.UGCCache.get_icon_cache(
- self.pkgkey, self.repository)
- if icon_doc is None:
+ webserv = self._webserv
+ const_debug_write(__name__,
+ "setup_ugc_icon, WebService available: %s" % (webserv,))
+
+ # sorry web service, we need data this way
+ with Privileges():
+ try:
+ icon_docs = webserv.get_icons([self.pkgkey],
+ cache = True, cached = True)[self.pkgkey]
+ except WebService.CacheMiss:
+ icon_docs = None
+
+ if icon_docs is None:
+ # not in cache
return
+
const_debug_write(__name__,
"setup_ugc_icon, UGC metadata available in cache for (%s, %s): %s" % (
- self.pkgkey, self.repository, icon_doc,))
+ self.pkgkey, self.repository, icon_docs,))
+
+ # get the first available in cache
+ store_path = None
+ store_doc = None
+ for icon_doc in icon_docs:
+ local_path = icon_doc.local_document()
+ if local_path is None:
+ continue
+ store_path = local_path
+ store_doc = icon_doc
+ # found a good one
+ break
- store_path = self.Entropy.UGC.UGCCache.get_stored_document(
- icon_doc['iddoc'], self.repository, icon_doc['store_url'])
const_debug_write(__name__,
"setup_ugc_icon, UGC store path for (%s, %s): %s" % (
self.pkgkey, self.repository, store_path,))
if store_path is None:
+ # cannot get any valid store path
+ return
- # fetch from WWW if not available
- self.Entropy.UGC.UGCCache.store_document(icon_doc['iddoc'],
- self.repository, icon_doc['store_url'])
- store_path = self.Entropy.UGC.UGCCache.get_stored_document(
- icon_doc['iddoc'], self.repository, icon_doc['store_url'])
+ if not (os.path.isfile(store_path) and os.access(store_path, os.R_OK)):
+ # fetch from WWW
+ with Privileges():
+ try:
+ store_path = webserv.get_document_url(store_doc)
+ except ClientWebService.DocumentError:
+ store_path = None
const_debug_write(__name__,
"setup_ugc_icon, UGC store path fetched for (%s, %s): %s" % (
self.pkgkey, self.repository, store_path,))
+ else:
+ const_debug_write(__name__,
+ "setup_ugc_icon, UGC store path "
+ "available in cache for (%s, %s)" % (
+ self.pkgkey, self.repository,))
if store_path is None:
- # cannot get store path
+ # meh!
+ return
+ if self._ugc_icon_store_path == store_path:
+ # meh! 2
return
- if not (os.access(store_path, os.R_OK) and os.path.isfile(store_path)):
- return
-
- const_debug_write(__name__,
- "setup_ugc_icon, UGC store path available in cache for (%s, %s)" % (
- self.pkgkey, self.repository,))
-
- if self._ugc_icon_store_path != store_path:
- self._ugc_icon_store_path = store_path
- # if image has __icon__ as title, use as real icon
- icon_path = store_path + ".sulfur_icon"
- if not (os.path.isfile(icon_path) and os.access(icon_path, os.R_OK)):
- try:
- resize_image(48.0, store_path, icon_path)
- except (ValueError, OSError,):
- # image should be a GdkPixbuf or empty
- return # wtf!
- self.pkginfo_ui.pkgImage.set_from_file(icon_path)
+ self._ugc_icon_store_path = store_path
+ # if image has __icon__ as title, use as real icon
+ icon_path = store_path + ".sulfur_icon"
+ if not (os.path.isfile(icon_path) and os.access(icon_path, os.R_OK)):
+ try:
+ resize_image(48.0, store_path, icon_path)
+ except (ValueError, OSError,):
+ # image should be a GdkPixbuf or empty
+ return # wtf!
+ gobject.idle_add(self.pkginfo_ui.pkgImage.set_from_file, icon_path)
def spawn_docs_fetch(self):
@@ -930,36 +1010,40 @@ class PkgInfoMenu(MenuSkel):
return
if self.repository is None:
return
+ if self._webserv is None:
+ return
- for doc_type in self.ugc_data:
- if int(doc_type) not in (etpConst['ugc_doctypes']['image'],):
+ try:
+ docs_map = self.ugc_data.copy()
+ except AttributeError:
+ # must be concurrency-free
+ return
+
+ for doc_type, docs in docs_map.items():
+
+ if doc_type not in (Document.IMAGE_TYPE_ID, Document.ICON_TYPE_ID):
continue
- for mydoc in self.ugc_data[doc_type]:
- if 'store_url' not in mydoc:
- continue
- if not mydoc['store_url']:
- continue
- store_path = self.Entropy.UGC.UGCCache.get_stored_document(
- mydoc['iddoc'], self.repository, mydoc['store_url'])
+ for mydoc in docs:
+ with Privileges():
+ try:
+ store_path = self._webserv.get_document_url(mydoc)
+ except ClientWebService.DocumentError:
+ store_path = None
if store_path is None:
- try:
- self.Entropy.UGC.UGCCache.store_document(mydoc['iddoc'],
- self.repository, mydoc['store_url'])
- except PermissionDenied:
- # not enough privileges
- continue
- store_path = self.Entropy.UGC.UGCCache.get_stored_document(
- mydoc['iddoc'], self.repository, mydoc['store_url'])
+ continue
+ if not (os.path.isfile(store_path) and \
+ os.access(store_path, os.R_OK)):
+ continue
- if (store_path != None) and os.access(store_path, os.R_OK):
- preview_path = store_path+".sulfur_preview"
- try:
- resize_image(64.0, store_path, preview_path)
- mydoc['preview_path'] = preview_path
- except (ValueError, OSError,):
- continue
+ preview_path = store_path+".sulfur_preview_height"
+ try:
+ resize_image_height(self._ugc_row_height - 4, store_path,
+ preview_path)
+ except (ValueError, OSError,):
+ continue
+ mydoc['preview_path'] = preview_path
def populate_ugc_view(self):
@@ -969,58 +1053,59 @@ class PkgInfoMenu(MenuSkel):
spawn_fetch = False
doc_types = list(self.ugc_data.keys())
doc_type_image_map = {
- 1: const.ugc_text_pix,
- 2: const.ugc_text_pix,
- 3: const.ugc_image_pix,
- 4: const.ugc_generic_pix,
- 5: const.ugc_video_pix,
+ Document.COMMENT_TYPE_ID: const.ugc_text_pix,
+ Document.IMAGE_TYPE_ID: const.ugc_image_pix,
+ Document.FILE_TYPE_ID: const.ugc_generic_pix,
+ Document.VIDEO_TYPE_ID: const.ugc_video_pix,
+ Document.ICON_TYPE_ID: const.ugc_image_pix,
}
doc_type_background_map = {
- 1: ('#67AB6F', '#599360'),
- 2: ('#67AB6F', '#599360'),
- 3: ('#AB8158', '#CA9968'),
- 4: ('#BBD5B0', '#99AE90'),
- 5: ('#A5C0D5', '#8EA5B7'),
+ Document.COMMENT_TYPE_ID: ('#67AB6F', '#599360'),
+ Document.IMAGE_TYPE_ID: ('#AB8158', '#CA9968'),
+ Document.FILE_TYPE_ID: ('#BBD5B0', '#99AE90'),
+ Document.VIDEO_TYPE_ID: ('#A5C0D5', '#8EA5B7'),
+ Document.ICON_TYPE_ID: ('#AB8158', '#CA9968'),
}
doc_type_foreground_map = {
- 1: '#FFFFFF',
- 2: '#FFFFFF',
- 3: '#FFFFFF',
- 4: '#FFFFFF',
- 5: '#FFFFFF',
+ Document.COMMENT_TYPE_ID: '#FFFFFF',
+ Document.IMAGE_TYPE_ID: '#FFFFFF',
+ Document.FILE_TYPE_ID: '#FFFFFF',
+ Document.VIDEO_TYPE_ID: '#FFFFFF',
+ Document.ICON_TYPE_ID: '#FFFFFF',
}
counter = 1
for doc_type in doc_types:
spawn_fetch = True
- image_path = doc_type_image_map.get(int(doc_type))
+ image_path = doc_type_image_map.get(doc_type)
cat_dict = {
'is_cat': True,
'image_path': image_path,
'parent_desc': "%s (%s)" % (
- etpConst['ugc_doctypes_description'].get(int(doc_type)),
+ Document.DESCRIPTION_PLURAL.get(doc_type, _("N/A")),
len(self.ugc_data[doc_type]),),
- 'foreground': doc_type_foreground_map.get(int(doc_type)),
- 'background': doc_type_background_map.get(int(doc_type)),
+ 'foreground': doc_type_foreground_map.get(doc_type),
+ 'background': doc_type_background_map.get(doc_type),
}
parent = self.ugcModel.append( None, (cat_dict,) )
docs_dates = {}
for mydoc in self.ugc_data[doc_type]:
ts = mydoc['ts']
- if ts not in docs_dates:
- docs_dates[ts] = []
- docs_dates[ts].append(mydoc)
+ lst = docs_dates.setdefault(ts, [])
+ lst.append(mydoc)
+
sorted_dates = sorted(docs_dates.keys())
for ts in sorted_dates:
for mydoc in docs_dates[ts]:
mydoc['image_path'] = const.ugc_pixmap_small
- mydoc['foreground'] = doc_type_foreground_map.get(int(doc_type))
- mydoc['background'] = doc_type_background_map.get(int(doc_type))
+ mydoc['foreground'] = doc_type_foreground_map.get(doc_type)
+ mydoc['background'] = doc_type_background_map.get(doc_type)
mydoc['counter'] = counter
self.ugcModel.append( parent, (mydoc,) )
counter += 1
if spawn_fetch:
- gobject.idle_add(self.spawn_docs_fetch)
+ th = ParallelTask(self.spawn_docs_fetch)
+ th.start()
self.ugcView.set_property('headers-visible', True)
self.ugcView.set_property('enable-search', True)
@@ -1232,21 +1317,89 @@ class PkgInfoMenu(MenuSkel):
def on_starEvent1_button_release_event(self, widget, event):
self.vote_click(1)
+ def _ugc_login(self):
+ if self.repository is None:
+ return False
+ if self._webserv is None:
+ return False
+
+ def fake_callback(*args, **kwargs):
+ return True
+
+ # use input box to read login
+ input_params = [
+ ('username', _('Username'), fake_callback, False),
+ ('password', _('Password'), fake_callback, True)
+ ]
+ login_data = self.Entropy.input_box(
+ "%s %s %s" % (
+ _('Please login against'), self.repository, _('repository'),),
+ input_params,
+ cancel_button = True
+ )
+ if not login_data:
+ return False
+
+ username, password = login_data['username'], login_data['password']
+ with Privileges():
+ self._webserv.add_credentials(username, password)
+ try:
+ self._webserv.validate_credentials()
+ except WebService.AuthenticationFailed:
+ okDialog(self.window,
+ _("Authentication error. Not logged in."))
+ return False
+
+ okDialog(self.window,
+ _("Successfully logged in."))
+ return True
+
def vote_click(self, vote):
- if self.Entropy.UGC is None:
- return
if not (self.repository and self.pkgkey):
return
- if not self.Entropy.UGC.is_repository_eapi3_aware(self.repository):
- return
- status, err_msg = self.Entropy.UGC.add_vote(self.repository, self.pkgkey, vote)
- if status:
- self.set_stars_from_repository()
- msg = "%s: %s" % (SulfurConf.color_good, _("Vote registered successfully"), vote,)
- else:
- msg = "%s: %s" % (SulfurConf.color_error, _("Error registering vote"), err_msg,)
- self.pkginfo_ui.ugcMessageBox.set_markup(msg)
+ def _do_vote():
+ if self._webserv is None:
+ return
+ with Privileges():
+ try:
+ voted = self._webserv.add_vote(self.pkgkey, vote)
+ except WebService.AuthenticationRequired:
+ def _do_login():
+ logged_in = self._ugc_login()
+ if logged_in:
+ # call myself again
+ gobject.idle_add(self.vote_click, vote)
+ return False
+ gobject.idle_add(_do_login)
+ return
+
+ if voted:
+ # inform user first
+ msg = "%s: %s" % (
+ SulfurConf.color_good,
+ _("Vote registered successfully"), vote,)
+ else:
+ msg = "%s: %s" % (
+ SulfurConf.color_error, _("Error"), _("Already voted"),)
+ gobject.idle_add(self.pkginfo_ui.ugcMessageBox.set_markup, msg)
+ if voted:
+ with Privileges():
+ # need to refill local cache
+ done = True
+ try:
+ self._webserv.get_votes([self.pkgkey], cache = False)
+ except WebService.WebServiceException as err:
+ # ouch! drop everything completely
+ self._webserv._drop_cached("get_votes")
+ done = False
+
+ if done:
+ gobject.idle_add(self.set_stars_from_repository)
+
+ th = ParallelTask(_do_vote)
+ th.start()
+
def star_enter(self, widget, event, number):
self.set_stars(number, hover = True)
@@ -1347,7 +1500,7 @@ class PkgInfoMenu(MenuSkel):
# Setup image column
cell = gtk.CellRendererPixbuf()
- cell.set_property('height', 78)
+ cell.set_property('height', self._ugc_row_height)
column = gtk.TreeViewColumn( _("Type"), cell ) # Document Type
column.set_cell_data_func( cell, self.ugc_pixbuf )
column.set_sizing( gtk.TREE_VIEW_COLUMN_FIXED )
@@ -1356,15 +1509,17 @@ class PkgInfoMenu(MenuSkel):
self.ugcView.append_column( column )
cell = gtk.CellRendererText()
- column = gtk.TreeViewColumn( _( "Content" ), cell )
- column.set_resizable( True )
- column.set_cell_data_func( cell, self.ugc_content )
- column.set_sizing( gtk.TREE_VIEW_COLUMN_FIXED )
- column.set_fixed_width( 350 )
+ cell.set_property('wrap-mode', gtk.WRAP_WORD)
+ cell.set_property('wrap-width', 340)
+ column = gtk.TreeViewColumn(_( "Content" ), cell)
+ column.set_resizable(True)
+ column.set_cell_data_func(cell, self.ugc_content)
+ column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
+ column.set_fixed_width(350)
column.set_expand(True)
- column.set_sort_column_id( -1 )
- self.ugcView.append_column( column )
- self.ugcView.set_model( self.ugcModel )
+ column.set_sort_column_id(-1)
+ self.ugcView.append_column(column)
+ self.ugcView.set_model(self.ugcModel)
self.ugcView.set_property('headers-visible', True)
self.ugcView.set_property('enable-search', True)
@@ -1436,24 +1591,17 @@ class PkgInfoMenu(MenuSkel):
# set package image
pkgatom = self._pkg_meta['atom']
- self.vote = int(pkg.vote)
+ self.vote = int(pkg.votefloat)
self.repository = pkg.repoid
self.pkgkey = entropy.dep.dep_getkey(pkgatom)
self.set_stars_from_repository()
self.pkginfo_ui.pkgImage.set_from_file(self.pkg_pixmap)
self.pkginfo_ui.ugcSmallIcon.set_from_file(self.ugc_small_pixmap)
- self.pkginfo_ui.ugcIcon.set_from_file(self.ugc_pixmap)
- self.pkginfo_ui.refreshImage.set_from_file(self.refresh_pixmap)
self.pkginfo_ui.labelAtom.set_markup("%s" % (
cleanMarkupString(pkgatom),))
self.pkginfo_ui.labelDescription.set_markup("%s" % (
cleanMarkupString(self._pkg_meta['description']),))
- self.pkginfo_ui.ugcDescriptionLabel.set_markup("%s\n%s" % (
- _("Share your opinion, your documents, your screenshots!"),
- _("Be part of our Community!")
- )
- )
self.set_download_numbers_from_repository()
bold_items = [ self.pkginfo_ui.locationLabel,
@@ -1475,7 +1623,6 @@ class PkgInfoMenu(MenuSkel):
self.pkginfo_ui.maskedLabel,
self.pkginfo_ui.triggerLabel,
self.pkginfo_ui.configProtectLabel,
- self.pkginfo_ui.ugcTitleLabel,
self.pkginfo_ui.changeLogLabel
]
for item in bold_items:
@@ -1718,14 +1865,13 @@ class SecurityAdvisoryMenu(MenuSkel):
class UGCInfoMenu(MenuSkel):
- def __init__(self, Entropy, obj, repository, window):
+ def __init__(self, Entropy, obj, package_name, repository, window):
- import subprocess
- self.subprocess = subprocess
+ self.package_name = package_name
self.repository = repository
self.window = window
self.Entropy = Entropy
- self.ugc_data = obj.copy()
+ self.ugc_doc = obj
self.ugcinfo_ui = UI( const.GLADE_FILE, 'ugcInfo', 'entropy' )
self.ugcinfo_ui.signal_autoconnect(self._getAllMethods())
self.ugcinfo_ui.ugcInfo.set_transient_for(self.window)
@@ -1736,49 +1882,62 @@ class UGCInfoMenu(MenuSkel):
return True
def on_getButton_clicked(self, widget):
- if self.ugc_data['store_url'] != None:
- load_url(self.ugc_data['store_url'])
+ url = self.ugc_doc.document_url()
+ if url is not None:
+ load_url(url)
def load(self):
- pix_path = self.ugc_data['image_path']
- if self.ugc_data.get('preview_path') is not None:
- if os.path.isfile(self.ugc_data['preview_path']) and \
- os.access(self.ugc_data['preview_path'], os.R_OK):
- pix_path = self.ugc_data['preview_path']
+ pix_path = self.ugc_doc['image_path']
+ if self.ugc_doc.get('preview_path') is not None:
+ if os.path.isfile(self.ugc_doc['preview_path']) and \
+ os.access(self.ugc_doc['preview_path'], os.R_OK):
+ pix_path = self.ugc_doc['preview_path']
self.ugcinfo_ui.ugcImage.set_from_file(pix_path)
self.ugcinfo_ui.labelKey.set_markup("%s" % (
- self.ugc_data['pkgkey'],))
- doc_type_desc = etpConst['ugc_doctypes_description_singular'].get(
- int(self.ugc_data['iddoctype']))
+ self.package_name,))
+ doc_type = self.ugc_doc.document_type()
+ doc_id = self.ugc_doc.document_id()
+
+ doc_type_desc = Document.DESCRIPTION_SINGULAR.get(doc_type, _("N/A"))
self.ugcinfo_ui.labelTypedesc.set_markup(
"[%s:%d] %s" % (
_("Id"),
- int(self.ugc_data['iddoc']),
+ doc_id,
doc_type_desc,
)
)
+ title = self.ugc_doc.get(Document.DOCUMENT_TITLE_ID, _("N/A"))
+ description = self.ugc_doc.get(Document.DOCUMENT_DESCRIPTION_ID,
+ _("N/A"))
+ username = self.ugc_doc.get(DocumentFactory.DOCUMENT_USERNAME_ID,
+ _("N/A"))
+ keywords = self.ugc_doc.document_keywords().strip().split()
+ ts = self.ugc_doc.document_timestamp()
+ ts = entropy.tools.convert_unix_time_to_human_time(ts)
+
self.ugcinfo_ui.titleContent.set_markup("%s" % (
- const_convert_to_unicode(self.ugc_data['title']),))
+ cleanMarkupString(const_convert_to_unicode(title)),))
self.ugcinfo_ui.descriptionContent.set_markup("%s" % (
- const_convert_to_unicode(self.ugc_data['description']),))
+ cleanMarkupString(const_convert_to_unicode(description)),))
self.ugcinfo_ui.authorContent.set_markup("%s" % (
- const_convert_to_unicode(self.ugc_data['username']),))
+ cleanMarkupString(const_convert_to_unicode(username)),))
self.ugcinfo_ui.dateContent.set_markup(
- "%s" % (self.ugc_data['ts'],))
- self.ugcinfo_ui.keywordsContent.set_markup("%s" % (
- const_convert_to_unicode(', '.join(self.ugc_data['keywords'])),))
- self.ugcinfo_ui.sizeContent.set_markup("%s" % (
- entropy.tools.bytes_into_human(self.ugc_data['size']),))
+ "%s" % (cleanMarkupString(ts),))
+ if keywords:
+ keywords_str = ", ".join(keywords)
+ self.ugcinfo_ui.keywordsContent.set_markup("%s" % (
+ cleanMarkupString(const_convert_to_unicode(keywords_str)),))
+ else:
+ self.ugcinfo_ui.keywordsContent.set_markup(_("No keywords"))
bold_items = [
self.ugcinfo_ui.titleLabel,
self.ugcinfo_ui.descLabel,
self.ugcinfo_ui.authorLabel,
self.ugcinfo_ui.dateLabel,
- self.ugcinfo_ui.keywordsLabel,
- self.ugcinfo_ui.sizeLabel
+ self.ugcinfo_ui.keywordsLabel
]
for item in bold_items:
t = item.get_text()
@@ -1790,17 +1949,13 @@ class UGCInfoMenu(MenuSkel):
self.ugcinfo_ui.descriptionContent,
self.ugcinfo_ui.authorContent,
self.ugcinfo_ui.dateContent,
- self.ugcinfo_ui.keywordsContent,
- self.ugcinfo_ui.sizeContent
+ self.ugcinfo_ui.keywordsContent
]
for item in small_items:
t = item.get_label()
item.set_markup("%s" % (t,))
- if self.ugc_data['iddoctype'] in (
- etpConst['ugc_doctypes']['comments'],
- etpConst['ugc_doctypes']['bbcode_doc'],):
-
+ if self.ugc_doc.is_comment():
self.ugcinfo_ui.ugcTable.remove(self.ugcinfo_ui.descLabel)
self.ugcinfo_ui.ugcTable.remove(self.ugcinfo_ui.descriptionContent)
self.ugcinfo_ui.buttonBox.hide()
@@ -1808,13 +1963,9 @@ class UGCInfoMenu(MenuSkel):
###
# we need to properly handle raw data coming from ddata dict key
###
- if const_isunicode(self.ugc_data['ddata']):
- buf_text = self.ugc_data['ddata']
- elif const_israwstring(self.ugc_data['ddata']):
- buf_text = const_convert_to_unicode(self.ugc_data['ddata'])
- else: # mysql shitty type?
- buf_text = const_convert_to_unicode(self.ugc_data['ddata'].tostring())
- mybuf.set_text(buf_text)
+ comment = self.ugc_doc.document_data()
+ comment = const_convert_to_unicode(comment)
+ mybuf.set_text(comment)
self.ugcinfo_ui.textContent.set_buffer(mybuf)
else:
self.ugcinfo_ui.textFrame.hide()
@@ -1824,8 +1975,6 @@ class UGCInfoMenu(MenuSkel):
class UGCAddMenu(MenuSkel):
- DOC_TYPES_LIST = sorted(etpConst['ugc_doctypes_description_singular'])
-
def __init__(self, Entropy, pkgkey, repository, window, refresh_cb):
self.loading_pix = gtk.image_new_from_file(const.loading_pix)
@@ -1842,7 +1991,7 @@ class UGCAddMenu(MenuSkel):
self.ugcadd_ui.ugcAdd.add_events(gtk.gdk.BUTTON_PRESS_MASK)
self.store = None
self.refresh_cb = refresh_cb
- self.text_types = (etpConst['ugc_doctypes']['comments'], etpConst['ugc_doctypes']['bbcode_doc'],)
+ self.text_types = [Document.COMMENT_TYPE_ID]
self.file_selected = None
self._combo_doc_types = []
@@ -1854,16 +2003,50 @@ class UGCAddMenu(MenuSkel):
myiter = widget.get_active_iter()
idx = self.store.get_value( myiter, 0 )
if idx in self.text_types:
- txt = "%s %s" % (_("Write your"), etpConst['ugc_doctypes_description_singular'][idx],) # write your
- self.setup_text_insert()
+ desc = Document.DESCRIPTION_SINGULAR[idx]
+ txt = "%s %s" % (_("Write your"), desc,)
+ self.setup_text_insert(txt)
else:
- txt = "%s %s" % (_("Select your"), etpConst['ugc_doctypes_description_singular'][idx],) # select your
+ desc = Document.DESCRIPTION_SINGULAR[idx]
+ txt = "%s %s" % (_("Select your"), desc,)
self.setup_file_insert(txt)
def on_ugcAddFileChooser_file_set(self, widget):
self.file_selected = widget.get_filename()
+ def _ugc_login(self, webserv):
+
+ def fake_callback(*args, **kwargs):
+ return True
+
+ # use input box to read login
+ input_params = [
+ ('username', _('Username'), fake_callback, False),
+ ('password', _('Password'), fake_callback, True)
+ ]
+ login_data = self.Entropy.input_box(
+ "%s %s %s" % (
+ _('Please login against'), self.repository, _('repository'),),
+ input_params,
+ cancel_button = True
+ )
+ if not login_data:
+ return False
+
+ username, password = login_data['username'], login_data['password']
+ with Privileges():
+ webserv.add_credentials(username, password)
+ try:
+ webserv.validate_credentials()
+ except WebService.AuthenticationFailed:
+ okDialog(self.window,
+ _("Authentication error. Not logged in."))
+ return False
+
+ return True
+
def on_submitButton_clicked(self, widget):
+
dialog_title = _("Submit issue")
myiter = self.ugcadd_ui.ugcAddTypeCombo.get_active_iter()
doc_type = self.store.get_value( myiter, 0 )
@@ -1877,20 +2060,24 @@ class UGCAddMenu(MenuSkel):
end_iter = mybuf.get_end_iter()
description = mybuf.get_text(start_iter, end_iter)
if not description:
- okDialog(self.window, _("Empty Document"), title = dialog_title)
+ okDialog(self.window, _("Empty Document"),
+ title = dialog_title)
return False
else:
if not description:
- okDialog(self.window, _("Invalid Description"), title = dialog_title)
+ okDialog(self.window, _("Invalid Description"),
+ title = dialog_title)
return False
doc_path = self.file_selected
# checking
if doc_type is None:
- okDialog(self.window, _("Invalid Document Type"), title = dialog_title)
+ okDialog(self.window, _("Invalid Document Type"),
+ title = dialog_title)
return False
if not title:
- okDialog(self.window, _("Invalid Title"), title = dialog_title)
+ okDialog(self.window, _("Invalid Title"),
+ title = dialog_title)
return False
# confirm ?
@@ -1900,68 +2087,125 @@ class UGCAddMenu(MenuSkel):
self.show_loading()
- old_show_progress = self.Entropy.UGC.show_progress
- self.Entropy.UGC.show_progress = True
- bck_output = self.Entropy.output
- self.Entropy.output = self.do_label_update_progress
try:
- t = ParallelTask(self.do_send_document_autosense, doc_type, doc_path, title, description, keywords_text)
- t.start()
- while True:
- if not t.isAlive(): break
- while gtk.events_pending():
- gtk.main_iteration()
- time.sleep(0.06)
- rslt, data = t.get_rc()
- finally:
- self.Entropy.UGC.show_progress = old_show_progress
- self.Entropy.output = bck_output
-
-
- self.hide_loading()
- if not rslt:
- txt = "%s: %s | %s" % (SulfurConf.color_error, _("UGC Error"), rslt, data,)
- self.ugcadd_ui.ugcAddStatusLabel.set_markup(txt)
+ webserv = get_entropy_webservice(self.Entropy, self.repository)
+ except WebService.UnsupportedService as err:
+ okDialog(self.window, _("Unsupported Service"),
+ title = dialog_title)
return False
- else:
- okDialog(self.ugcadd_ui.ugcAdd, _("Document added successfully. Thank you"), title = _("Success!"))
- self.on_closeAdd_clicked(None, None)
- self.refresh_cb()
- return True
- def do_label_update_progress(self, *myargs, **mykwargs):
-
- count = mykwargs.get("count")
- percent = mykwargs.get("percent")
- text = myargs[0].encode('utf-8')
-
- count_str = ""
- if count:
- if len(count) > 1:
- if percent:
- count_str = " ("+str(round((float(count[0])/count[1])*100, 1))+"%) "
- else:
- count_str = " (%s/%s) " % (str(count[0]), str(count[1]),)
-
- txt = count_str+text
- txt = decolorize(txt)
- self.ugcadd_ui.ugcAddStatusLabel.set_markup(cleanMarkupString(txt))
-
- def do_send_document_autosense(self, doc_type, doc_path, title, description, keywords_text):
try:
- rslt, data = self.Entropy.UGC.send_document_autosense(
- self.repository,
- str(self.pkgkey),
- doc_type,
- doc_path,
- title,
- description,
- keywords_text
- )
- except Exception as e:
- rslt = False
- data = e
- return rslt, data
+ available = webserv.service_available()
+ except WebService.WebServiceException:
+ okDialog(self.window, _("Service is unavailable"),
+ title = dialog_title)
+ return False
+ if not available:
+ okDialog(self.window, _("Service is unavailable"),
+ title = dialog_title)
+ return False
+
+ with Privileges():
+ # ask user to login
+ need_login = False
+ if webserv.credentials_available():
+ try:
+ webserv.validate_credentials()
+ except WebService.AuthenticationFailed:
+ need_login = True
+ else:
+ need_login = True
+
+ if need_login:
+ logged_in = self._ugc_login(webserv)
+ if not logged_in:
+ return False
+
+ # can't be None
+ username = webserv.get_credentials()
+ webserv._set_transfer_callback(self.do_label_update_progress)
+
+ # Build up the Document object
+ doc_factory = DocumentFactory(self.repository)
+
+ doc_f = None
+ try:
+ if doc_type == Document.COMMENT_TYPE_ID:
+ doc = doc_factory.comment(username, description,
+ title, keywords_text)
+ elif doc_type == Document.ICON_TYPE_ID:
+ doc_f = open(doc_path, "rb")
+ doc = doc_factory.icon(username, doc_f, title,
+ description, keywords_text)
+ elif doc_type == Document.FILE_TYPE_ID:
+ doc_f = open(doc_path, "rb")
+ doc = doc_factory.file(username, doc_f, title,
+ description, keywords_text)
+ elif doc_type == Document.IMAGE_TYPE_ID:
+ doc_f = open(doc_path, "rb")
+ doc = doc_factory.image(username, doc_f, title,
+ description, keywords_text)
+ elif doc_type == Document.VIDEO_TYPE_ID:
+ doc_f = open(doc_path, "rb")
+ doc = doc_factory.video(username, doc_f, title,
+ description, keywords_text)
+ else:
+ # WTF
+ raise AssertionError("invalid document type")
+ except AssertionError as err:
+ okDialog(self.window, "%s: %s" % (_("Invalid fields"), err),
+ title = dialog_title)
+ if doc_f is not None:
+ doc_f.close()
+ doc_f = None
+ return False
+
+ def _do_add_document(doc, doc_f):
+ err_msg = None
+ try:
+ new_doc = webserv.add_document(self.pkgkey, doc)
+ except WebService.WebServiceException as err:
+ new_doc = None
+ err_msg = str(err)
+ finally:
+ if doc_f is not None:
+ doc_f.close()
+ gobject.idle_add(self.hide_loading)
+
+ if new_doc is not None:
+ def _happy_ending():
+ okDialog(self.ugcadd_ui.ugcAdd,
+ _("Document added successfully. Thank you"),
+ title = _("Success!"))
+ self.on_closeAdd_clicked(None, None)
+ self.refresh_cb()
+ return False
+ gobject.idle_add(_happy_ending)
+ else:
+ def _unhappy_ending():
+ txt = "%s: %s" % (
+ SulfurConf.color_error, _("UGC Error"), err_msg,)
+ self.ugcadd_ui.ugcAddStatusLabel.set_markup(txt)
+ return False
+ gobject.idle_add(_unhappy_ending)
+
+ th = ParallelTask(_do_add_document, doc, doc_f)
+ th.start()
+ return False
+
+ def do_label_update_progress(self, transfered, total, download):
+
+ if download:
+ action = _("Downloading")
+ else:
+ action = _("Uploading")
+
+ percent = 100
+ if (total > 0) and (transfered <= total):
+ percent = int(round((float(transfered)/total) * 100, 1))
+
+ msg = cleanMarkupString("[%s%s] %s ..." % (percent, "%", action))
+ gobject.idle_add(self.ugcadd_ui.ugcAddStatusLabel.set_markup, msg)
def show_loading(self):
self.ugcadd_ui.ugcAddButtonBox.hide()
@@ -1995,13 +2239,15 @@ class UGCAddMenu(MenuSkel):
self.ugcadd_ui.ugcAddInsertLabel.set_markup(txt)
def prepare_image_insert(self, pkg_name, image_path, as_icon = False):
- image_doctype = etpConst['ugc_doctypes']['image']
+ doc_type = Document.IMAGE_TYPE_ID
+ if as_icon:
+ doc_type = Document.ICON_TYPE_ID
self.ugcadd_ui.ugcAddTypeCombo.set_active(
- self._combo_doc_types.index(image_doctype))
+ self._combo_doc_types.index(doc_type))
self.ugcadd_ui.ugcAddFileChooser.set_filename(image_path)
self.file_selected = image_path
if as_icon:
- self.ugcadd_ui.ugcAddTitleEntry.set_text("__icon__")
+ self.ugcadd_ui.ugcAddTitleEntry.set_text(pkg_name + " icon")
self.ugcadd_ui.ugcAddDescEntry.set_text("This is the %s icon" % (
pkg_name,))
else:
@@ -2011,9 +2257,8 @@ class UGCAddMenu(MenuSkel):
pkg_name,))
def prepare_file_insert(self, pkg_name, file_path):
- file_doctype = etpConst['ugc_doctypes']['generic_file']
self.ugcadd_ui.ugcAddTypeCombo.set_active(
- self._combo_doc_types.index(file_doctype))
+ self._combo_doc_types.index(Document.FILE_TYPE_ID))
self.ugcadd_ui.ugcAddFileChooser.set_filename(file_path)
self.file_selected = file_path
self.ugcadd_ui.ugcAddTitleEntry.set_text("%s document" % (
@@ -2029,19 +2274,15 @@ class UGCAddMenu(MenuSkel):
_("On repository"), self.repository,))
# add types to combo
- doc_types_list = UGCAddMenu.DOC_TYPES_LIST
self.store = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
self.ugcadd_ui.ugcAddTypeCombo.set_model(self.store)
cell = gtk.CellRendererText()
self.ugcadd_ui.ugcAddTypeCombo.pack_start(cell, True)
self.ugcadd_ui.ugcAddTypeCombo.add_attribute(cell, 'text', 1)
del self._combo_doc_types[:]
- for idx in doc_types_list:
- # disable bbcode for now
- if idx == etpConst['ugc_doctypes']['bbcode_doc']:
- continue
+ for idx in Document.SUPPORTED_TYPES:
self._combo_doc_types.append(idx)
- self.store.append( (idx, etpConst['ugc_doctypes_description_singular'][idx],) )
+ self.store.append((idx, Document.DESCRIPTION_SINGULAR[idx],))
self.ugcadd_ui.ugcAddTypeCombo.set_active(0)
# hide file chooser
@@ -2063,7 +2304,7 @@ class UGCAddMenu(MenuSkel):
class MaskedPackagesDialog(MenuSkel):
- def __init__( self, Entropy, etpbase, parent, pkgs, top_text = None, sub_text = None ):
+ def __init__( self, Entropy, etpbase, parent, pkgs, top_text = None, sub_text = None):
self.pkgs = pkgs
self.pkgcount = 0
diff --git a/sulfur/src/sulfur/entropyapi.py b/sulfur/src/sulfur/entropyapi.py
index 91ead590e..c953ea766 100644
--- a/sulfur/src/sulfur/entropyapi.py
+++ b/sulfur/src/sulfur/entropyapi.py
@@ -25,10 +25,11 @@ except ImportError:
import _thread as thread
from sulfur.setup import const, SulfurConf
from sulfur.dialogs import LicenseDialog, okDialog, choiceDialog, inputDialog
+from sulfur.core import get_entropy_webservice
import gobject
# Entropy Imports
-from entropy.const import etpConst, etpUi
+from entropy.const import etpConst, etpUi, const_debug_write
from entropy.output import print_generic, nocolor, decolorize
from entropy.client.interfaces import Client
from entropy.fetchers import UrlFetcher
@@ -37,6 +38,7 @@ from entropy.misc import ParallelTask
from entropy.client.mirrors import StatusInterface
from entropy.exceptions import RepositoryError
from entropy.db.exceptions import OperationalError, IntegrityError
+from entropy.services.client import WebService
import entropy.dep
import entropy.tools
@@ -193,14 +195,22 @@ class QueueExecutor:
if not download_sources:
def spawn_ugc():
- try:
- if self._entropy.UGC != None:
- for myrepo in mykeys:
- mypkgkeys = sorted(mykeys[myrepo])
- self._entropy.UGC.add_download_stats(myrepo,
- mypkgkeys)
- except:
- pass
+ for myrepo, mykeys in mykeys.items():
+ try:
+ webserv = get_entropy_webservice(self._entropy,
+ myrepo)
+ except WebService.UnsupportedService:
+ continue
+ try:
+ avail = webserv.service_available()
+ except WebService.WebServiceException:
+ avail = False
+ if avail:
+ try:
+ webserv.add_downloads(sorted(mykeys))
+ except WebService.WebServiceException as err:
+ const_debug_write(__name__, repr(err))
+ continue
spawn_ugc()
def do_skip_hide():
@@ -315,8 +325,6 @@ class Equo(Client):
Client.init_singleton(self, *args, **kwargs)
self._progress_divider = 1
self.xcache = True # force xcache enabling
- if etpUi['debug']:
- self.UGC.quiet = False
self._mthread_rc = {
'ask_question': {},
'input_box': {},
diff --git a/sulfur/src/sulfur/events.py b/sulfur/src/sulfur/events.py
index b7c95f4c2..c41728c28 100644
--- a/sulfur/src/sulfur/events.py
+++ b/sulfur/src/sulfur/events.py
@@ -35,6 +35,7 @@ from entropy.output import print_generic
from entropy.i18n import _
from entropy.misc import ParallelTask
from entropy.client.mirrors import StatusInterface
+from entropy.services.client import WebService
import entropy.dump
from sulfur.filters import Filter
@@ -563,7 +564,8 @@ class SulfurApplicationEventsMixin:
do_clear_filter_bar = False
if action != self.lastPkgPB:
- do_clear_filter_bar = True
+ # disabled for now, users are complaining
+ do_clear_filter_bar = False
if action == "updates":
self.ui.updatesButtonbox.show()
@@ -813,46 +815,72 @@ class SulfurApplicationEventsMixin:
self.load_color_settings()
def on_ugcLoginButton_clicked(self, widget):
- if self._entropy.UGC == None: return
+ if not self._ugc_status:
+ return
model, myiter = self.ugcRepositoriesView.get_selection().get_selected()
- if (myiter == None) or (model == None): return
+ if (myiter == None) or (model == None):
+ return
obj = model.get_value( myiter, 0 )
if obj:
- #logged_data = self._entropy.UGC.read_login(obj['repoid'])
- self._entropy.UGC.login(obj['repoid'], force = True)
+ webserv = self._get_webservice(obj['repoid'])
+ if webserv is None:
+ return
+
+ def fake_callback(*args, **kwargs):
+ return True
+
+ # use input box to read login
+ input_params = [
+ ('username', _('Username'), fake_callback, False),
+ ('password', _('Password'), fake_callback, True)
+ ]
+ login_data = self._entropy.input_box(
+ "%s %s %s" % (
+ _('Please login against'), obj['repoid'], _('repository'),),
+ input_params,
+ cancel_button = True
+ )
+ if not login_data:
+ okDialog(self.ui.main, _("Login aborted. Not logged in."))
+ return
+
+ username, password = login_data['username'], login_data['password']
+ with self._privileges:
+ webserv.add_credentials(username, password)
+ try:
+ webserv.validate_credentials()
+ except WebService.AuthenticationFailed:
+ okDialog(self.ui.main,
+ _("Authentication error. Not logged in."))
+ return
self.load_ugc_repositories()
def on_ugcClearLoginButton_clicked(self, widget):
- if self._entropy.UGC == None: return
+ if not self._ugc_status:
+ return
model, myiter = self.ugcRepositoriesView.get_selection().get_selected()
- if (myiter == None) or (model == None): return
+ if (myiter == None) or (model == None):
+ return
obj = model.get_value( myiter, 0 )
if obj:
- if not self._entropy.UGC.is_repository_eapi3_aware(obj['repoid']):
+ webserv = self._get_webservice(obj['repoid'])
+ if webserv is None:
return
- logged_data = self._entropy.UGC.read_login(obj['repoid'])
- if logged_data: self._entropy.UGC.remove_login(obj['repoid'])
+ with self._privileges:
+ webserv.remove_credentials()
self.load_ugc_repositories()
- def on_ugcClearCacheButton_clicked(self, widget):
- if self._entropy.UGC == None: return
- repo_excluded = self._settings['repositories']['excluded']
- avail_repos = self._settings['repositories']['available']
- for repoid in list(set(list(avail_repos.keys())+list(repo_excluded.keys()))):
- self._entropy.UGC.UGCCache.clear_cache(repoid)
- self.set_status_ticker("%s: %s ..." % (_("Cleaning UGC cache of"), repoid,))
- self.set_status_ticker("%s" % (_("UGC cache cleared"),))
-
def on_ugcClearCredentialsButton_clicked(self, widget):
- if self._entropy.UGC == None:
+ if not self._ugc_status:
return
repo_excluded = self._settings['repositories']['excluded']
avail_repos = self._settings['repositories']['available']
for repoid in list(set(list(avail_repos.keys())+list(repo_excluded.keys()))):
- if not self._entropy.UGC.is_repository_eapi3_aware(repoid):
+ webserv = self._get_webservice(repoid)
+ if webserv is None:
continue
- logged_data = self._entropy.UGC.read_login(repoid)
- if logged_data: self._entropy.UGC.remove_login(repoid)
+ with self._privileges:
+ webserv.remove_credentials()
self.load_ugc_repositories()
self.set_status_ticker("%s" % (_("UGC credentials cleared"),))
diff --git a/sulfur/src/sulfur/package.py b/sulfur/src/sulfur/package.py
index f14197aa2..f3d56be0e 100644
--- a/sulfur/src/sulfur/package.py
+++ b/sulfur/src/sulfur/package.py
@@ -14,10 +14,15 @@ from entropy.const import *
from entropy.i18n import _
import entropy.dep
import entropy.tools
+from entropy.services.client import WebService
from sulfur.entropyapi import Equo
from sulfur.setup import cleanMarkupString, SulfurConf
+from sulfur.core import get_entropy_webservice
+
+
ENTROPY = Equo()
+WEBSERV_MAP = {}
class DummyEntropyPackage:
@@ -130,6 +135,25 @@ class EntropyPackage:
self.matched_atom = matched_atom
self.installed_match = None
+ def _get_webservice(self):
+
+ repository_id = self.get_repository_clean()
+ webserv = WEBSERV_MAP.get(repository_id)
+
+ if webserv == -1:
+ return None # not available
+ if webserv is not None:
+ return webserv
+
+ try:
+ webserv = get_entropy_webservice(ENTROPY, repository_id)
+ except WebService.UnsupportedService:
+ WEBSERV_MAP[repository_id] = -1
+ return None
+
+ WEBSERV_MAP[repository_id] = webserv
+ return webserv
+
# for debugging purposes, sample method
"""
def __setattr__(self, name, value):
@@ -263,8 +287,7 @@ class EntropyPackage:
if atom is None: # wtf!
return 'N/A'
- key = entropy.dep.dep_getkey(atom)
- downloads = ENTROPY.UGC.UGCCache.get_package_downloads(repo_clean, key)
+ downloads = self.get_ugc_package_downloads()
ugc_string = '[%s|%s] ' % (
downloads, SulfurConf.color_title2, repo_clean,)
if ver_str:
@@ -577,14 +600,40 @@ class EntropyPackage:
return ENTROPY.Settings()['repositories']['branch']
return self.dbconn.retrieveBranch(self.matched_id)
+ def _get_vote_raw(self, pkg_key):
+ webserv = self._get_webservice()
+ if webserv is None:
+ return None
+
+ # try to get vote for the single package first, if it fails,
+ # we'll search the info inside the available vote data.
+ got_miss = False
+ try:
+ vote = webserv.get_votes([pkg_key], cache = True,
+ cached = True)[pkg_key]
+ except WebService.CacheMiss:
+ vote = None
+ got_miss = True
+
+ # found it?
+ if vote is not None:
+ return vote
+
+ # fallback to available cache
+ try:
+ return webserv.get_available_votes(cache = True,
+ cached = True).get(pkg_key)
+ except WebService.CacheMiss:
+ return None
+
def get_ugc_package_vote(self):
if self.pkgset:
return -1
atom = self.get_name()
if not atom:
return None
- return ENTROPY.UGC.UGCCache.get_package_vote(
- self.get_repository_clean(), entropy.dep.dep_getkey(atom))
+ pkg_key = entropy.dep.dep_getkey(atom)
+ return self._get_vote_raw(pkg_key)
def get_ugc_package_vote_int(self):
if self.pkgset:
@@ -592,9 +641,10 @@ class EntropyPackage:
atom = self.get_name()
if not atom:
return 0
- vote = ENTROPY.UGC.UGCCache.get_package_vote(
- self.get_repository_clean(), entropy.dep.dep_getkey(atom))
- if not isinstance(vote, float):
+
+ pkg_key = entropy.dep.dep_getkey(atom)
+ vote = self._get_vote_raw(pkg_key)
+ if vote is None:
return 0
return int(vote)
@@ -604,9 +654,10 @@ class EntropyPackage:
atom = self.get_name()
if not atom:
return 0.0
- vote = ENTROPY.UGC.UGCCache.get_package_vote(
- self.get_repository_clean(), entropy.dep.dep_getkey(atom))
- if not isinstance(vote, float):
+
+ pkg_key = entropy.dep.dep_getkey(atom)
+ vote = self._get_vote_raw(pkg_key)
+ if vote is None:
return 0.0
return vote
@@ -619,9 +670,17 @@ class EntropyPackage:
atom = self.get_name()
if not atom:
return 0
- key = entropy.dep.dep_getkey(atom)
- return ENTROPY.UGC.UGCCache.get_package_downloads(
- self.get_repository_clean(), key)
+
+ webserv = self._get_webservice()
+ if webserv is None:
+ return 0
+ pkg_key = entropy.dep.dep_getkey(atom)
+ try:
+ downloads = webserv.get_available_downloads(cache = True,
+ cached = True).get(pkg_key, 0)
+ except WebService.CacheMiss:
+ return 0
+ return downloads
def get_attribute(self, attr):
cached = self.__cache.get(('get_attribute', attr,))
diff --git a/sulfur/src/sulfur/sulfur.glade b/sulfur/src/sulfur/sulfur.glade
index 0173974ce..b71c935ac 100644
--- a/sulfur/src/sulfur/sulfur.glade
+++ b/sulfur/src/sulfur/sulfur.glade
@@ -124,9 +124,9 @@
True
2
False
+
-
True
@@ -2740,8 +2740,8 @@ Relaxed
True
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
+
True
@@ -2783,8 +2783,8 @@ Relaxed
True
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
+
True
@@ -2869,8 +2869,8 @@ Relaxed
True
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
+
True
@@ -2891,8 +2891,8 @@ Relaxed
True
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
+
True
@@ -2913,8 +2913,8 @@ Relaxed
True
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
+
True
@@ -2998,8 +2998,8 @@ Relaxed
True
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
+
True
@@ -3020,8 +3020,8 @@ Relaxed
True
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
+
True
@@ -3042,8 +3042,8 @@ Relaxed
True
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
+
True
@@ -3441,34 +3441,6 @@ Relaxed
0
-
-
- True
- True
- True
- Clear all cache
-
-
-
- True
-
-
- True
- gtk-harddisk
-
-
- 0
-
-
-
-
-
-
- False
- False
- 1
-
-
False
@@ -6998,8 +6970,8 @@ gz
True
True
True
-
+
True
@@ -7988,90 +7960,6 @@ gz
True
vertical
-
-
- True
-
-
- True
- gtk-dnd
- 0
- 6
-
-
- 3
- 0
-
-
-
-
- True
- vertical
-
-
- True
- 0
- 1
- User Generated Content
- True
-
-
- False
- 3
- 0
-
-
-
-
- True
- 0
- 0
- User Generated Content description
-
-
- 1
-
-
-
-
- 1
-
-
-
-
- True
- 20
- 6
-
-
- True
- True
- True
- Load User Generated Content
-
-
-
- True
- gtk-refresh
- 6
-
-
-
-
-
-
- False
- False
- 2
-
-
-
-
- False
- 6
- 0
-
-
True
@@ -8195,7 +8083,6 @@ gz
True
- 6
end
@@ -8238,6 +8125,29 @@ gz
1
+
+
+ True
+ True
+ True
+ True
+ Load User Generated Content
+
+
+
+ True
+ 22
+ view-refresh
+ 3
+
+
+
+
+ False
+ False
+ 2
+
+
False
@@ -8247,7 +8157,7 @@ gz
- 1
+ 0
@@ -9282,6 +9192,7 @@ Please read them carefully and <b>make your choice</b>.
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ vertical
True
@@ -9359,8 +9270,8 @@ Please read them carefully and <b>make your choice</b>.
True
True
True
-
+
True
@@ -9385,37 +9296,13 @@ Please read them carefully and <b>make your choice</b>.
True
+ vertical
True
- 6
+ 5
2
3
-
-
- True
- 0
- this is the size
- True
-
-
- 1
- 2
- 5
- 6
-
-
-
-
- True
- 0
- Size
-
-
- 5
- 6
-
-
True
@@ -11393,8 +11280,8 @@ Please read them carefully and <b>make your choice</b>.
True
-
+
True
diff --git a/sulfur/src/sulfur/views.py b/sulfur/src/sulfur/views.py
index 24f207c7b..716c391e1 100644
--- a/sulfur/src/sulfur/views.py
+++ b/sulfur/src/sulfur/views.py
@@ -25,16 +25,16 @@ import tempfile
from entropy.exceptions import RepositoryError, InvalidPackageSet
from entropy.const import etpConst, etpSys, initconfig_entropy_constants, \
- const_debug_write
+ const_debug_write, const_debug_enabled, const_get_stringtype
from entropy.misc import ParallelTask, TimeScheduled
from entropy.i18n import _, _LOCALE
from entropy.tools import print_traceback
from entropy.dep import dep_getkey
-from entropy.const import const_get_stringtype
from sulfur.setup import const, cleanMarkupString, SulfurConf
from sulfur.core import UI, busy_cursor, normal_cursor, \
- STATUS_BAR_CONTEXT_IDS, resize_image, fork_function
+ STATUS_BAR_CONTEXT_IDS, resize_image, fork_function, \
+ get_entropy_webservice, Privileges
from sulfur.widgets import CellRendererStars
from sulfur.package import DummyEntropyPackage, EntropyPackage
from sulfur.entropyapi import Equo
@@ -44,6 +44,8 @@ from sulfur.event import SulfurSignals
from entropy.db.exceptions import ProgrammingError, Error as DbError, \
OperationalError, DatabaseError
+from entropy.services.client import WebService
+from entropy.client.services.interfaces import ClientWebService
class EntropyPackageViewModelInjector:
@@ -494,6 +496,7 @@ class EntropyPackageView:
self.selected_objs = []
self.last_row = None
self.loaded_reinstallables = []
+ self._webserv_map = {}
self._pixbuf_map = {}
self.loaded_event = None
self.do_refresh_view = False
@@ -689,15 +692,14 @@ class EntropyPackageView:
self.queue_full_exception = Full
self.queue_empty_exception = Empty
+ self.__pkg_ugc_icon_local_path_cache = {}
self.__pkg_ugc_icon_cache = {}
- self.__pkg_ugc_icon_call_cache = {}
- # max 64 items at time, don't lower it too much, can cause
- # request starvation with the current very low priority
- self._ugc_load_queue = queue_class(64)
- self._ugc_load_thread = TimeScheduled(3, self._ugc_queue_run)
+ # avoid DoS, lol
+ self._ugc_icon_load_queue = queue_class(64)
+ self._ugc_icon_thread = TimeScheduled(3, self._ugc_icon_queue_run)
if self._ugc_status:
# deferred loading, speedup UI init
- gobject.timeout_add_seconds(15, self._ugc_load_thread.start)
+ gobject.timeout_add_seconds(15, self._ugc_icon_thread.start)
def __update_ugc_event(self, event):
self.view.queue_draw()
@@ -864,7 +866,7 @@ class EntropyPackageView:
self.loaded_event = event
del self.loaded_reinstallables[:]
- if objs == None:
+ if objs is None:
objs = self.collect_selected_items(widget)
event_x = event.x
@@ -909,16 +911,16 @@ class EntropyPackageView:
return True
- elif len(objs) == 1:
- obj = objs[0]
- distance = 0
- for col in self.view.get_columns()[0:2]:
- distance += col.get_width()
- if (event_x > distance) and (event_x < (distance+self.stars_col_size)):
- vote = int((event_x - distance)/self.stars_col_size*5)+1
- # this is required to fix idiotic GTK behaviour
+ elif column.get_title() == self.pkgcolumn_text_rating:
+ def _do_vote(x, widget):
+ rel_distance = x
+ valid_votes = ClientWebService.VALID_VOTES
+ vote = int(float(rel_distance) / self.stars_col_size * \
+ len(valid_votes)) + 1
self.delayed_vote_submit(widget, vote)
- return True
+ return False
+ gobject.idle_add(_do_vote, x, widget)
+ return True
return False
@@ -952,6 +954,7 @@ class EntropyPackageView:
def run_properties_menu(self, menu_item):
objs = self.collect_selected_items()
+
for obj in objs:
if obj.is_group or obj.is_pkgset_cat:
continue
@@ -1141,7 +1144,8 @@ class EntropyPackageView:
busy_cursor(self.main_window)
objs = self.selected_objs
oldmask = self.etpbase.unmaskingPackages.copy()
- mydialog = MaskedPackagesDialog(self._entropy, self.etpbase, self.ui.main, objs)
+ mydialog = MaskedPackagesDialog(self._entropy, self.etpbase,
+ self.ui.main, objs)
result = mydialog.run()
if result != -5:
self.etpbase.unmaskingPackages = oldmask.copy()
@@ -1734,25 +1738,116 @@ class EntropyPackageView:
return store
+ def _get_webservice(self, repository_id):
+ webserv = self._webserv_map.get(repository_id)
+ if webserv == -1:
+ # not available
+ return None
+ if webserv is not None:
+ return webserv
+
+ with Privileges():
+ try:
+ webserv = get_entropy_webservice(self._entropy, repository_id)
+ except WebService.UnsupportedService as err:
+ webserv = None
+
+ if webserv is None:
+ self._webserv_map[repository_id] = -1
+ # not available
+ return
+
+ try:
+ available = webserv.service_available()
+ except WebService.WebServiceException:
+ available = False
+
+ if not available:
+ self._webserv_map[repository_id] = -1
+ # not available
+ return
+
+ self._webserv_map[repository_id] = webserv
+ return webserv
+
+ def _ugc_available(self, repository_id):
+ webserv = self._get_webservice(repository_id)
+ if webserv is None:
+ return False
+ return True
+
+ def _ugc_cache_icons(self, repository_id, package_names, cache):
+
+ webserv = self._get_webservice(repository_id)
+ if webserv is None:
+ return
+
+ for package_name in package_names:
+ with Privileges():
+ # sorry web service, we need data this way
+ try:
+ icon_docs = webserv.get_icons([package_name],
+ cache = cache)[package_name]
+ except WebService.WebServiceException as err:
+ return
+
+ # get document urls, store to local cache
+ for icon_doc in icon_docs:
+ cache_key = package_name, icon_doc.repository_id()
+ if cache_key in self.__pkg_ugc_icon_local_path_cache:
+ const_debug_write(__name__,
+ "_ugc_cache_icons: already in cache: %s" % (
+ cache_key,))
+ continue
+ with Privileges():
+ try:
+ local_path = webserv.get_document_url(icon_doc)
+ except ClientWebService.DocumentError as err:
+ const_debug_write(__name__,
+ "_ugc_cache_icons: document error: %s" % (
+ err,))
+ continue
+
+ try:
+ self.__pkg_ugc_icon_cache.pop(cache_key)
+ except KeyError:
+ pass
+ self.__pkg_ugc_icon_local_path_cache[cache_key] = local_path
+ const_debug_write(__name__,
+ "_ugc_cache_icons: pushed to cache: %s, %s" % (
+ cache_key, local_path,))
+ break
+
def __ugc_dnd_updates_clear_cache(self, *args):
const_debug_write(__name__, "EntropyPackageView, "
"__ugc_dnd_updates_clear_cache called")
- while True:
- try:
- key, repoid = self._ugc_dnd_cache_taint.pop()
- except KeyError:
- break
- self._entropy.UGC.get_docs(repoid, key)
+ def _do_parallel():
- self.__pkg_ugc_icon_cache.clear()
- self.__pkg_ugc_icon_call_cache.clear()
- self._ugc_pixbuf_map.clear()
- self._ugc_metadata_sync_exec_cache.clear()
- self._emit_ugc_update()
+ fetch_map = {}
+ while True:
+ try:
+ key, repoid = self._ugc_dnd_cache_taint.pop()
+ except KeyError:
+ break
+ obj = fetch_map.setdefault(repoid, set())
+ obj.add(key)
- def _ugc_drag_data_received(self, view, context, x, y, selection, drop_id, etime):
+ for repository_id, keys in fetch_map.items():
+ self._ugc_cache_icons(repository_id, keys, False)
+
+ self.__pkg_ugc_icon_cache.clear()
+ self._ugc_pixbuf_map.clear()
+ self._ugc_metadata_sync_exec_cache.clear()
+ self._emit_ugc_update()
+ self.__pkg_ugc_icon_local_path_cache.clear()
+
+ th = ParallelTask(_do_parallel)
+ th.start()
+
+ def _ugc_drag_data_received(self, view, context, x, y, selection, drop_id,
+ etime):
"""
Callback function for drag_data_received event used for UGC interaction
on Drag and Drop.
@@ -1857,7 +1952,7 @@ class EntropyPackageView:
obj.voted = 0.0
return
repository = obj.repoid
- if not self._entropy.UGC.is_repository_eapi3_aware(repository):
+ if not self._ugc_available(repository):
obj.voted = 0.0
return
atom = obj.name
@@ -1868,8 +1963,80 @@ class EntropyPackageView:
t = ParallelTask(self.vote_submit_thread, repository, key, obj)
t.start()
+ def _ugc_login(self, webserv, repository):
+
+ def fake_callback(*args, **kwargs):
+ return True
+
+ # use input box to read login
+ input_params = [
+ ('username', _('Username'), fake_callback, False),
+ ('password', _('Password'), fake_callback, True)
+ ]
+ login_data = self._entropy.input_box(
+ "%s %s %s" % (
+ _('Please login against'), repository, _('repository'),),
+ input_params,
+ cancel_button = True
+ )
+ if not login_data:
+ return False
+
+ username, password = login_data['username'], login_data['password']
+ with Privileges():
+ webserv.add_credentials(username, password)
+ try:
+ webserv.validate_credentials()
+ except WebService.AuthenticationFailed:
+ okDialog(self.ui.main,
+ _("Authentication error. Not logged in."))
+ return False
+ okDialog(self.ui.main,
+ _("Successfully logged in."))
+ return True
+
def vote_submit_thread(self, repository, key, obj):
- status, err_msg = self._entropy.UGC.add_vote(repository, key, int(obj.voted))
+
+ status = True
+ err_msg = None
+
+ webserv = self._get_webservice(repository)
+ if webserv is None:
+ err_msg = _("Unsupported Service")
+ status = False
+
+ if status:
+
+ with Privileges():
+ try:
+ status = webserv.add_vote(key, int(obj.voted))
+ except WebService.AuthenticationRequired:
+ def _do_login():
+ logged_in = self._ugc_login(webserv, repository)
+ if logged_in:
+ # call myself again
+ gobject.idle_add(self.vote_submit_thread,
+ repository, key, obj)
+ else:
+ t = ParallelTask(self.refresh_vote_info, obj)
+ t.start()
+ return False
+ gobject.idle_add(_do_login)
+ return False
+ except WebService.WebServiceException as err:
+ err_msg = repr(err)
+ status = False
+
+ if status:
+ with Privileges():
+ # need to refill local cache
+ done = True
+ try:
+ webserv.get_votes([key], cache = False)
+ except WebService.WebServiceException as err:
+ # ouch! drop everything completely
+ webserv._drop_cached("get_votes")
+ done = False
if status:
color = SulfurConf.color_good
@@ -1878,19 +2045,16 @@ class EntropyPackageView:
else:
color = SulfurConf.color_error
txt1 = _("Error registering vote")
- txt2 = err_msg
+ txt2 = err_msg or _("Already voted")
msg = "%s: %s" % (
color, txt1, txt2,)
def do_refresh(msg):
- self.ui.status.push(STATUS_BAR_CONTEXT_IDS['UGC'],
- "%s: %s" % (txt1, txt2,))
self.ui.UGCMessageLabel.show()
self.ui.UGCMessageLabel.set_markup(msg)
return False
def remove_ugc_sts():
- self.ui.status.pop(STATUS_BAR_CONTEXT_IDS['UGC'])
self.ui.UGCMessageLabel.set_markup("")
self.ui.UGCMessageLabel.hide()
return False
@@ -1899,6 +2063,7 @@ class EntropyPackageView:
gobject.timeout_add_seconds(20, remove_ugc_sts)
t = ParallelTask(self.refresh_vote_info, obj)
t.start()
+ return False
def refresh_vote_info(self, obj):
time.sleep(5)
@@ -2045,12 +2210,12 @@ class EntropyPackageView:
else:
cell.set_property('foreground', None)
- def _ugc_queue_run(self):
+ def _ugc_icon_queue_run(self):
- const_debug_write(__name__, "_ugc_queue_run called")
+ const_debug_write(__name__, "_ugc_icon_queue_run called")
pkgs = set()
- queue = self._ugc_load_queue
+ queue = self._ugc_icon_load_queue
while queue.qsize():
try:
@@ -2062,40 +2227,24 @@ class EntropyPackageView:
if pkgs:
const_debug_write(__name__,
- "_ugc_queue_run, spawning fetch of: %s" % (pkgs,))
- self._spawn_ugc_metadata_fetch(pkgs)
+ "_ugc_icon_queue_run, spawning fetch of: %s" % (pkgs,))
+ self._spawn_ugc_icon_docs_fetch(pkgs)
- def _spawn_ugc_metadata_fetch(self, pkgs):
+ def _spawn_ugc_icon_docs_fetch(self, pkgs):
def do_ugc_sync():
+ pkg_map = {}
for key, repoid in pkgs:
- const_debug_write(__name__,
- "_spawn_ugc_metadata_fetch, checking: %s, %s" % (
- key, repoid,))
- if self._entropy.UGC.UGCCache.is_alldocs_cached(key, repoid):
- const_debug_write(__name__,
- "_spawn_ugc_metadata_fetch, skipping !!: %s, %s" % (
- key, repoid,))
- continue
- outcome = self._entropy.UGC.get_docs(repoid, key)
- const_debug_write(__name__,
- "_spawn_ugc_metadata_fetch, get_docs() called: %s" % (
- outcome,))
- self.__pkg_ugc_icon_call_cache.clear()
+ obj = pkg_map.setdefault(repoid, [])
+ obj.append(key)
- def do_fork():
- fork_function(do_ugc_sync, self._emit_ugc_update)
+ for repoid, keys in pkg_map.items():
+ self._ugc_cache_icons(repoid, keys, True)
+ self._emit_ugc_update()
- gobject.idle_add(do_fork, priority = gobject.PRIORITY_LOW)
-
- def _spawn_ugc_icon_fetch(self, icon_doc, repoid):
-
- def do_icon_fetch():
- self._entropy.UGC.UGCCache.store_document(icon_doc['iddoc'],
- repoid, icon_doc['store_url'])
-
- fork_function(do_icon_fetch, self._emit_ugc_update)
+ th = ParallelTask(do_ugc_sync)
+ th.start()
def _get_cached_pkg_ugc_icon(self, pkg):
@@ -2109,9 +2258,12 @@ class EntropyPackageView:
cache_key = (key, repoid,)
cached = self.__pkg_ugc_icon_cache.get(cache_key)
+ if cached == -1:
+ # unavailable
+ return None
if cached is not None:
- const_debug_write(__name__, "_get_cached_pkg_ugc_icon %s in RAM" % (
- cache_key,))
+ #const_debug_write(__name__, "_get_cached_pkg_ugc_icon %s in RAM" % (
+ # cache_key,))
return cached
# validate variables...
@@ -2120,38 +2272,41 @@ class EntropyPackageView:
if repoid is None:
return
- icon_doc = self._entropy.UGC.UGCCache.get_icon_cache(key, repoid)
- if icon_doc is None:
- const_debug_write(__name__,
- "_get_cached_pkg_ugc_icon %s NOT on disk" % (
- cache_key,))
- # not cached
- return
-
- const_debug_write(__name__,
- "_get_cached_pkg_ugc_icon %s on disk?" % (
+ webserv = self._get_webservice(repoid)
+ if webserv is None:
+ const_debug_write(__name__, "_get_cached_pkg_ugc_icon %s unsup." % (
cache_key,))
+ return
- store_path = self._entropy.UGC.UGCCache.get_stored_document(
- icon_doc['iddoc'], repoid, icon_doc['store_url'])
-
+ store_path = self.__pkg_ugc_icon_local_path_cache.get(cache_key)
if store_path is None:
- # not cached
- called = self.__pkg_ugc_icon_call_cache.get(cache_key)
- if not called:
- self._spawn_ugc_icon_fetch(icon_doc, repoid)
- self.__pkg_ugc_icon_call_cache[cache_key] = True
- const_debug_write(__name__,
- "_get_cached_pkg_ugc_icon %s not cached on disk" % (
- cache_key,))
- return
- if not (os.access(store_path, os.R_OK) and os.path.isfile(store_path)):
- # not cached
- const_debug_write(__name__,
- "_get_cached_pkg_ugc_icon %s path not available" % (
- cache_key,))
- return
+ with Privileges():
+ # sorry web service, we need data this way
+ try:
+ icon_docs = webserv.get_icons([key], cache = True,
+ cached = True)[key]
+ except WebService.CacheMiss as err:
+ #const_debug_write(__name__,
+ # "_get_cached_pkg_ugc_icon %s NOT cached yet" % (
+ # cache_key,))
+ self.__pkg_ugc_icon_cache[cache_key] = -1
+ return
+
+ # get document urls, store to local cache
+ for icon_doc in icon_docs:
+ local_path = icon_doc.local_document()
+ if local_path is None:
+ continue
+ store_path = local_path
+ break
+
+ if store_path is None:
+ #const_debug_write(__name__,
+ # "_get_cached_pkg_ugc_icon %s NOT cached yet (2)" % (
+ # cache_key,))
+ self.__pkg_ugc_icon_cache[cache_key] = -1
+ return
icon_path = store_path + ".sulfur_icon_small"
pixbuf = self._ugc_pixbuf_map.get(icon_path)
@@ -2165,7 +2320,8 @@ class EntropyPackageView:
if not (os.path.isfile(icon_path) and \
os.access(icon_path, os.R_OK)):
try:
- resize_image(self._get_row_height(), store_path,
+ # keep some margin... -5
+ resize_image(self._get_row_height() - 5, store_path,
icon_path)
except (ValueError, OSError, IOError, gobject.GError):
# OSError = source file moved while copying
@@ -2191,52 +2347,63 @@ class EntropyPackageView:
def __new_ugc_pixbuf_stash_fetch(self, pkg):
# stash to queue for loading from WWW if required
- const_debug_write(__name__,
- "__new_ugc_pixbuf_stash_fetch called: %s" % (
- pkg,))
+ #if const_debug_enabled():
+ # const_debug_write(__name__,
+ # "__new_ugc_pixbuf_stash_fetch called: %s" % (
+ # pkg,))
if not self._ugc_status:
- const_debug_write(__name__,
- "__new_ugc_pixbuf_stash_fetch UGC STATUS FALSE!")
+ if const_debug_enabled():
+ const_debug_write(__name__,
+ "__new_ugc_pixbuf_stash_fetch UGC STATUS FALSE!")
return
- const_debug_write(__name__,
- "__new_ugc_pixbuf_stash_fetch going on for: %s" % (
- pkg,))
+ #if const_debug_enabled():
+ # const_debug_write(__name__,
+ # "__new_ugc_pixbuf_stash_fetch going on for: %s" % (
+ # pkg,))
try:
repoid = pkg.repoid
sync_item = (pkg.key, repoid)
except (ProgrammingError, OperationalError) as err:
- const_debug_write(__name__,
- "__new_ugc_pixbuf_stash_fetch, ouch: %s" % (
- repr(err),))
+ if const_debug_enabled():
+ const_debug_write(__name__,
+ "__new_ugc_pixbuf_stash_fetch, ouch: %s" % (
+ repr(err),))
return
if sync_item in self._ugc_metadata_sync_exec_cache:
- const_debug_write(__name__,
- "__new_ugc_pixbuf_stash_fetch: already in cache: %s" % (
- sync_item,))
+ #if const_debug_enabled():
+ # const_debug_write(__name__,
+ # "__new_ugc_pixbuf_stash_fetch: already in cache: %s" % (
+ # sync_item,))
return
self._ugc_metadata_sync_exec_cache.add(sync_item)
- if not self._entropy.UGC.is_repository_eapi3_aware(repoid):
- const_debug_write(__name__,
- "__new_ugc_pixbuf_stash_fetch: repository not EAPI3 aware: %s" % (
- repoid,))
+ if not self._ugc_available(repoid):
+ if const_debug_enabled():
+ const_debug_write(__name__,
+ "__new_ugc_pixbuf_stash_fetch: "
+ "repository not Web Services aware: %s" % (
+ repoid,))
return
- const_debug_write(__name__,
- "__new_ugc_pixbuf_stash_fetch: enqueue %s" % (sync_item,))
+ if const_debug_enabled():
+ const_debug_write(__name__,
+ "__new_ugc_pixbuf_stash_fetch: enqueue %s" % (sync_item,))
try:
- self._ugc_load_queue.put_nowait(sync_item)
- const_debug_write(__name__,
- "__new_ugc_pixbuf_stash_fetch: enqueued!! %s" % (sync_item,))
+ self._ugc_icon_load_queue.put_nowait(sync_item)
+ if const_debug_enabled():
+ const_debug_write(__name__,
+ "__new_ugc_pixbuf_stash_fetch: enqueued!! %s" % (
+ sync_item,))
except self.queue_full_exception as err:
# argh! queue full!
- const_debug_write(__name__,
- "__new_ugc_pixbuf_stash_fetch: ARGH QUEUE FULL %s" % (
- sync_item,))
+ if const_debug_enabled():
+ const_debug_write(__name__,
+ "__new_ugc_pixbuf_stash_fetch: ARGH QUEUE FULL %s" % (
+ sync_item,))
pass
def new_ugc_pixbuf(self, column, cell, model, myiter):