Ejemplo n.º 1
0
    def build(self, filename):

        # check the package has .desktop files
        print 'SOURCE\t', filename
        pkg = Package(filename)

        for b in self.cfg.get_package_blacklist():
            if fnmatch.fnmatch(pkg.name, b):
                print 'IGNORE\t', filename, '\t', "package is blacklisted:", pkg.name
                return

        # set up state
        if not os.path.exists('./appstream'):
            os.makedirs('./appstream')
        if not os.path.exists('./icons'):
            os.makedirs('./icons')
        if not os.path.exists('./screenshot-cache'):
            os.makedirs('./screenshot-cache')
        if not os.path.exists('./screenshots'):
            os.makedirs('./screenshots')
        if not os.path.exists('./screenshots/source'):
            os.makedirs('./screenshots/source')
        for size in self.cfg.get_screenshot_thumbnail_sizes():
            path = './screenshots/' + str(size[0]) + 'x' + str(size[1])
            if not os.path.exists(path):
                os.makedirs(path)

        # remove tmp
        if os.path.exists('./tmp'):
            shutil.rmtree('./tmp')
        os.makedirs('./tmp')

        # decompress main file and search for desktop files
        package_decompress(pkg)
        files = []
        for f in self.cfg.get_interesting_installed_files():
            files.extend(glob.glob("./tmp" + f))
        files.sort()

        # we only need to install additional files if we're not running on
        # the builders
        for c in self.cfg.get_package_data_list():
            if fnmatch.fnmatch(pkg.name, c[0]):
                extra_files = glob.glob("./packages/%s*.rpm" % c[1])
                for f in extra_files:
                    extra_pkg = Package(f)
                    print "INFO\tAdding extra package %s for %s" % (extra_pkg.name, pkg.name)
                    package_decompress(extra_pkg)

        # open the AppStream file for writing
        xml_output_file = './appstream/' + pkg.name + '.xml'
        xml = open(xml_output_file, 'w')
        xml.write("<?xml version=\"1.0\"?>\n")
        xml.write("<applications version=\"0.1\">\n")

        # check for duplicate apps in the package
        application_ids = []
        has_valid_content = False

        # process each desktop file in the original package
        for f in files:

            print 'PROCESS\t', f

            fi = Gio.file_new_for_path(f)
            info = fi.query_info('standard::content-type', 0, None)

            # create the right object depending on the content type
            content_type = info.get_content_type()
            if content_type == 'inode/symlink':
                continue
            if content_type == 'application/x-font-ttf':
                app = FontFile(pkg, self.cfg)
            elif content_type == 'application/x-font-otf':
                app = FontFile(pkg, self.cfg)
            elif content_type == 'application/x-desktop':
                app = DesktopFile(pkg, self.cfg)
            elif content_type == 'application/xml':
                app = InputMethodComponent(pkg, self.cfg)
            elif content_type == 'application/x-sqlite3':
                app = InputMethodTable(pkg, self.cfg)
            else:
                print 'IGNORE\t', f, '\t', "content type " + content_type + " not supported"
                continue

            # the ID is the filename
            app.set_id(f.split('/')[-1])

            # application is blacklisted
            blacklisted = False
            for b in self.cfg.get_id_blacklist():
                if fnmatch.fnmatch(app.app_id, b):
                    print 'IGNORE\t', f, '\t', "application is blacklisted:", app.app_id
                    blacklisted = True
                    break
            if blacklisted:
                continue

            # packages that ship .desktop files in /usr/share/applications
            # *and* /usr/share/applications/kde4 do not need multiple entries
            if app.app_id in application_ids:
                print 'IGNORE\t', f, '\t', app.app_id, 'duplicate ID in package'
                continue
            application_ids.append(app.app_id)

            # parse desktop file
            if not app.parse_file(f):
                continue

            # do we have an AppData file?
            appdata_file = './tmp/usr/share/appdata/' + app.app_id + '.appdata.xml'
            appdata_extra_file = './appdata-extra/' + app.type_id + '/' + app.app_id + '.appdata.xml'
            if os.path.exists(appdata_file) and os.path.exists(appdata_extra_file):
                print 'DELETE\t', appdata_extra_file, 'as upstream AppData file exists'
                os.remove(appdata_extra_file)

            # just use the extra file in places of the missing upstream one
            if os.path.exists(appdata_extra_file):
                appdata_file = appdata_extra_file

            # need to extract details
            if os.path.exists(appdata_file):
                data = AppData()
                data.extract(appdata_file)

                # check AppData file validates
                if os.path.exists('/usr/bin/appdata-validate'):
                    env = os.environ
                    p = subprocess.Popen(['/usr/bin/appdata-validate',
                                          '--relax', appdata_file],
                                         cwd='.', env=env, stdout=subprocess.PIPE)
                    p.wait()
                    if p.returncode:
                        for line in p.stdout:
                            line = line.replace('\n', '')
                            print 'WARNING\tAppData did not validate: ' + line

                # check the id matches
                if data.get_id() != app.app_id and data.get_id() != app.app_id_full:
                    raise StandardError('The AppData id does not match: ' + app.app_id)

                # check the licence is okay
                if data.get_licence() not in self.cfg.get_content_licences():
                    raise StandardError('The AppData licence is not okay for ' +
                                        app.app_id + ': \'' +
                                        data.get_licence() + '\'')

                # if we have an override, use it for all languages
                tmp = data.get_names()
                if tmp:
                    app.names = tmp

                # if we have an override, use it for all languages
                tmp = data.get_summaries()
                if tmp:
                    app.comments = tmp

                # get optional bits
                tmp = data.get_url()
                if tmp:
                    app.homepage_url = tmp
                tmp = data.get_project_group()
                if tmp:
                    app.project_group = tmp
                app.descriptions = data.get_descriptions()

                # get screenshots
                tmp = data.get_screenshots()
                for image in tmp:
                    print 'DOWNLOADING\t', image
                    app.add_screenshot_url(image)

            elif app.requires_appdata:
                print 'IGNORE\t', f, '\t', app.app_id_full, 'requires AppData to be included'
                continue

            # use the homepage to filter out same more generic apps
            if not app.project_group:

                # GNOME
                project_urls = [ 'http*://*.gnome.org*',
                                 'http://gnome-*.sourceforge.net/']
                for m in project_urls:
                    if fnmatch.fnmatch(app.homepage_url, m):
                        app.project_group = "GNOME"

                # KDE
                project_urls = [ 'http*://*.kde.org*',
                                'http://*kde-apps.org/*' ]
                for m in project_urls:
                    if fnmatch.fnmatch(app.homepage_url, m):
                        app.project_group = "KDE"

                # XFCE
                project_urls = [ 'http://*xfce.org*' ]
                for m in project_urls:
                    if fnmatch.fnmatch(app.homepage_url, m):
                        app.project_group = "XFCE"

                # LXDE
                project_urls = [ 'http://lxde.org*',
                                 'http://lxde.sourceforge.net/*' ]
                for m in project_urls:
                    if fnmatch.fnmatch(app.homepage_url, m):
                        app.project_group = "LXDE"

                # MATE
                project_urls = [ 'http://*mate-desktop.org*' ]
                for m in project_urls:
                    if fnmatch.fnmatch(app.homepage_url, m):
                        app.project_group = "MATE"

                # print that we auto-added it
                if app.project_group:
                    print 'INFO\t', f, '\t', app.app_id, 'assigned', app.project_group

            # we got something useful
            if not has_valid_content:
                has_valid_content = True

            # Do not include apps without a name
            if not 'C' in app.names:
                print 'IGNORE\t', f, '\t', "no Name"
                continue

            # Do not include apps without a summary
            if not 'C' in app.comments:
                print 'IGNORE\t', f, '\t', "no Comment"
                continue

            # Do not include apps without an icon
            if not app.icon:
                print 'IGNORE\t', f, '\t', "Icon unspecified"
                continue

            # write content
            app.write(xml)

        # create AppStream XML
        xml.write("</applications>\n")
        xml.close()
        if not has_valid_content:
            os.remove(xml_output_file)

        # create AppStream icon tar
        if has_valid_content:
            output_file = "./appstream/%s-icons.tar" % pkg.name
            print 'WRITING\t', output_file
            tar = tarfile.open(output_file, "w")
            files = glob.glob("./icons/*.png")
            for f in files:
                tar.add(f, arcname=f.split('/')[-1])
            tar.close()

        # remove tmp
        if not os.getenv('APPSTREAM_DEBUG'):
            shutil.rmtree('./tmp')
            shutil.rmtree('./icons')
