~ubuntu-branches/ubuntu/raring/software-center/raring-proposed

« back to all changes in this revision

Viewing changes to softwarecenter/utils.py

  • Committer: Package Import Robot
  • Author(s): Michael Vogt
  • Date: 2012-10-11 15:33:05 UTC
  • mfrom: (195.1.18 quantal)
  • Revision ID: package-import@ubuntu.com-20121011153305-fm5ln7if3rpzts4n
Tags: 5.4.1.1
* lp:~mvo/software-center/reinstall-previous-purchase-token-fix:
  - fix reinstall previous purchases that have a system-wide
    license key LP: #1065481
* lp:~mvo/software-center/lp1060106:
  - Add missing gettext init for utils/update-software-center-agent
    (LP: #1060106)

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
19
import dbus
 
20
import gc
20
21
import gettext
21
22
from gi.repository import GObject
22
23
from gi.repository import Gio
38
39
    from urlparse import urlsplit
39
40
 
40
41
from enums import Icons, APP_INSTALL_PATH_DELIMITER
41
 
from paths import SOFTWARE_CENTER_CACHE_DIR
 
42
from paths import (
 
43
    SOFTWARE_CENTER_CACHE_DIR,
 
44
    OEM_CHANNEL_DESCRIPTOR,
 
45
    )
42
46
 
43
47
from config import get_config
44
48
 
82
86
            log_traceback("populate model from query: '%s' (threaded: %s)")
83
87
 
84
88
 
 
89
class TraceActiveObjectTypes(object):
 
90
    """ A context manager that tracks what and how many new object types
 
91
        are added in the context block.
 
92
 
 
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
 
95
    """
 
96
 
 
97
    def __init__(self, info):
 
98
        self.info = info
 
99
        self._known_obj_ids = set()
 
100
 
 
101
    def __enter__(self):
 
102
        gc.collect()
 
103
        for obj in gc.get_objects():
 
104
            self._known_obj_ids.add(id(obj))
 
105
 
 
106
    def __exit__(self, atype, value, stack):
 
107
        # ensure we start clean
 
108
        gc.collect()
 
109
        new_obj_types = {}
 
110
        for obj in gc.get_objects():
 
111
            if id(obj) in self._known_obj_ids:
 
112
                continue
 
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
 
118
        #print new_obj_types
 
119
        for v in sorted(new_obj_types, key=new_obj_types.get):
 
120
            print v, new_obj_types[v]
 
121
        print "/+++\n"
 
122
 
 
123
 
 
124
class TraceMemoryUsage(object):
 
125
    """Trace amount of memory used by the app using /proc/$$/statm"""
 
126
 
 
127
    def __init__(self, info):
 
128
        self.info = info
 
129
 
 
130
    def __enter__(self):
 
131
        self.resident = self._get_mem_from_proc()["resident"]
 
132
        self.data = self._get_mem_from_proc()["data"]
 
133
 
 
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" % (
 
138
            self.info,
 
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)
 
143
 
 
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),
 
148
                'data': int(data),
 
149
               }
 
150
 
 
151
 
85
152
def utf8(s):
86
153
    """
87
154
    Takes a string or unicode object and returns a utf-8 encoded
367
434
    return name
368
435
 
369
436
 
 
437
def is_dbus_service_running(service_name):
 
438
    running = False
 
439
    try:
 
440
        bus = dbus.SessionBus()
 
441
        running = bus.name_has_owner(service_name)
 
442
    except:
 
443
        LOG.exception("could not check for dbus service %s" % service_name)
 
444
    return running
 
445
 
 
446
 
 
447
def is_gnome_shell_running():
 
448
    return is_dbus_service_running("org.gnome.Shell")
 
449
 
 
450
 
370
451
def is_unity_running():
371
452
    """
372
453
    return True if Unity is currently running
373
454
    """
374
 
    unity_running = False
375
 
    try:
376
 
        bus = dbus.SessionBus()
377
 
        unity_running = bus.name_has_owner("com.canonical.Unity")
378
 
    except:
379
 
        LOG.exception("could not check for Unity dbus service")
380
 
    return unity_running
 
455
    return is_dbus_service_running("com.canonical.Unity")
381
456
 
382
457
 
383
458
def get_icon_from_theme(icons, iconname=None, iconsize=Icons.APP_ICON_SIZE,
390
465
    try:
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
438
 
    # pkgname itself
 
513
    # pkgname itself for the case of for-purchase items, etc.
439
514
    if pkgname:
440
515
        installed_desktop_file_path = "/usr/share/applications/%s.desktop" %\
441
516
            pkgname
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)
446
527
    return ""
528
609
 
529
610
 
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)
535
616
 
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)
658
739
    else:
659
740
        datadir = softwarecenter.paths.datadir
666
747
    return str(uuid.uuid4())
667
748
 
668
749
 
 
750
def get_recommender_uuid():
 
751
    """ the recommender service requires a UUID that does not contain
 
752
        dashes
 
753
    """
 
754
    return get_uuid().replace("-", "")
 
755
 
 
756
 
669
757
def get_lock(path):
670
758
    """ return a lock that can be released with release_lock on success
671
759
        and -1 on failure
740
828
                raise
741
829
 
742
830
 
 
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):
 
834
        return ""
 
835
    with open(path) as f:
 
836
        for line in filter(lambda l: not l.startswith("#"), f):
 
837
            return line.strip()
 
838
 
 
839
 
743
840
class SimpleFileDownloader(GObject.GObject):
744
841
 
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,
827
 
                           None)
828
 
 
829
 
    def _check_url_reachable_and_then_download_cb(self, f, result,
830
 
                                                  user_data=None):
 
924
                           url)
 
925
 
 
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.
 
929
        """
 
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
 
934
        # the wrong file
 
935
        if self.url != want_url:
 
936
            self.LOG.warn("url changed from '%s' to '%s'" % (
 
937
                    want_url, self.url))
 
938
            return False
 
939
        return True
 
940
 
 
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):
 
944
            return
 
945
        # normal operation
832
946
        try:
833
947
            info = f.query_info_finish(result)
834
948
            etag = info.get_etag()
838
952
                                                        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)
846
960
        del f
847
961
 
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):
 
965
            return
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