def __init__(self, search_dir): self._import_dir = search_dir self._asmdata = AppStream.Metadata() self._asmdata.set_locale("C") self._xdg_cat_map = { 'AudioVideo': self._category_by_id("multimedia"), 'Audio': self._category_by_id("multimedia"), 'Video': self._category_by_id("multimedia"), 'Development': self._category_by_id("development"), 'Education': self._category_by_id("education"), 'Game': self._category_by_id("games"), 'Graphics': self._category_by_id("graphics"), 'Network': self._category_by_id("network"), 'Office': self._category_by_id("customization"), 'Science': self._category_by_id("science"), 'Settings': self._category_by_id("tools"), 'System': self._category_by_id("system"), 'Utility': self._category_by_id("tools"), 'Arcade': self._category_by_id("arcade") }
def load(self, mdata=None): ''' Load the actual AppStream component from stored XML data. An existing Metadata instance can be reused. ''' if not mdata: import gi gi.require_version('AppStream', '1.0') from gi.repository import AppStream mdata = AppStream.Metadata() mdata.clear_components() mdata.set_format_style(AppStream.FormatStyle.COLLECTION) if not self.xml: raise Exception('Can not load AppStream component from empty data.') mdata.parse(self.xml, AppStream.FormatKind.XML) self.cpt = mdata.get_component() self.cpt.set_active_locale('C') return self.cpt
def update_appstream_data(session, local_repo, repo, suite, component, arch): ''' Import AppStream metadata about software components and associate it with the binary packages the data belongs to. ''' if arch.name == 'all': # arch:all has no AppStream components, those are always associated with an architecture # and are included in arch-specific files (even if the package they belong to is arch:all) return arch_all = session.query(ArchiveArchitecture) \ .filter(ArchiveArchitecture.name == 'all').one() yaml_fname = local_repo.index_file( suite, os.path.join(component.name, 'dep11', 'Components-{}.yml.xz'.format(arch.name))) if not yaml_fname: return cidmap_fname = local_repo.index_file( suite, os.path.join(component.name, 'dep11', 'CID-Index-{}.json.gz'.format(arch.name)), check=False) if not cidmap_fname: return with gzip.open(cidmap_fname, 'rb') as f: cid_map = json.loads(f.read()) with lzma.open(yaml_fname, 'r') as f: yaml_data = str(f.read(), 'utf-8') mdata = AppStream.Metadata() mdata.set_locale('ALL') mdata.set_format_style(AppStream.FormatStyle.COLLECTION) mdata.set_parse_flags(AppStream.ParseFlags.IGNORE_MEDIABASEURL) mdata.parse(yaml_data, AppStream.FormatKind.YAML) cpts = mdata.get_components() if len(cpts) == 0: return log.debug('Found {} software components in {}/{}'.format( len(cpts), suite.name, component.name)) # create context for direct serialization to collection XML chunk context = AppStream.Context() context.set_locale('ALL') context.set_style(AppStream.FormatStyle.COLLECTION) for cpt in cpts: cpt.set_active_locale('C') pkgname = cpt.get_pkgname() if not pkgname: # we skip these for now, web-apps have no package assigned - we might need a better way to map # those to their packages, likely with an improved appstream-generator integration log.debug( 'Found DEP-11 component without package name in {}/{}: {}'. format(suite.name, component.name, cpt.get_id())) continue # fetch package this component belongs to bin_pkg = session.query(BinaryPackage) \ .filter(BinaryPackage.name == pkgname) \ .filter(BinaryPackage.repo_id == repo.id) \ .filter(BinaryPackage.architecture_id.in_((arch.id, arch_all.id))) \ .filter(BinaryPackage.component_id == component.id) \ .filter(BinaryPackage.suites.any(ArchiveSuite.id == suite.id)) \ .order_by(BinaryPackage.version.desc()).first() if not bin_pkg: log.info('Found orphaned DEP-11 component in {}/{}: {}'.format( suite.name, component.name, cpt.get_id())) continue dcpt = SoftwareComponent() dcpt.kind = int(cpt.get_kind()) dcpt.cid = cpt.get_id() dcpt.xml = cpt.to_xml_data(context) dcpt.gcid = cid_map.get(dcpt.cid) if not dcpt.gcid: log.info('Found DEP-11 component without GCID in {}/{}: {}'.format( suite.name, component.name, cpt.get_id())) # create UUID for this component (based on GCID or XML data) dcpt.update_uuid() existing_dcpt = session.query(SoftwareComponent) \ .filter(SoftwareComponent.uuid == dcpt.uuid).one_or_none() if existing_dcpt: if bin_pkg in existing_dcpt.bin_packages: continue # the binary package is already registered with this component existing_dcpt.bin_packages.append(bin_pkg) continue # we already have this component, no need to add it again # add new software component to database dcpt.name = cpt.get_name() dcpt.summary = cpt.get_summary() dcpt.description = cpt.get_description() for icon in cpt.get_icons(): if icon.get_kind() == AppStream.IconKind.CACHED: dcpt.icon_name = icon.get_name() break dcpt.project_license = cpt.get_project_license() dcpt.developer_name = cpt.get_developer_name() # test for free software dcpt.is_free = False if not dcpt.project_license: # We have no license set. # If we are in the 'main' component, we # assume we have free software if bin_pkg.component.name == 'main': dcpt.is_free = True else: # have AppStream test the SPDX license expression for free software dcpt.is_free = AppStream.license_is_free_license( dcpt.project_license) dcpt.categories = [] for cat in cpt.get_categories(): dcpt.categories.append(cat) dcpt.bin_packages = [bin_pkg] session.add(dcpt) log.debug('Added new software component \'{}\' to database'.format( dcpt.cid)) session.commit()