Ejemplo n.º 2
0
    def add_appdata_file(self):

        # do we have an AppData file?
        filename = './tmp/usr/share/appdata/' + self.app_id + '.appdata.xml'
        fn_extra = '../appdata-extra/' + self.type_id + '/' + self.app_id + '.appdata.xml'
        if os.path.exists(filename) and os.path.exists(fn_extra):
            self.log.write(LoggerItem.INFO,
                           "deleting %s as upstream AppData file exists" % fn_extra)
            os.remove(fn_extra)

        # just use the extra file in places of the missing upstream one
        if os.path.exists(fn_extra):
            filename = fn_extra

        # need to extract details
        if not os.path.exists(filename):
            return False

        data = AppData()
        if not data.extract(filename):
            self.log.write(LoggerItem.WARNING,
                           "AppData file '%s' could not be parsed" % filename)
            return False

        # check AppData file validates
        enable_validation = self.type_id != 'font'
        if enable_validation and os.path.exists('/usr/bin/appdata-validate'):
            env = os.environ
            p = subprocess.Popen(['/usr/bin/appdata-validate',
                                  '--relax', filename],
                                 cwd='.', env=env, stdout=subprocess.PIPE)
            p.wait()
            if p.returncode:
                for line in p.stdout:
                    line = line.replace('\n', '').decode('utf-8')
                    self.log.write(LoggerItem.WARNING,
                                   "AppData did not validate: %s" % line)

        # check the id matches
        if data.get_id() != self.app_id and data.get_id() != self.app_id_full:
            self.log.write(LoggerItem.WARNING,
                           "The AppData id does not match: " + self.app_id)
            return False

        # check the licence is okay
        if data.get_licence() not in self.cfg.get_content_licences():
            self.log.write(LoggerItem.WARNING,
                           "The AppData licence is not okay for " +
                           self.app_id + ': \'' +
                           data.get_licence() + '\'')
            return False

        # if we have an override, use it for all languages
        tmp = data.get_names()
        if tmp:
            self.names = tmp

        # if we have an override, use it for all languages
        tmp = data.get_summaries()
        if tmp:
            self.comments = tmp

        # get metadata
        tmp = data.get_metadata()
        if tmp:
            # and extra packages we want to add in?
            if 'ExtraPackages' in tmp:
                for pkg in tmp['ExtraPackages'].split(','):
                    if pkg not in self.pkgnames:
                        self.pkgnames.append(pkg)
                del tmp['ExtraPackages']
            self.metadata.update(tmp)

        # get optional bits
        tmp = data.get_urls()
        if tmp:
            for key in tmp:
                self.urls[key] = tmp[key]
        tmp = data.get_project_group()
        if tmp:
            self.project_group = tmp
        try:
            self.descriptions = data.get_descriptions()
        except StandardError, e:
            self.log.write(LoggerItem.WARNING,
                           "failed to add description: %s" % str(e))