From 0efb611c4839677b080f3753df861e46a16f244e Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Fri, 21 Jan 2011 11:56:20 +0000 Subject: untested patch for .desktop-format activity.info files --- diff --git a/src/sugar/bundle/activitybundle.py b/src/sugar/bundle/activitybundle.py index 542fa00..d2aee44 100644 --- a/src/sugar/bundle/activitybundle.py +++ b/src/sugar/bundle/activitybundle.py @@ -36,6 +36,19 @@ from sugar.bundle.bundleversion import NormalizedVersion from sugar.bundle.bundleversion import InvalidVersionError +_INFO_SYNONYMS = { + 'Icon': ['icon'], + 'MimeTypes': ['mime_types'], + 'Name': ['name'], + 'X-Sugar-ActivityVersion': ['activity_version'], + 'X-Sugar-BundleId': ['bundle_id', 'service_name'], + 'X-Sugar-Exec': ['exec'], + 'X-Sugar-ShowLauncher': ['show_launcher'], + 'X-Sugar-Tags': ['tags'], +} +_INFO_LOCALESTRINGS = ['Icon', 'Name', 'X-Sugar-Tags'] + + class ActivityBundle(Bundle): """A Sugar activity bundle @@ -51,7 +64,6 @@ class ActivityBundle(Bundle): def __init__(self, path): Bundle.__init__(self, path) - self.activity_class = None self.bundle_exec = None self._name = None @@ -63,6 +75,7 @@ class ActivityBundle(Bundle): self._tags = None self._activity_version = '0' self._installation_time = os.stat(path).st_mtime + self._have_desktop_file = True info_file = self.get_file('activity/activity.info') if info_file is None: @@ -80,55 +93,68 @@ class ActivityBundle(Bundle): cp = ConfigParser() cp.readfp(info_file) - section = 'Activity' - - if cp.has_option(section, 'bundle_id'): - self._bundle_id = cp.get(section, 'bundle_id') - # FIXME deprecated - elif cp.has_option(section, 'service_name'): - warnings.warn('use bundle_id instead of service_name ' \ - 'in your activity.info', DeprecationWarning) - self._bundle_id = cp.get(section, 'service_name') + old_section = 'Activity' + new_section = 'Desktop Entry' + + # for backwards compatibility + if not cp.has_section('Desktop Entry'): + cp.add_section('Desktop Entry') + for new_name, old_names in _INFO_SYNONYMS.items(): + if cp.has_option(new_section, new_name): + continue + for old_name in old_names: + if not cp.has_option(old_section, old_name): + continue + cp.set(new_section, new_name, cp.get(old_section, old_name)) + self._have_desktop_file = False + + if not self._have_desktop_file: + warnings.warn('Old activity.info format detected, please' + ' tell the author to update it to Desktop Entry format.', + DeprecationWarning) + + if cp.has_option(new_section, 'X-Sugar-BundleId'): + self._bundle_id = cp.get(new_section, 'X-Sugar-BundleId') else: raise MalformedBundleException( 'Activity bundle %s does not specify a bundle id' % self._path) - if cp.has_option(section, 'name'): - self._name = cp.get(section, 'name') + if cp.has_option(new_section, 'Name'): + self._name = cp.get(new_section, 'Name') else: raise MalformedBundleException( 'Activity bundle %s does not specify a name' % self._path) + self._local_name = self._get_localised_value(cp, 'Name') + # FIXME class is deprecated - if cp.has_option(section, 'class'): - warnings.warn('use exec instead of class ' \ - 'in your activity.info', DeprecationWarning) - self.activity_class = cp.get(section, 'class') - elif cp.has_option(section, 'exec'): - self.bundle_exec = cp.get(section, 'exec') + if cp.has_option(new_section, 'X-Sugar-Exec'): + self.bundle_exec = cp.get(new_section, 'X-Sugar-Exec') + elif cp.has_option(old_section, 'class'): + self.bundle_exec = 'sugar-activity ' + cp.get(old_section, 'class') else: raise MalformedBundleException( - 'Activity bundle %s must specify either class or exec' % - self._path) + 'Activity bundle %s must specify either X-Sugar-Exec, class' + ' or exec' % self._path) - if cp.has_option(section, 'mime_types'): - mime_list = cp.get(section, 'mime_types').strip(';') - self._mime_types = [mime.strip() for mime in mime_list.split(';')] + if cp.has_option(new_section, 'MimeTypes'): + type_list = cp.get(new_section, 'MimeTypes').strip(';').split(';') + self._mime_types = [typ.strip() for typ in type_list] - if cp.has_option(section, 'show_launcher'): - if cp.get(section, 'show_launcher') == 'no': + if cp.has_option(new_section, 'X-Sugar-ShowLauncher'): + if cp.get(new_section, 'X-Sugar-ShowLauncher') in ['no', 'false']: self._show_launcher = False - if cp.has_option(section, 'tags'): - tag_list = cp.get(section, 'tags').strip(';') - self._tags = [tag.strip() for tag in tag_list.split(';')] + tags = self._get_localised_value(cp, 'X-Sugar-Tags') + if tags: + self._tags = [tag.strip() for tag in tags.strip(';').split(';')] - if cp.has_option(section, 'icon'): - self._icon = cp.get(section, 'icon') + if cp.has_option(new_section, 'Icon'): + self._icon = cp.get(new_section, 'Icon') - if cp.has_option(section, 'activity_version'): - version = cp.get(section, 'activity_version') + if cp.has_option(new_section, 'X-Sugar-ActivityVersion'): + version = cp.get(new_section, 'X-Sugar-ActivityVersion') try: NormalizedVersion(version) except InvalidVersionError: @@ -137,6 +163,22 @@ class ActivityBundle(Bundle): (self._path, version)) self._activity_version = version + def _get_localised_value(self, config, name): + languages = os.environ['LANGUAGE'].split(':') + for code in languages: + if config.has_option('Desktop Entry', '%s[%s]' % (name, code)): + return config.get('Desktop Entry', '%s[%s]' % (name, code)) + + for code in languages: + language, sep_, country_ = code.partition('_') + if config.has_option('Desktop Entry', '%s[%s]' % (name, language)): + return config.get('Desktop Entry', '%s[%s]' % (name, language)) + + if config.has_option('Desktop Entry', name): + return config.get('Desktop Entry', name) + + return None + def _get_linfo_file(self): lang = locale.getdefaultlocale()[0] if not lang: @@ -200,6 +242,7 @@ class ActivityBundle(Bundle): """Get the activity bundle id""" return self._bundle_id + # FIXME: Handling of XDG 'Icon' different from Sugar 'icon' def get_icon(self): """Get the activity icon name""" # FIXME: this should return the icon data, not a filename, so that @@ -221,12 +264,7 @@ class ActivityBundle(Bundle): def get_command(self): """Get the command to execute to launch the activity factory""" - if self.bundle_exec: - command = os.path.expandvars(self.bundle_exec) - else: - command = 'sugar-activity ' + self.activity_class - - return command + return os.path.expandvars(self.bundle_exec) def get_mime_types(self): """Get the MIME types supported by the activity""" @@ -248,6 +286,7 @@ class ActivityBundle(Bundle): install_path = os.path.join(install_dir, self._zip_root_dir) self.install_mime_type(install_path) + self.install_desktop_file(install_path) return install_path @@ -288,6 +327,18 @@ class ActivityBundle(Bundle): os.path.join(installed_icons_dir, os.path.basename(info_file))) + def install_desktop_file(self, install_path): + if not self._have_desktop_file: + return + + xdg_data_home = os.getenv('XDG_DATA_HOME', + os.path.expanduser('~/.local/share')) + + info_path = os.path.join(install_path, 'activity', 'activity.info') + installed_desktop_path = os.path.join(xdg_data_home, 'applications', + self._bundle_id+'.desktop') + self._symlink(info_path, installed_desktop_path) + def _symlink(self, src, dst): if not os.path.isfile(src): return @@ -312,12 +363,17 @@ class ActivityBundle(Bundle): mime_dir = os.path.join(xdg_data_home, 'mime') installed_mime_path = os.path.join(mime_dir, 'packages', - '%s.xml' % self._bundle_id) + '%s.desktop' % self._bundle_id) if os.path.exists(installed_mime_path): os.remove(installed_mime_path) os.spawnlp(os.P_WAIT, 'update-mime-database', 'update-mime-database', mime_dir) + installed_desktop_path = os.path.join(xdg_data_home, 'applications', + self._bundle_id+'.xml') + if os.path.exists(installed_desktop_path): + os.remove(installed_desktop_path) + mime_types = self.get_mime_types() if mime_types is not None: installed_icons_dir = os.path.join(xdg_data_home, -- cgit v0.9.1