82
86
log_traceback("populate model from query: '%s' (threaded: %s)")
89
class TraceActiveObjectTypes(object):
90
""" A context manager that tracks what and how many new object types
91
are added in the context block.
93
Note that due to the gc.collect() call this is slow and should not
94
be used in production code, but its very useful inside e.g. tests
97
def __init__(self, info):
99
self._known_obj_ids = set()
103
for obj in gc.get_objects():
104
self._known_obj_ids.add(id(obj))
106
def __exit__(self, atype, value, stack):
107
# ensure we start clean
110
for obj in gc.get_objects():
111
if id(obj) in self._known_obj_ids:
113
self._known_obj_ids.add(id(obj))
114
if not type(obj) in new_obj_types:
115
new_obj_types[type(obj)] = 0
116
new_obj_types[type(obj)] += 1
117
print "+++ new types after '%s':" % self.info
119
for v in sorted(new_obj_types, key=new_obj_types.get):
120
print v, new_obj_types[v]
124
class TraceMemoryUsage(object):
125
"""Trace amount of memory used by the app using /proc/$$/statm"""
127
def __init__(self, info):
131
self.resident = self._get_mem_from_proc()["resident"]
132
self.data = self._get_mem_from_proc()["data"]
134
def __exit__(self, atype, value, stack):
135
now_resident = self._get_mem_from_proc()["resident"] - self.resident
136
now_data = self._get_mem_from_proc()["data"] - self.data
137
print "++++ MEMORY DELTA for '%s': res: %s data: %s (%s %s)\n" % (
139
# assume page size of 4k here
140
get_nice_size(now_resident * 4 * 1024),
141
get_nice_size(now_data * 4 * 1024),
142
now_resident, now_data)
144
def _get_mem_from_proc(self):
145
with open("/proc/%i/statm" % os.getpid()) as f:
146
size, resident, share, text, lib, data, dt = f.readline().split()
147
return {'resident': int(resident),
87
154
Takes a string or unicode object and returns a utf-8 encoded
437
def is_dbus_service_running(service_name):
440
bus = dbus.SessionBus()
441
running = bus.name_has_owner(service_name)
443
LOG.exception("could not check for dbus service %s" % service_name)
447
def is_gnome_shell_running():
448
return is_dbus_service_running("org.gnome.Shell")
370
451
def is_unity_running():
372
453
return True if Unity is currently running
374
unity_running = False
376
bus = dbus.SessionBus()
377
unity_running = bus.name_has_owner("com.canonical.Unity")
379
LOG.exception("could not check for Unity dbus service")
455
return is_dbus_service_running("com.canonical.Unity")
383
458
def get_icon_from_theme(icons, iconname=None, iconsize=Icons.APP_ICON_SIZE,
391
466
icon = icons.load_icon(iconname, iconsize, 0)
392
467
except Exception as e:
393
LOG.warning(utf8("could not load icon '%s', displaying missing "\
468
LOG.warning(utf8("could not load icon '%s', displaying missing "
394
469
"icon instead: %s ") % (
395
470
utf8(iconname), utf8(e.message)))
396
471
icon = icons.load_icon(missingicon, iconsize, 0)
435
510
if os.path.exists(installed_desktop_file_path):
436
511
return installed_desktop_file_path
437
512
# lastly, just try checking directly for the desktop file based on the
513
# pkgname itself for the case of for-purchase items, etc.
440
515
installed_desktop_file_path = "/usr/share/applications/%s.desktop" %\
442
517
if os.path.exists(installed_desktop_file_path):
443
518
return installed_desktop_file_path
519
# files in the extras archive have their desktop filenames prepended
520
# by "extras-", so we check for that also (LP: #1012877)
521
extras_desktop_file_path = ("/usr/share/applications/"
522
"extras-%s.desktop" % pkgname)
523
if os.path.exists(extras_desktop_file_path):
524
return extras_desktop_file_path
444
525
LOG.warn("Could not determine the installed desktop file path for "
445
526
"app-install desktop file: '%s'" % app_install_data_file_path)
530
611
def get_nice_size(n_bytes):
531
nice_size = lambda s: [(s % 1024 ** i and "%.1f" % (s / 1024.0 ** i) or \
532
str(s / 1024 ** i)) + x.strip() for i, x in enumerate(' KMGTPEZY') \
612
nice_size = lambda s: [(s % 1024 ** i and "%.1f" % (s / 1024.0 ** i) or
613
str(s / 1024 ** i)) + x.strip() for i, x in enumerate(' KMGTPEZY')
533
614
if s < 1024 ** (i + 1) or i == 8][0]
534
615
return nice_size(n_bytes)
648
729
xapian_base_path = datadir
649
730
# set new global datadir
650
731
softwarecenter.paths.datadir = datadir
732
softwarecenter.paths.XAPIAN_BASE_PATH = xapian_base_path
651
733
# also alter the app-install path
652
path = "%s/desktop/software-center.menu" % \
653
softwarecenter.paths.APP_INSTALL_PATH
654
if not os.path.exists(path):
734
path = "./build/share/app-install/desktop/software-center.menu"
735
if os.path.exists(path):
655
736
softwarecenter.paths.APP_INSTALL_PATH = './build/share/app-install'
656
logging.warn("using local APP_INSTALL_PATH: %s" %\
737
logging.warn("using local APP_INSTALL_PATH: %s" %
657
738
softwarecenter.paths.APP_INSTALL_PATH)
659
740
datadir = softwarecenter.paths.datadir
831
def get_oem_channel_descriptor(path=OEM_CHANNEL_DESCRIPTOR):
832
"""Return the ubuntu distribution channel descriptor or a empty string """
833
if not os.path.exists(path):
835
with open(path) as f:
836
for line in filter(lambda l: not l.startswith("#"), f):
743
840
class SimpleFileDownloader(GObject.GObject):
745
842
LOG = logging.getLogger("softwarecenter.simplefiledownloader")
824
921
f.query_info_async(Gio.FILE_ATTRIBUTE_STANDARD_SIZE, 0, 0,
825
922
self._cancellable,
826
923
self._check_url_reachable_and_then_download_cb,
829
def _check_url_reachable_and_then_download_cb(self, f, result,
926
def _ensure_correct_url(self, want_url):
927
"""This function will ensure that the url we requested to download
928
earlier matches that is now downloaded.
930
# this function is needed as there is a rance condition when the
931
# operation is finished but the signal is not delivered yet (its
932
# still in the gtk event loop). in this case there is nothing to
933
# self._cancel but self.url/self.dest_file_path will still point to
935
if self.url != want_url:
936
self.LOG.warn("url changed from '%s' to '%s'" % (
941
def _check_url_reachable_and_then_download_cb(self, f, result, want_url):
831
942
self.LOG.debug("_check_url_reachable_and_then_download_cb: %s" % f)
943
if not self._ensure_correct_url(want_url):
833
947
info = f.query_info_finish(result)
834
948
etag = info.get_etag()
839
953
# url is reachable, now download the file
840
954
f.load_contents_async(
841
self._cancellable, self._file_download_complete_cb, None)
955
self._cancellable, self._file_download_complete_cb, want_url)
842
956
except GObject.GError as e:
843
957
self.LOG.debug("file *not* reachable %s" % self.url)
844
958
self.emit('file-url-reachable', False)
845
959
self.emit('error', GObject.GError, e)
848
def _file_download_complete_cb(self, f, result, path=None):
962
def _file_download_complete_cb(self, f, result, want_url):
849
963
self.LOG.debug("file download completed %s" % self.dest_file_path)
964
if not self._ensure_correct_url(want_url):
850
966
# The result from the download is actually a tuple with three
851
967
# elements (content, size, etag?)
852
968
# The first element is the actual content so let's grab that