Esempio n. 1
0
    def __init__(self, system_bus, mainloop):
        # Init dbus service.
        dbus.service.Object.__init__(self, system_bus, DSC_SERVICE_PATH)
        # Init.
        self.mainloop = mainloop
        self.pkg_cache = AptCache()
        self.exit_flag = False
        self.simulate = False
        self.all_upgrade_pkg_names = []
        self.download_dir = "/var/cache/apt/archives"

        self.is_upgrading = False
        self.in_update_list = False

        self.apt_action_pool = AptActionPool(self.pkg_cache)
        self.apt_action_pool.start()

        global_event.register_event('parse-download-error',
                                    self.send_parse_download_error)

        global_event.register_event("action-start", self.action_start)
        global_event.register_event("action-update", self.action_update)
        global_event.register_event("action-finish", self.action_finish)
        global_event.register_event("action-failed", self.action_failed)

        global_event.register_event("download-start", self.download_start)
        global_event.register_event("download-update", self.download_update)
        global_event.register_event("download-finish", self.download_finish)
        global_event.register_event("download-stop", self.download_stop)
        global_event.register_event("download-error", self.download_failed)

        global_event.register_event("update-list-start",
                                    self.update_list_start)
        global_event.register_event("update-list-finish",
                                    self.update_list_finish)
        global_event.register_event("update-list-failed",
                                    self.update_list_failed)
        global_event.register_event("update-list-update",
                                    self.update_list_update)

        self.packages_status = {}

        self.exit_manager = ExitManager(self.mainloop,
                                        self.is_update_list_running,
                                        self.is_download_action_running,
                                        self.is_apt_action_running,
                                        self.have_exit_request)
        self.exit_manager.start()

        self.set_download_dir('/var/cache/apt/archives')
        self.download_manager = DownloadManager(global_event, verbose=True)
Esempio n. 2
0
    def __init__(self, system_bus, mainloop):
        # Init dbus service.
        dbus.service.Object.__init__(self, system_bus, DSC_SERVICE_PATH)
        # Init.
        self.mainloop = mainloop
        self.pkg_cache = AptCache()
        self.exit_flag = False
        self.simulate = False
        self.all_upgrade_pkg_names = []
        self.download_dir = "/var/cache/apt/archives"

        self.is_upgrading = False
        self.in_update_list = False

        self.apt_action_pool = AptActionPool(self.pkg_cache)
        self.apt_action_pool.start()

        global_event.register_event(
            'parse-download-error', self.send_parse_download_error)

        global_event.register_event("action-start", self.action_start)
        global_event.register_event("action-update", self.action_update)
        global_event.register_event("action-finish", self.action_finish)
        global_event.register_event("action-failed", self.action_failed)

        global_event.register_event("download-start", self.download_start)
        global_event.register_event("download-update", self.download_update)
        global_event.register_event("download-finish", self.download_finish)
        global_event.register_event("download-stop", self.download_stop)
        global_event.register_event("download-error", self.download_failed)

        global_event.register_event(
            "update-list-start", self.update_list_start)
        global_event.register_event(
            "update-list-finish", self.update_list_finish)
        global_event.register_event(
            "update-list-failed", self.update_list_failed)
        global_event.register_event(
            "update-list-update", self.update_list_update)

        self.packages_status = {}

        self.exit_manager = ExitManager(
            self.mainloop,
            self.is_update_list_running,
            self.is_download_action_running,
            self.is_apt_action_running,
            self.have_exit_request)
        self.exit_manager.start()

        self.set_download_dir('/var/cache/apt/archives')
        self.download_manager = DownloadManager(global_event, verbose=True)
class PackageManager(dbus.service.Object):
    '''
    docs
    '''

    def __init__(self, system_bus, mainloop):
        log("init dbus")
        
        # Init dbus service.
        dbus.service.Object.__init__(self, system_bus, DSC_SERVICE_PATH)
        # Init.
        self.mainloop = mainloop
        self.pkg_cache = AptCache()
        self.exit_flag = False
        self.simulate = False
        self.all_upgrade_pkg_names = []

        self.is_upgrading = False
        self.in_update_list = False
        
        self.apt_action_pool = AptActionPool(self.pkg_cache)
        self.apt_action_pool.start()

        global_event.register_event('parse-download-error', self.send_parse_download_error)

        global_event.register_event("action-start", self.action_start)
        global_event.register_event("action-update", self.action_update)
        global_event.register_event("action-finish", self.action_finish)
        global_event.register_event("action-failed", self.action_failed)
        
        global_event.register_event("download-start", self.download_start)
        global_event.register_event("download-update", self.download_update)
        global_event.register_event("download-finish", self.download_finish)
        global_event.register_event("download-stop", self.download_stop)
        global_event.register_event("download-error", self.download_failed)
        
        global_event.register_event("update-list-start", self.update_list_start)
        global_event.register_event("update-list-finish", self.update_list_finish)
        global_event.register_event("update-list-failed", self.update_list_failed)
        global_event.register_event("update-list-update", self.update_list_update)

        self.packages_status = {}
        
        self.exit_manager = ExitManager(
            self.mainloop,
            self.is_update_list_running,
            self.is_download_action_running,
            self.is_apt_action_running,
            self.have_exit_request)
        self.exit_manager.start()
        
        log("init finish")
        self.set_download_dir('/var/cache/apt/archives')
        self.init_download_manager(5)

    def download_start(self, pkg_name, action_type):
        utils.set_running_lock(True)
        self.update_signal([("download-start", (pkg_name, action_type))])
        if action_type == ACTION_UPGRADE:
            self.is_upgrading = True

    def download_update(self, pkg_name, action_type, data):
        self.update_signal([("download-update", (pkg_name, action_type, data))])
        if action_type == ACTION_UPGRADE:
            self.is_upgrading = True

    def download_stop(self, pkg_name, action_type):
        self.update_signal([("download-stop", (pkg_name, action_type))])
        self.exit_manager.check()    

        if action_type == ACTION_UPGRADE:
            self.is_upgrading = False
        
    def download_failed(self, pkg_name, action_type, e):
        logger.error("%s download failed with %s" % (pkg_name, e))
        utils.set_running_lock(False)
        self.update_signal([("download-failed", (pkg_name, action_type, e))])
        
        self.exit_manager.check()    

        if action_type == ACTION_UPGRADE:
            self.is_upgrading = False
           
    def download_finish(self, action_id, action_type, all_pkg_names):
        utils.set_running_lock(False)
        self.update_signal([("download-finish", (action_id, action_type))])
        
        if action_type == ACTION_INSTALL:
            self.apt_action_pool.add_install_action(all_pkg_names)
        elif action_type == ACTION_UPGRADE:
            self.start_upgrade(all_pkg_names, action_id)
            self.is_upgrading = False
            
        self.exit_manager.check()

    def action_start(self, signal_content):
        utils.set_running_lock(True)
        self.update_signal([("action-start", signal_content)])
        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = True
        
    def action_update(self, signal_content):
        self.update_signal([("action-update", signal_content)])

        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = True
        
    def action_finish(self, signal_content):
        utils.set_running_lock(False)
        pkg_name, action_type, pkg_info_list = signal_content
        if action_type == ACTION_INSTALL:
            for pkg_info in pkg_info_list:
                self.pkg_cache.set_pkg_status(pkg_name, self.pkg_cache.PKG_STATUS_INSTALLED)
        elif action_type == ACTION_UPGRADE:
            for pkg_info in pkg_info_list:
                self.pkg_cache.set_pkg_status(pkg_name, self.pkg_cache.PKG_STATUS_UPGRADED)
        elif action_type == ACTION_UNINSTALL:
            for pkg_info in pkg_info_list:
                self.pkg_cache.set_pkg_status(pkg_name, self.pkg_cache.PKG_STATUS_UNINSTALLED)

        self.update_signal([("action-finish", signal_content)])
        self.exit_manager.check()

        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = False

    def action_failed(self, signal_content):
        utils.set_running_lock(False)
        self.update_signal([("action-failed", signal_content)])
        
        self.exit_manager.check()
        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = False

    def is_update_list_running(self):
        return self.in_update_list
    
    def is_download_action_running(self):
        return len(self.download_manager.fetch_files_dict) > 0
    
    def is_apt_action_running(self):
        return len(self.apt_action_pool.active_mission_list) + len(self.apt_action_pool.wait_mission_list) > 0
    
    def have_exit_request(self):
        return self.exit_flag
        
    def update_list_start(self):
        self.in_update_list = True
        self.update_signal([("update-list-start", "")])

    def update_list_finish(self):
        self.update_signal([("update-list-merge", "")])
        self.pkg_cache.open(apb.OpProgress())
        db_build.BuildSoftwareDB(self.pkg_cache)

        self.update_signal([("update-list-finish", "")])
        self.in_update_list = False
        self.exit_manager.check()

    def update_list_failed(self):
        self.in_update_list = False
        self.update_signal([("update-list-failed", "")])
        
        self.exit_manager.check()
        
    def update_list_update(self, percent, status_message, speed_str):
        self.update_signal([("update-list-update", (percent, status_message, speed_str))])

    def handle_dbus_reply(self, *reply):
        log("%s (reply): %s" % (self.module_dbus_name, str(reply)))        
        
    def handle_dbus_error(self, *error):
        log("%s (error): %s" % (self.module_dbus_name, str(error)))

    def send_parse_download_error(self, pkg_name, action_type):
        self.update_signal([("parse-download-error", (pkg_name, action_type))])

    def get_unique_id(self):
        return str(uuid.uuid4())

    def get_real_pkg_name(self, pkg_name):
        if pkg_name in self.pkg_cache:
            return pkg_name
        elif (pkg_name + ":i386") in self.pkg_cache:
            return pkg_name + ":i386"
        else:
            return None

    def add_upgrade_download_with_new_policy(self, pkg_names, action_type):
        action_id = '%s_%s' % (self.get_unique_id(), action_type)
        self.update_signal([("ready-download-start", (action_id, action_type))])

        real_pkg_dict, not_in_cache = parse_pkg.get_real_pkg_dict(self.pkg_cache, pkg_names)
        if not_in_cache:
            self.update_signal([("pkgs-not-in-cache", (json.dumps(not_in_cache), action_type))])
        else:
            (all_change_pkgs, mark_failed_pkg_dict, marked_delete_sys_pkgs
                    ) = parse_pkg.get_changes_pkgs(self.pkg_cache, real_pkg_dict)

            if mark_failed_pkg_dict:
                self.update_signal([("pkgs-mark-failed", (json.dumps(mark_failed_pkg_dict.keys()), action_type))])

            elif marked_delete_sys_pkgs:
                self.update_signal([("marked-delete-system-pkgs", (json.dumps(marked_delete_sys_pkgs), action_type))])
            else:
                self.update_signal([("ready-download-finish", (action_id, action_type))])
                download_pkg_infos = parse_pkg.check_pkg_download_info(all_change_pkgs)
                if download_pkg_infos[0] == DOWNLOAD_STATUS_ERROR:
                    self.update_signal([("pkgs-parse-download-error", (str(download_pkg_infos[1]), action_type))])
                elif download_pkg_infos[0] == DOWNLOAD_STATUS_NOTNEED:
                    self.start_upgrade(pkg_names, action_id)
                else:
                    (names, download_urls, download_hash_infos, pkg_sizes) = download_pkg_infos
                    self.all_upgrade_pkg_names = all_change_pkgs
                    self.download_manager.add_download(
                                            action_id,
                                            action_type,
                                            download_urls,
                                            all_pkg_names=pkg_names,
                                            all_change_pkgs=all_change_pkgs,
                                            file_save_dir=self.download_dir,
                                            )
        
    def add_download(self, pkg_name, action_type, simulate=False):
        pkg_infos = get_pkg_download_info(self.pkg_cache, pkg_name)
        self.update_signal([("ready-download-finish", (pkg_name, action_type))])
        if pkg_infos[0] == DOWNLOAD_STATUS_NOTNEED:
            self.download_finish(pkg_name, action_type, [pkg_name,])
            print "Don't need download"
        elif pkg_infos[0] == DOWNLOAD_STATUS_ERROR:
            self.update_signal([("parse-download-error", (pkg_name, action_type))])
            print "Download error"
        else:
            (names, download_urls, download_hash_infos, pkg_sizes) = pkg_infos
            
            self.download_manager.add_download(
                                        pkg_name, 
                                        action_type, 
                                        download_urls, 
                                        all_pkg_names=[pkg_name,],
                                        file_save_dir=self.download_dir)

    def start_upgrade(self, pkg_names, action_id):
        self.apt_action_pool.add_multi_upgrade_mission(pkg_names, action_id)
        
    def del_source_list_d(self):
        white_list_path = os.path.join(get_parent_dir(__file__), 'white_list.txt')
        if os.path.exists(white_list_path):
            with open(white_list_path) as fp:
                for line in fp:
                    line = line.strip()
                    if os.path.exists(line):
                        os.remove(line)

    def get_desktops(self, pkg_name):
        desktops = []
        try:
            pkg_obj = self.pkg_cache[pkg_name]
            for f in pkg_obj.installed_files:
                if f.endswith(".desktop"):
                    desktops.append(f)
        except:
            pass
        return desktops

    @dbus.service.method(DSC_SERVICE_NAME, in_signature='', out_signature='as')
    def read_no_notify_config(self, no_notify_config_path):
        if os.path.exists(no_notify_config_path):
           no_notify_config_str = read_file(no_notify_config_path)
           try:
               no_notify_config = eval(no_notify_config_str)
               
               if type(no_notify_config).__name__ != "list":
                   no_notify_config = []
           except Exception:
               no_notify_config = []
               
           return no_notify_config
        else:
            return []

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def add_no_notify_pkg(self, info):
        pkg_name, path = info
        no_notify_config = self.read_no_notify_config(path)
        
        if pkg_name not in no_notify_config:
            pkg_name = str(pkg_name)
            no_notify_config.append(pkg_name)
            write_file(path, str(no_notify_config))

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def remove_no_notify_pkg(self, info):
        pkg_name, path = info
        pkg_name = str(pkg_name)
        path = str(path)
        no_notify_config = self.read_no_notify_config(path)
        
        if pkg_name in no_notify_config:
            write_file(path, str(filter(lambda config_pkg_name: config_pkg_name != pkg_name, no_notify_config)))

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="i", out_signature="")
    def init_download_manager(self, number):
        self.download_manager = DownloadManager(global_event, number, verbose=True)

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="")
    def set_download_dir(self, local_dir):
        apt_pkg.config.set("Dir::Cache::Archives", local_dir)
        self.download_dir = local_dir
    
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="ai")
    def get_download_size(self, pkg_name):
        total_size = 0
        pkg_infos = get_pkg_download_info(self.pkg_cache, pkg_name)
        if pkg_infos[0] == DOWNLOAD_STATUS_NOTNEED:
            total_size = get_pkg_own_size(self.pkg_cache, pkg_name)
            size_flag = PKG_SIZE_OWN
        elif pkg_infos[0] == DOWNLOAD_STATUS_ERROR:
            total_size = -1
            size_flag = PKG_SIZE_ERROR
        else:
            (names, download_urls, download_hash_infos, pkg_sizes) = pkg_infos
            for size in pkg_sizes:
                total_size += size
            size_flag = PKG_SIZE_DOWNLOAD
        return [size_flag, total_size]

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="as")
    def get_upgrade_download_size(self, pkg_names):
        real_pkg_dict, not_in_cache = parse_pkg.get_real_pkg_dict(self.pkg_cache, pkg_names)
        if not_in_cache:
            return ["-1", json.dumps([])]
        else:
            (all_change_pkgs, mark_failed_pkg_dict, marked_delete_sys_pkgs
                    ) = parse_pkg.get_changes_pkgs(self.pkg_cache, real_pkg_dict)

            download_pkg_infos = parse_pkg.check_pkg_download_info(all_change_pkgs)
            change_pkg_names = [pkg.name for pkg in all_change_pkgs]
            if download_pkg_infos[0] == DOWNLOAD_STATUS_ERROR:
                return ["-1", json.dumps([])]
            elif download_pkg_infos[0] == DOWNLOAD_STATUS_NOTNEED:
                return ["0", json.dumps(change_pkg_names)]
            else:
                (names, download_urls, download_hash_infos, pkg_sizes) = download_pkg_infos
                total_size = 0
                for size in pkg_sizes:
                    total_size += size
                return [str(total_size), json.dumps(change_pkg_names)]

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="ai")
    def clean_download_cache(self):
        '''Clean download cache.'''
        # get action packages.
        remain_pkgs = []
        for (pkg_name, info_dict) in self.download_manager.fetch_files_dict.items():
            remain_pkgs.append(pkg_name)

        for (pkg_name, info_dict) in self.apt_action_pool.install_action_dict.items():
            remain_pkgs.append(pkg_name)
        for (pkg_name, info_dict) in self.apt_action_pool.upgrade_action_dict.items():
            remain_pkgs.append(pkg_name)
        
        # Get depend packages.
        remain_pkgs_paths = []
        for pkg_name in remain_pkgs:
            result = get_pkg_dependence_file_path(self.pkg_cache, pkg_name)
            if not result:
                remain_pkgs_paths += result

        # Init clean size.
        packageNum = 0
        cleanSize = 0
                
        # Delete cache directory.
        cache_archive_dir = get_cache_archive_dir()
        if os.path.exists(cache_archive_dir):
            for root, folder, files in os.walk(cache_archive_dir):
                for file_name in files:
                    path = os.path.join(root, file_name)
                    if path.endswith(".deb") and (path not in remain_pkgs_paths):
                        packageNum += 1
                        cleanSize += os.path.getsize(path)
                        remove_file(path)

        return [packageNum, cleanSize]
        
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="b", out_signature="")    
    def say_hello(self, simulate):
        # Set exit_flag with False to prevent backend exit, 
        # this just useful that frontend start again before backend exit.
        log("Say hello from frontend.")
        
        self.exit_flag = False
        self.simulate = simulate
        
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")    
    def request_quit(self):
        # Set exit flag.
        self.exit_flag = True
        
        self.exit_manager.check()
        self.update_signal([("frontend-quit", "")])

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def change_source_list(self, repo_urls):
        ubuntu_repo_url, deepin_repo_url = repo_urls
        new_source_list_content = get_source_list_contents(ubuntu_repo_url, deepin_repo_url)
        os.system('cp %s %s.save' % (SOURCE_LIST, SOURCE_LIST))
        with open(SOURCE_LIST, 'w') as fp:
            fp.write(new_source_list_content)
        
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="(sas)")
    # def request_upgrade_pkgs(self):  // old api name
    def RequestUpgradeStatus(self):
        """
        Get upgrade status
        
        @return: Return (status_code, [json.dumps(pkg_name, pkg_version)]), 
        status code is in below constants:
            - normal: no dpkg action, just return packages that need to upgrade;
            - upgrading: in upgrading packages;
            - cache-updating: in updating apt cache;
        """
        if self.in_update_list:
            return ("cache-updating", [])
        elif self.is_upgrading:
            return ("upgrading", [])
        else:
            cache_upgrade_pkgs = self.pkg_cache.get_upgrade_pkgs()
            return ("normal", cache_upgrade_pkgs)
    
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="s")
    def request_uninstall_pkgs(self):
        return json.dumps(self.pkg_cache.get_uninstall_pkgs())

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="as")    
    def request_pkgs_install_version(self, pkg_names):
        pkg_versions = []
        for pkg_name in pkg_names:
            try:
                version = self.pkg_cache[pkg_name].versions[0].version
                pkg_versions.append(version)
            except:
                try:
                    version = self.pkg_cache[pkg_name+":i386"].versions[0].version
                    pkg_versions.append(version)
                except:
                    self.update_signal([("pkg-not-in-cache", pkg_name)])
        return pkg_versions

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="as")    
    def is_pkg_in_cache(self, pkg_name):
        result = []
        try:
            self.pkg_cache[pkg_name]
            result.append(pkg_name)
        except:
            try:
                pkg_name += ":i386"
                self.pkg_cache[pkg_name]
                result.append(pkg_name)
            except:
                pass
        return result

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="as")    
    def request_pkgs_uninstall_version(self, pkg_names):
        return self.pkg_cache.get_pkgs_uninstall_version(pkg_names)

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")    
    def install_pkg(self, pkg_names):
        for pkg_name in pkg_names:
            real_pkg_name = self.get_real_pkg_name(pkg_name)
            if real_pkg_name:
                ThreadMethod(self.add_download, (real_pkg_name, ACTION_INSTALL, self.simulate)).start()
            else:
                self.update_signal([("pkg-not-in-cache", pkg_name)])
    
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="sb", out_signature="")    
    def uninstall_pkg(self, pkg_name, purge):
        real_pkg_name = self.get_real_pkg_name(pkg_name)
        if real_pkg_name:
            self.apt_action_pool.add_uninstall_action(real_pkg_name, self.simulate, purge)
        else:
            self.update_signal([("pkg-not-in-cache", pkg_name)])

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="sb", out_signature="")
    def uninstall_pkg_from_desktop(self, desktop_path, purge):
        ThreadMethod(self.uninstall_pkg_from_desktop_thread, (desktop_path, purge)).start()

    def uninstall_pkg_from_desktop_thread(self, path, purge):
        pkg_name = self.get_pkg_name_from_path(path)
        if pkg_name:
            self.uninstall_pkg(pkg_name, purge)
        else:
            global_event.emit("action-failed", (path, ACTION_UNINSTALL, [], "no package found for path: %s" % path))

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="s")
    def get_pkg_name_from_path(self, path):
        result = subprocess.check_output(['dpkg', '-S', path]).strip().split(":")
        if len(result) == 2 and result[1].strip() == path.strip():
            return result[0].strip()
        else:
            return ""

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")    
    def upgrade_pkg(self, pkg_names):
        for pkg_name in pkg_names:
            real_pkg_name = self.get_real_pkg_name(pkg_name)
            if real_pkg_name:
                self.update_signal([("ready-download-start", (real_pkg_name, ACTION_UPGRADE))])
                ThreadMethod(self.add_download, (real_pkg_name, ACTION_UPGRADE, self.simulate)).start()
            else:
                self.update_signal([("pkg-not-in-cache", pkg_name)])

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")    
    def upgrade_pkgs_with_new_policy(self, pkg_names):
        ThreadMethod(self.add_upgrade_download_with_new_policy, (pkg_names, ACTION_UPGRADE)).start()

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")    
    def stop_download_pkg(self, pkg_names):
        for pkg_name in pkg_names:
            self.download_manager.stop_wait_download(pkg_name)

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")
    def cancel_upgrade_download(self):
        if getattr(self, 'upgrade_id'):
            self.download_manager.stop_wait_download(self.upgrade_id)
            
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")    
    def remove_wait_missions(self, pkg_infos):
        self.apt_action_pool.remove_wait_missions(pkg_infos)

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")    
    def remove_wait_downloads(self, pkg_names):
        for pkg_name in pkg_names:
            self.download_manager.stop_wait_download(pkg_name)
            
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="s")
    def request_pkg_short_desc(self, pkg_name):
        return self.pkg_cache.get_pkg_short_desc(pkg_name)
    
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="as")
    def request_status(self):
        download_status = {
            ACTION_INSTALL : [],
            ACTION_UPGRADE : []}
        for (pkg_name, info_dict) in self.download_manager.fetch_files_dict.items():
            if info_dict["action_type"] == ACTION_INSTALL:
                download_status[ACTION_INSTALL].append((pkg_name, info_dict["status"]))
            elif info_dict["action_type"] == ACTION_UPGRADE:
                download_status[ACTION_UPGRADE].append((pkg_name, info_dict["status"]))
                
        action_status = {
            ACTION_INSTALL : [],
            ACTION_UPGRADE : [],
            ACTION_UNINSTALL : []}        
        for (pkg_name, info_dict) in self.apt_action_pool.install_action_dict.items():
            action_status[ACTION_INSTALL].append((pkg_name, info_dict["status"]))
        for (pkg_name, info_dict) in self.apt_action_pool.upgrade_action_dict.items():
            action_status[ACTION_UPGRADE].append((pkg_name, info_dict["status"]))
        for (pkg_name, info_dict) in self.apt_action_pool.uninstall_action_dict.items():
            action_status[ACTION_UNINSTALL].append((pkg_name, info_dict["status"]))
        
        return [str(download_status), str(action_status)]
    
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")
    def start_update_list(self):
        log("start update list...")
        self.del_source_list_d()
        self.pkg_cache.open(apb.OpProgress())
        self.apt_action_pool.add_update_list_mission()
        log("start update list done")
        
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="ab")
    def request_pkgs_install_status(self, pkg_names):
        _status = []
        for pkg in pkg_names:
            _status.append(self.pkg_cache.is_pkg_installed(pkg))
        return _status
            
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="(si)", out_signature="")
    def set_pkg_status(self, pkg_status):
        pkg_name, status = pkg_status
        self.pkg_cache.set_pkg_status(pkg_name, pkg_status)

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="i")
    def get_pkg_installed(self, pkg_name):
        if self.is_pkg_in_cache(pkg_name):
            if self.pkg_cache.is_pkg_installed(pkg_name):
                return 1
            else:
                return 0
        else:
            return -1

    @dbus.service.method(DSC_SERVICE_NAME, in_signature="ss", out_signature="s")
    def get_pkg_start_status(self, pkg_name, start_pkg_names):
        is_current_installed = self.get_pkg_installed(pkg_name)
        if is_current_installed == -1:
            return "unknown"
        elif is_current_installed == 0:
            return "uninstalled"
        else:
            desktops = self.get_desktops(pkg_name)
            names = start_pkg_names.split(",")
            for name in names:
                if self.get_pkg_installed(name) == 1:
                    desktops += self.get_desktops(name)
            return json.dumps(desktops)

    @dbus.service.signal(DSC_SERVICE_NAME, signature='a(sv)')
    # Use below command for test:
    # dbus-monitor --system "type='signal', interface='com.linuxdeepin.softwarecenter'" 
    def update_signal(self, message):
        # The signal is emitted when this method exits
        # You can have code here if you wish
        pass
Esempio n. 4
0
class PackageManager(dbus.service.Object):
    '''
    docs
    '''
    def invoked_log(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            info = "dbus method invoked: %s, arguments: %s" % (func.__name__,
                                                               str(args[1:]))
            logger.debug(info)
            return func(*args, **kw)

        return wrapper

    def __init__(self, system_bus, mainloop):
        # Init dbus service.
        dbus.service.Object.__init__(self, system_bus, DSC_SERVICE_PATH)
        # Init.
        self.mainloop = mainloop
        self.pkg_cache = AptCache()
        self.exit_flag = False
        self.simulate = False
        self.all_upgrade_pkg_names = []
        self.download_dir = "/var/cache/apt/archives"

        self.is_upgrading = False
        self.in_update_list = False

        self.apt_action_pool = AptActionPool(self.pkg_cache)
        self.apt_action_pool.start()

        global_event.register_event('parse-download-error',
                                    self.send_parse_download_error)

        global_event.register_event("action-start", self.action_start)
        global_event.register_event("action-update", self.action_update)
        global_event.register_event("action-finish", self.action_finish)
        global_event.register_event("action-failed", self.action_failed)

        global_event.register_event("download-start", self.download_start)
        global_event.register_event("download-update", self.download_update)
        global_event.register_event("download-finish", self.download_finish)
        global_event.register_event("download-stop", self.download_stop)
        global_event.register_event("download-error", self.download_failed)

        global_event.register_event("update-list-start",
                                    self.update_list_start)
        global_event.register_event("update-list-finish",
                                    self.update_list_finish)
        global_event.register_event("update-list-failed",
                                    self.update_list_failed)
        global_event.register_event("update-list-update",
                                    self.update_list_update)

        self.packages_status = {}

        self.exit_manager = ExitManager(self.mainloop,
                                        self.is_update_list_running,
                                        self.is_download_action_running,
                                        self.is_apt_action_running,
                                        self.have_exit_request)
        self.exit_manager.start()

        self.set_download_dir('/var/cache/apt/archives')
        self.download_manager = DownloadManager(global_event, verbose=True)

    def download_start(self, pkg_name, action_type):
        utils.set_running_lock(True)
        self.update_signal([("download-start", (pkg_name, action_type))])
        if action_type == ACTION_UPGRADE:
            self.is_upgrading = True

    def download_update(self, pkg_name, action_type, data):
        self.update_signal([("download-update", (pkg_name, action_type, data))
                            ])
        if action_type == ACTION_UPGRADE:
            self.is_upgrading = True

    def download_stop(self, pkg_name, action_type):
        self.update_signal([("download-stop", (pkg_name, action_type))])
        self.exit_manager.check()

        if action_type == ACTION_UPGRADE:
            self.is_upgrading = False

    def download_failed(self, pkg_name, action_type, e):
        logger.error("%s download failed with %s" % (pkg_name, e))
        utils.set_running_lock(False)
        self.update_signal([("download-failed", (pkg_name, action_type, e))])

        self.exit_manager.check()

        if action_type == ACTION_UPGRADE:
            self.is_upgrading = False

    def download_finish(self, action_id, action_type, all_pkg_names):
        utils.set_running_lock(False)
        self.update_signal([("download-finish", (action_id, action_type))])

        if action_type == ACTION_INSTALL:
            self.apt_action_pool.add_install_action(all_pkg_names)
        elif action_type == ACTION_UPGRADE:
            self.start_upgrade(all_pkg_names, action_id)
            self.is_upgrading = False

        self.exit_manager.check()

    def action_start(self, signal_content):
        utils.set_running_lock(True)
        self.update_signal([("action-start", signal_content)])
        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = True

    def action_update(self, signal_content):
        self.update_signal([("action-update", signal_content)])

        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = True

    def action_finish(self, signal_content):
        utils.set_running_lock(False)
        pkg_name, action_type, pkg_info_list = signal_content
        if action_type == ACTION_INSTALL:
            for pkg_info in pkg_info_list:
                self.pkg_cache.set_pkg_status(
                    pkg_name, self.pkg_cache.PKG_STATUS_INSTALLED)
        elif action_type == ACTION_UPGRADE:
            for pkg_info in pkg_info_list:
                self.pkg_cache.set_pkg_status(
                    pkg_name, self.pkg_cache.PKG_STATUS_UPGRADED)
        elif action_type == ACTION_UNINSTALL:
            for pkg_info in pkg_info_list:
                self.pkg_cache.set_pkg_status(
                    pkg_name, self.pkg_cache.PKG_STATUS_UNINSTALLED)

        self.update_signal([("action-finish", signal_content)])
        self.exit_manager.check()

        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = False

    def action_failed(self, signal_content):
        utils.set_running_lock(False)
        self.update_signal([("action-failed", signal_content)])

        self.exit_manager.check()
        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = False

    def is_update_list_running(self):
        return self.in_update_list

    def is_download_action_running(self):
        return len(self.download_manager.download_task_info) > 0

    def is_apt_action_running(self):
        return len(self.apt_action_pool.active_mission_list) + len(
            self.apt_action_pool.wait_mission_list) > 0

    def have_exit_request(self):
        return self.exit_flag

    def update_list_start(self):
        self.in_update_list = True
        self.update_signal([("update-list-start", "")])

    def update_list_finish(self):
        self.update_signal([("update-list-merge", "")])
        self.pkg_cache.open(apb.OpProgress())
        db_build.BuildSoftwareDB(self.pkg_cache)

        self.update_signal([("update-list-finish", "")])
        self.in_update_list = False
        self.exit_manager.check()

    def update_list_failed(self):
        self.in_update_list = False
        self.update_signal([("update-list-failed", "")])

        self.exit_manager.check()

    def update_list_update(self, percent, status_message, speed_str):
        self.update_signal([("update-list-update", (percent, status_message,
                                                    speed_str))])

    def handle_dbus_reply(self, *reply):
        logger.info("%s (reply): %s" % (self.module_dbus_name, str(reply)))

    def handle_dbus_error(self, *error):
        logger.info("%s (error): %s" % (self.module_dbus_name, str(error)))

    def send_parse_download_error(self, pkg_name, action_type):
        self.update_signal([("parse-download-error", (pkg_name, action_type))])

    def get_unique_id(self):
        return str(uuid.uuid4())

    def get_real_pkg_name(self, pkg_name):
        if pkg_name in self.pkg_cache:
            return pkg_name
        elif (pkg_name + ":i386") in self.pkg_cache:
            return pkg_name + ":i386"
        else:
            return None

    def dist_upgrade(self):
        action_type = ACTION_UPGRADE
        action_id = '%s_%s' % (self.get_unique_id(), action_type)
        self.update_signal([("ready-download-start", (action_id, action_type))
                            ])

        dist_upgrade_changes = self.pkg_cache.get_dist_upgrade_changes()
        # detect and prevent the system components from being uninstalled
        pkg_in_white_list = []
        download_pkgs = []
        self.all_upgrade_pkg_names = []
        for pkg in dist_upgrade_changes["delete"]:
            name = pkg.name
            if name in SYS_PKG_WHITE_LIST:
                pkg_in_white_list.append(name)
        if len(pkg_in_white_list) > 0:
            self.update_signal([("remove-pkgs-in-white-list",
                                 (json.dumps(pkg_in_white_list), action_type))
                                ])
            logger.error("found remove system packages: %s" %
                         json.dumps(pkg_in_white_list))
        else:
            for status in dist_upgrade_changes:
                for pkg in dist_upgrade_changes[status]:
                    self.all_upgrade_pkg_names.append(pkg.name)
                    if status == "delete" or status == "keep":
                        continue
                    if not parse_pkg.pkg_file_has_exist(pkg):
                        download_pkgs.append(pkg)

            self.update_signal([("ready-download-finish", (action_id,
                                                           action_type))])
            if len(download_pkgs) == 0:
                global_event.emit("download-finish", action_id, action_type,
                                  self.all_upgrade_pkg_names)
            else:
                names = []
                download_urls = []
                download_hash_infos = []
                pkg_sizes = []
                for pkg in download_pkgs:
                    names.append(pkg.name)
                    download_urls.append(pkg.candidate.uri)
                    download_hash_infos.append(pkg.candidate.md5)
                    pkg_sizes.append(pkg.candidate.size)
                self.download_manager.add_download(
                    action_id,
                    action_type,
                    download_urls,
                    download_sizes=pkg_sizes,
                    download_md5s=download_hash_infos,
                    all_task_names=names,
                    all_change_pkgs=self.all_upgrade_pkg_names,
                    file_save_dir=self.download_dir)

    def add_download(self, pkg_name, action_type, simulate=False):
        installed = self.get_pkg_installed(pkg_name)
        if installed == 1:
            self.update_signal([("pkg-installed", (pkg_name, action_type))])
            return
        elif installed == -1:
            self.update_signal([("pkg-not-in-cache", (pkg_name, action_type))])
            return
        pkg_infos = get_pkg_download_info(self.pkg_cache, pkg_name)
        status = pkg_infos["status"]
        self.update_signal([("ready-download-finish", (pkg_name, action_type))
                            ])
        if status == DOWNLOAD_STATUS_NOTNEED:
            self.download_finish(pkg_name, action_type, [
                pkg_name,
            ])
        elif status == DOWNLOAD_STATUS_ERROR:
            self.update_signal([("parse-download-error", (pkg_name,
                                                          action_type))])
        else:
            names = []
            download_urls = []
            download_hash_infos = []
            pkg_sizes = []
            for info in pkg_infos["info"]:
                names.append(info["name"])
                download_urls.append(info["url"])
                download_hash_infos.append(info["hash"])
                pkg_sizes.append(info["size"])

            self.download_manager.add_download(
                pkg_name,
                action_type,
                download_urls,
                download_sizes=pkg_sizes,
                download_md5s=download_hash_infos,
                all_task_names=[pkg_name],
                file_save_dir=self.download_dir)

    def start_upgrade(self, pkg_names, action_id):
        self.apt_action_pool.add_multi_upgrade_mission(pkg_names, action_id)

    def del_source_list_d(self):
        white_list_path = os.path.join(get_parent_dir(__file__),
                                       'white_list.txt')
        if os.path.exists(white_list_path):
            with open(white_list_path) as fp:
                for line in fp:
                    line = line.strip()
                    if os.path.exists(line):
                        os.remove(line)

    def get_desktops(self, pkg_name):
        desktops = []
        try:
            pkg_obj = self.pkg_cache[pkg_name]
            for f in pkg_obj.installed_files:
                if f.endswith(".desktop"):
                    desktops.append(f)
        except:
            pass
        return desktops

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature='', out_signature='as')
    def read_no_notify_config(self, no_notify_config_path):
        if os.path.exists(no_notify_config_path):
            no_notify_config_str = read_file(no_notify_config_path)
            try:
                no_notify_config = eval(no_notify_config_str)

                if type(no_notify_config).__name__ != "list":
                    no_notify_config = []
            except Exception:
                no_notify_config = []

            return no_notify_config
        else:
            return []

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def add_no_notify_pkg(self, info):
        pkg_name, path = info
        no_notify_config = self.read_no_notify_config(path)

        if pkg_name not in no_notify_config:
            pkg_name = str(pkg_name)
            no_notify_config.append(pkg_name)
            write_file(path, str(no_notify_config))

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def remove_no_notify_pkg(self, info):
        pkg_name, path = info
        pkg_name = str(pkg_name)
        path = str(path)
        no_notify_config = self.read_no_notify_config(path)

        if pkg_name in no_notify_config:
            write_file(
                path,
                str(
                    filter(lambda config_pkg_name: config_pkg_name != pkg_name,
                           no_notify_config)))

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="i", out_signature="")
    def init_download_manager(self, number):
        pass

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="")
    def set_download_dir(self, local_dir):
        apt_pkg.config.set("Dir::Cache::Archives", local_dir)
        self.download_dir = local_dir

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME,
                         in_signature="s",
                         out_signature="ai")
    def get_download_size(self, pkg_name):
        total_size = 0
        pkg_infos = get_pkg_download_info(self.pkg_cache, pkg_name)
        status = pkg_infos["status"]
        if status == DOWNLOAD_STATUS_NOTNEED:
            total_size = get_pkg_own_size(self.pkg_cache, pkg_name)
            size_flag = PKG_SIZE_OWN
        elif status == DOWNLOAD_STATUS_ERROR:
            total_size = -1
            size_flag = PKG_SIZE_ERROR
        else:
            for info in pkg_infos["info"]:
                total_size += info["size"]
            size_flag = PKG_SIZE_DOWNLOAD
        return [size_flag, total_size]

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="ai")
    def clean_download_cache(self):
        '''Clean download cache.'''
        # get action packages.
        remain_pkgs = []
        for pkg_name in self.download_manager.task_name_to_id.keys():
            remain_pkgs.append(pkg_name)

        for pkg_name in self.apt_action_pool.install_action_dict.keys():
            remain_pkgs.append(pkg_name)
        for pkg_name in self.apt_action_pool.upgrade_action_dict.keys():
            remain_pkgs.append(pkg_name)

        # Get depend packages.
        remain_pkgs_paths = []
        for pkg_name in remain_pkgs:
            result = get_pkg_dependence_file_path(self.pkg_cache, pkg_name)
            if not result:
                remain_pkgs_paths += result

        # Init clean size.
        packageNum = 0
        cleanSize = 0

        # Delete cache directory.
        cache_archive_dir = get_cache_archive_dir()
        if os.path.exists(cache_archive_dir):
            for root, folder, files in os.walk(cache_archive_dir):
                for file_name in files:
                    path = os.path.join(root, file_name)
                    if path.endswith(".deb") and (path
                                                  not in remain_pkgs_paths):
                        packageNum += 1
                        cleanSize += os.path.getsize(path)
                        remove_file(path)

        return [packageNum, cleanSize]

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="b", out_signature="")
    def say_hello(self, simulate):
        # Set exit_flag with False to prevent backend exit,
        # this just useful that frontend start again before backend exit.

        self.exit_flag = False
        self.simulate = simulate

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")
    def request_quit(self):
        # Set exit flag.
        self.exit_flag = True

        self.exit_manager.check()
        self.update_signal([("frontend-quit", "")])

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def change_source_list(self, repo_urls):
        ubuntu_repo_url, deepin_repo_url = repo_urls
        new_source_list_content = get_source_list_contents(
            ubuntu_repo_url, deepin_repo_url)
        os.system('cp %s %s.save' % (SOURCE_LIST, SOURCE_LIST))
        with open(SOURCE_LIST, 'w') as fp:
            fp.write(new_source_list_content)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME,
                         in_signature="",
                         out_signature="(ss)")
    def RequestUpgradeStatus(self):
        if self.in_update_list:
            return ("cache-updating", json.dumps([]))
        elif self.is_upgrading:
            return ("upgrading", json.dumps([]))
        else:
            dist_upgrade_changes = self.pkg_cache.get_dist_upgrade_changes()
            return_infos = []
            for status in dist_upgrade_changes:
                for pkg in dist_upgrade_changes[status]:
                    return_infos.append(
                        dict(status=status,
                             name=pkg.name,
                             version=pkg.candidate.version,
                             size=pkg.candidate.size,
                             downloaded=parse_pkg.pkg_file_has_exist(pkg)))
            return ("normal", json.dumps(return_infos))

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME,
                         in_signature="a(si)",
                         out_signature="")
    def RemoveWaitMissions(self, pkg_infos):
        self.apt_action_pool.remove_wait_missions(pkg_infos)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="s")
    def request_uninstall_pkgs(self):
        return json.dumps(self.pkg_cache.get_uninstall_pkgs())

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME,
                         in_signature="as",
                         out_signature="as")
    def request_pkgs_install_version(self, pkg_names):
        pkg_versions = []
        for pkg_name in pkg_names:
            try:
                version = self.pkg_cache[pkg_name].versions[0].version
                pkg_versions.append(version)
            except:
                try:
                    version = self.pkg_cache[pkg_name +
                                             ":i386"].versions[0].version
                    pkg_versions.append(version)
                except:
                    self.update_signal([("pkg-not-in-cache", pkg_name)])
        return pkg_versions

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME,
                         in_signature="s",
                         out_signature="as")
    def is_pkg_in_cache(self, pkg_name):
        result = []
        try:
            self.pkg_cache[pkg_name]
            result.append(pkg_name)
        except:
            try:
                pkg_name += ":i386"
                self.pkg_cache[pkg_name]
                result.append(pkg_name)
            except:
                pass
        return result

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME,
                         in_signature="as",
                         out_signature="as")
    def request_pkgs_uninstall_version(self, pkg_names):
        return self.pkg_cache.get_pkgs_uninstall_version(pkg_names)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def install_pkg(self, pkg_names):
        for pkg_name in pkg_names:
            real_pkg_name = self.get_real_pkg_name(pkg_name)
            if real_pkg_name:
                ThreadMethod(
                    self.add_download,
                    (real_pkg_name, ACTION_INSTALL, self.simulate)).start()
            else:
                self.update_signal([("pkg-not-in-cache", pkg_name)])

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="sb", out_signature="")
    def uninstall_pkg(self, pkg_name, purge):
        real_pkg_name = self.get_real_pkg_name(pkg_name)
        if real_pkg_name:
            self.apt_action_pool.add_uninstall_action(real_pkg_name,
                                                      self.simulate, purge)
        else:
            self.update_signal([("pkg-not-in-cache", pkg_name)])

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="sb", out_signature="")
    def uninstall_pkg_from_desktop(self, desktop_path, purge):
        ThreadMethod(self.uninstall_pkg_from_desktop_thread,
                     (desktop_path, purge)).start()

    def uninstall_pkg_from_desktop_thread(self, path, purge):
        pkg_name = self.get_pkg_name_from_path(path)
        if pkg_name:
            self.uninstall_pkg(pkg_name, purge)
        else:
            global_event.emit("action-failed",
                              (path, ACTION_UNINSTALL, [],
                               "no package found for path: %s" % path))

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="s")
    def get_pkg_name_from_path(self, path):
        pkg_name = utils.file_path_to_package_name(path)
        if pkg_name == "" and path.endswith(".desktop"):
            desktop_name = os.path.split(path)[1]
            path = utils.desktop_name_to_desktop_path(desktop_name)
            pkg_name = utils.file_path_to_package_name(path)
        return pkg_name

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def upgrade_pkg(self, pkg_names):
        for pkg_name in pkg_names:
            real_pkg_name = self.get_real_pkg_name(pkg_name)
            if real_pkg_name:
                self.update_signal([("ready-download-start",
                                     (real_pkg_name, ACTION_UPGRADE))])
                ThreadMethod(
                    self.add_download,
                    (real_pkg_name, ACTION_UPGRADE, self.simulate)).start()
            else:
                self.update_signal([("pkg-not-in-cache", pkg_name)])

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")
    def DistUpgrade(self):
        ThreadMethod(self.dist_upgrade).start()

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def stop_download_pkg(self, pkg_names):
        for pkg_name in pkg_names:
            self.download_manager.stop_wait_download(pkg_name)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")
    def cancel_upgrade_download(self):
        if getattr(self, 'upgrade_id'):
            self.download_manager.stop_wait_download(self.upgrade_id)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def remove_wait_downloads(self, pkg_names):
        for pkg_name in pkg_names:
            self.download_manager.stop_wait_download(pkg_name)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="s")
    def request_pkg_short_desc(self, pkg_name):
        return self.pkg_cache.get_pkg_short_desc(pkg_name)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="as")
    def request_status(self):
        download_status = {ACTION_INSTALL: [], ACTION_UPGRADE: []}
        for info_dict in self.download_manager.download_task_info.values():
            pkg_name = info_dict["task_name"]
            if info_dict["action_type"] == ACTION_INSTALL:
                download_status[ACTION_INSTALL].append(
                    (pkg_name, info_dict["status"]))
            elif info_dict["action_type"] == ACTION_UPGRADE:
                download_status[ACTION_UPGRADE].append(
                    (pkg_name, info_dict["status"]))

        action_status = {
            ACTION_INSTALL: [],
            ACTION_UPGRADE: [],
            ACTION_UNINSTALL: []
        }
        for info_dict in self.apt_action_pool.install_action_dict.values():
            pkg_name = info_dict["task_name"]
            action_status[ACTION_INSTALL].append(
                (pkg_name, info_dict["status"]))

        for info_dict in self.apt_action_pool.upgrade_action_dict.values():
            pkg_name = info_dict["task_name"]
            action_status[ACTION_UPGRADE].append(
                (pkg_name, info_dict["status"]))

        for info_dict in self.apt_action_pool.uninstall_action_dict.values():
            pkg_name = info_dict["task_name"]
            action_status[ACTION_UNINSTALL].append(
                (pkg_name, info_dict["status"]))

        return [str(download_status), str(action_status)]

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")
    def start_update_list(self):
        self.del_source_list_d()
        self.pkg_cache.open(apb.OpProgress())
        self.apt_action_pool.add_update_list_mission()

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME,
                         in_signature="as",
                         out_signature="ab")
    def request_pkgs_install_status(self, pkg_names):
        _status = []
        for pkg in pkg_names:
            _status.append(self.pkg_cache.is_pkg_installed(pkg))
        return _status

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME,
                         in_signature="(si)",
                         out_signature="")
    def set_pkg_status(self, pkg_status):
        pkg_name, status = pkg_status
        self.pkg_cache.set_pkg_status(pkg_name, pkg_status)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="i")
    def get_pkg_installed(self, pkg_name):
        if self.is_pkg_in_cache(pkg_name):
            if self.pkg_cache.is_pkg_installed(pkg_name):
                return 1
            else:
                return 0
        else:
            return -1

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME,
                         in_signature="ss",
                         out_signature="s")
    def get_pkg_start_status(self, pkg_name, start_pkg_names):
        is_current_installed = self.get_pkg_installed(pkg_name)
        if is_current_installed == -1:
            return "unknown"
        elif is_current_installed == 0:
            return "uninstalled"
        else:
            desktops = self.get_desktops(pkg_name)
            names = start_pkg_names.split(",")
            for name in names:
                if self.get_pkg_installed(name) == 1:
                    desktops += self.get_desktops(name)
            return json.dumps(desktops)

    @dbus.service.signal(DSC_SERVICE_NAME, signature='a(sv)')
    # Use below command for test:
    # dbus-monitor --system "type='signal', interface='com.linuxdeepin.softwarecenter'"
    def update_signal(self, message):
        # The signal is emitted when this method exits
        # You can have code here if you wish
        info = str(message)
        logger.debug("dbus signal emit: %s" % info)
Esempio n. 5
0
class PackageManager(dbus.service.Object):
    '''
    docs
    '''

    def invoked_log(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            info = "dbus method invoked: %s, arguments: %s" % (
                func.__name__, str(args[1:]))
            logger.debug(info)
            return func(*args, **kw)
        return wrapper

    def __init__(self, system_bus, mainloop):
        # Init dbus service.
        dbus.service.Object.__init__(self, system_bus, DSC_SERVICE_PATH)
        # Init.
        self.mainloop = mainloop
        self.pkg_cache = AptCache()
        self.exit_flag = False
        self.simulate = False
        self.all_upgrade_pkg_names = []
        self.download_dir = "/var/cache/apt/archives"

        self.is_upgrading = False
        self.in_update_list = False

        self.apt_action_pool = AptActionPool(self.pkg_cache)
        self.apt_action_pool.start()

        global_event.register_event(
            'parse-download-error', self.send_parse_download_error)

        global_event.register_event("action-start", self.action_start)
        global_event.register_event("action-update", self.action_update)
        global_event.register_event("action-finish", self.action_finish)
        global_event.register_event("action-failed", self.action_failed)

        global_event.register_event("download-start", self.download_start)
        global_event.register_event("download-update", self.download_update)
        global_event.register_event("download-finish", self.download_finish)
        global_event.register_event("download-stop", self.download_stop)
        global_event.register_event("download-error", self.download_failed)

        global_event.register_event(
            "update-list-start", self.update_list_start)
        global_event.register_event(
            "update-list-finish", self.update_list_finish)
        global_event.register_event(
            "update-list-failed", self.update_list_failed)
        global_event.register_event(
            "update-list-update", self.update_list_update)

        self.packages_status = {}

        self.exit_manager = ExitManager(
            self.mainloop,
            self.is_update_list_running,
            self.is_download_action_running,
            self.is_apt_action_running,
            self.have_exit_request)
        self.exit_manager.start()

        self.set_download_dir('/var/cache/apt/archives')
        self.download_manager = DownloadManager(global_event, verbose=True)

    def download_start(self, pkg_name, action_type):
        utils.set_running_lock(True)
        self.update_signal([("download-start", (pkg_name, action_type))])
        if action_type == ACTION_UPGRADE:
            self.is_upgrading = True

    def download_update(self, pkg_name, action_type, data):
        self.update_signal([("download-update", (
            pkg_name, action_type, data))])
        if action_type == ACTION_UPGRADE:
            self.is_upgrading = True

    def download_stop(self, pkg_name, action_type):
        self.update_signal([("download-stop", (pkg_name, action_type))])
        self.exit_manager.check()

        if action_type == ACTION_UPGRADE:
            self.is_upgrading = False

    def download_failed(self, pkg_name, action_type, e):
        logger.error("%s download failed with %s" % (pkg_name, e))
        utils.set_running_lock(False)
        self.update_signal([("download-failed", (pkg_name, action_type, e))])

        self.exit_manager.check()

        if action_type == ACTION_UPGRADE:
            self.is_upgrading = False

    def download_finish(self, action_id, action_type, all_pkg_names):
        utils.set_running_lock(False)
        self.update_signal([("download-finish", (action_id, action_type))])

        if action_type == ACTION_INSTALL:
            self.apt_action_pool.add_install_action(all_pkg_names)
        elif action_type == ACTION_UPGRADE:
            self.start_upgrade(all_pkg_names, action_id)
            self.is_upgrading = False

        self.exit_manager.check()

    def action_start(self, signal_content):
        utils.set_running_lock(True)
        self.update_signal([("action-start", signal_content)])
        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = True

    def action_update(self, signal_content):
        self.update_signal([("action-update", signal_content)])

        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = True

    def action_finish(self, signal_content):
        utils.set_running_lock(False)
        pkg_name, action_type, pkg_info_list = signal_content
        if action_type == ACTION_INSTALL:
            for pkg_info in pkg_info_list:
                self.pkg_cache.set_pkg_status(
                    pkg_name, self.pkg_cache.PKG_STATUS_INSTALLED)
        elif action_type == ACTION_UPGRADE:
            for pkg_info in pkg_info_list:
                self.pkg_cache.set_pkg_status(
                    pkg_name, self.pkg_cache.PKG_STATUS_UPGRADED)
        elif action_type == ACTION_UNINSTALL:
            for pkg_info in pkg_info_list:
                self.pkg_cache.set_pkg_status(
                    pkg_name, self.pkg_cache.PKG_STATUS_UNINSTALLED)

        self.update_signal([("action-finish", signal_content)])
        self.exit_manager.check()

        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = False

    def action_failed(self, signal_content):
        utils.set_running_lock(False)
        self.update_signal([("action-failed", signal_content)])

        self.exit_manager.check()
        if signal_content[1] == ACTION_UPGRADE:
            self.is_upgrading = False

    def is_update_list_running(self):
        return self.in_update_list

    def is_download_action_running(self):
        return len(self.download_manager.download_task_info) > 0

    def is_apt_action_running(self):
        return len(self.apt_action_pool.active_mission_list) + len(
            self.apt_action_pool.wait_mission_list) > 0

    def have_exit_request(self):
        return self.exit_flag

    def update_list_start(self):
        self.in_update_list = True
        self.update_signal([("update-list-start", "")])

    def update_list_finish(self):
        self.update_signal([("update-list-merge", "")])
        self.pkg_cache.open(apb.OpProgress())
        db_build.BuildSoftwareDB(self.pkg_cache)

        self.update_signal([("update-list-finish", "")])
        self.in_update_list = False
        self.exit_manager.check()

    def update_list_failed(self):
        self.in_update_list = False
        self.update_signal([("update-list-failed", "")])

        self.exit_manager.check()

    def update_list_update(self, percent, status_message, speed_str):
        self.update_signal([(
            "update-list-update", (percent, status_message, speed_str))])

    def handle_dbus_reply(self, *reply):
        logger.info("%s (reply): %s" % (self.module_dbus_name, str(reply)))

    def handle_dbus_error(self, *error):
        logger.info("%s (error): %s" % (self.module_dbus_name, str(error)))

    def send_parse_download_error(self, pkg_name, action_type):
        self.update_signal([("parse-download-error", (pkg_name, action_type))])

    def get_unique_id(self):
        return str(uuid.uuid4())

    def get_real_pkg_name(self, pkg_name):
        if pkg_name in self.pkg_cache:
            return pkg_name
        elif (pkg_name + ":i386") in self.pkg_cache:
            return pkg_name + ":i386"
        else:
            return None

    def dist_upgrade(self):
        action_type = ACTION_UPGRADE
        action_id = '%s_%s' % (self.get_unique_id(), action_type)
        self.update_signal([(
            "ready-download-start", (action_id, action_type))])

        dist_upgrade_changes = self.pkg_cache.get_dist_upgrade_changes()
        # detect and prevent the system components from being uninstalled
        pkg_in_white_list = []
        download_pkgs = []
        self.all_upgrade_pkg_names = []
        for pkg in dist_upgrade_changes["delete"]:
            name = pkg.name
            if name in SYS_PKG_WHITE_LIST:
                pkg_in_white_list.append(name)
        if len(pkg_in_white_list) > 0:
            self.update_signal([(
                "remove-pkgs-in-white-list",
                (json.dumps(pkg_in_white_list), action_type))])
            logger.error("found remove system packages: %s" %
                json.dumps(pkg_in_white_list))
        else:
            for status in dist_upgrade_changes:
                for pkg in dist_upgrade_changes[status]:
                    self.all_upgrade_pkg_names.append(pkg.name)
                    if status == "delete" or status == "keep":
                        continue
                    if not parse_pkg.pkg_file_has_exist(pkg):
                        download_pkgs.append(pkg)

            self.update_signal([("ready-download-finish", (action_id, action_type))])
            if len(download_pkgs) == 0:
                global_event.emit("download-finish", action_id, action_type,
                        self.all_upgrade_pkg_names)
            else:
                names = []
                download_urls = []
                download_hash_infos = []
                pkg_sizes = []
                for pkg in download_pkgs:
                    names.append(pkg.name)
                    download_urls.append(pkg.candidate.uri)
                    download_hash_infos.append(pkg.candidate.md5)
                    pkg_sizes.append(pkg.candidate.size)
                self.download_manager.add_download(
                    action_id,
                    action_type,
                    download_urls,
                    download_sizes=pkg_sizes,
                    download_md5s=download_hash_infos,
                    all_task_names=names,
                    all_change_pkgs=self.all_upgrade_pkg_names,
                    file_save_dir=self.download_dir
                    )

    def add_download(self, pkg_name, action_type, simulate=False):
        installed = self.get_pkg_installed(pkg_name)
        if installed == 1:
            self.update_signal([("pkg-installed", (pkg_name, action_type))])
            return
        elif installed == -1:
            self.update_signal([("pkg-not-in-cache", (pkg_name, action_type))])
            return
        pkg_infos = get_pkg_download_info(self.pkg_cache, pkg_name)
        status = pkg_infos["status"]
        self.update_signal([("ready-download-finish", (pkg_name, action_type))])
        if status == DOWNLOAD_STATUS_NOTNEED:
            self.download_finish(pkg_name, action_type, [pkg_name,])
        elif status == DOWNLOAD_STATUS_ERROR:
            self.update_signal([("parse-download-error", (pkg_name, action_type))])
        else:
            names = []
            download_urls = []
            download_hash_infos = []
            pkg_sizes = []
            for info in pkg_infos["info"]:
                names.append(info["name"])
                download_urls.append(info["url"])
                download_hash_infos.append(info["hash"])
                pkg_sizes.append(info["size"])

            self.download_manager.add_download(
                                        pkg_name,
                                        action_type,
                                        download_urls,
                                        download_sizes=pkg_sizes,
                                        download_md5s=download_hash_infos,
                                        all_task_names=[pkg_name],
                                        file_save_dir=self.download_dir
                                        )

    def start_upgrade(self, pkg_names, action_id):
        self.apt_action_pool.add_multi_upgrade_mission(pkg_names, action_id)

    def del_source_list_d(self):
        white_list_path = os.path.join(get_parent_dir(__file__), 'white_list.txt')
        if os.path.exists(white_list_path):
            with open(white_list_path) as fp:
                for line in fp:
                    line = line.strip()
                    if os.path.exists(line):
                        os.remove(line)

    def get_desktops(self, pkg_name):
        desktops = []
        try:
            pkg_obj = self.pkg_cache[pkg_name]
            for f in pkg_obj.installed_files:
                if f.endswith(".desktop"):
                    desktops.append(f)
        except:
            pass
        return desktops

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature='', out_signature='as')
    def read_no_notify_config(self, no_notify_config_path):
        if os.path.exists(no_notify_config_path):
            no_notify_config_str = read_file(no_notify_config_path)
            try:
                no_notify_config = eval(no_notify_config_str)

                if type(no_notify_config).__name__ != "list":
                    no_notify_config = []
            except Exception:
                no_notify_config = []

            return no_notify_config
        else:
            return []

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def add_no_notify_pkg(self, info):
        pkg_name, path = info
        no_notify_config = self.read_no_notify_config(path)

        if pkg_name not in no_notify_config:
            pkg_name = str(pkg_name)
            no_notify_config.append(pkg_name)
            write_file(path, str(no_notify_config))

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def remove_no_notify_pkg(self, info):
        pkg_name, path = info
        pkg_name = str(pkg_name)
        path = str(path)
        no_notify_config = self.read_no_notify_config(path)

        if pkg_name in no_notify_config:
            write_file(path, str(filter(
                lambda config_pkg_name: config_pkg_name != pkg_name,
                no_notify_config)))

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="i", out_signature="")
    def init_download_manager(self, number):
        pass

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="")
    def set_download_dir(self, local_dir):
        apt_pkg.config.set("Dir::Cache::Archives", local_dir)
        self.download_dir = local_dir

    @invoked_log
    @dbus.service.method(
        DSC_SERVICE_NAME, in_signature="s", out_signature="ai")
    def get_download_size(self, pkg_name):
        total_size = 0
        pkg_infos = get_pkg_download_info(self.pkg_cache, pkg_name)
        status = pkg_infos["status"]
        if status == DOWNLOAD_STATUS_NOTNEED:
            total_size = get_pkg_own_size(self.pkg_cache, pkg_name)
            size_flag = PKG_SIZE_OWN
        elif status == DOWNLOAD_STATUS_ERROR:
            total_size = -1
            size_flag = PKG_SIZE_ERROR
        else:
            for info in pkg_infos["info"]:
                total_size += info["size"]
            size_flag = PKG_SIZE_DOWNLOAD
        return [size_flag, total_size]

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="ai")
    def clean_download_cache(self):
        '''Clean download cache.'''
        # get action packages.
        remain_pkgs = []
        for pkg_name in self.download_manager.task_name_to_id.keys():
            remain_pkgs.append(pkg_name)

        for pkg_name in self.apt_action_pool.install_action_dict.keys():
            remain_pkgs.append(pkg_name)
        for pkg_name in self.apt_action_pool.upgrade_action_dict.keys():
            remain_pkgs.append(pkg_name)

        # Get depend packages.
        remain_pkgs_paths = []
        for pkg_name in remain_pkgs:
            result = get_pkg_dependence_file_path(self.pkg_cache, pkg_name)
            if not result:
                remain_pkgs_paths += result

        # Init clean size.
        packageNum = 0
        cleanSize = 0

        # Delete cache directory.
        cache_archive_dir = get_cache_archive_dir()
        if os.path.exists(cache_archive_dir):
            for root, folder, files in os.walk(cache_archive_dir):
                for file_name in files:
                    path = os.path.join(root, file_name)
                    if path.endswith(".deb") and (
                            path not in remain_pkgs_paths):
                        packageNum += 1
                        cleanSize += os.path.getsize(path)
                        remove_file(path)

        return [packageNum, cleanSize]

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="b", out_signature="")
    def say_hello(self, simulate):
        # Set exit_flag with False to prevent backend exit,
        # this just useful that frontend start again before backend exit.

        self.exit_flag = False
        self.simulate = simulate

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")
    def request_quit(self):
        # Set exit flag.
        self.exit_flag = True

        self.exit_manager.check()
        self.update_signal([("frontend-quit", "")])

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def change_source_list(self, repo_urls):
        ubuntu_repo_url, deepin_repo_url = repo_urls
        new_source_list_content = get_source_list_contents(
            ubuntu_repo_url, deepin_repo_url)
        os.system('cp %s %s.save' % (SOURCE_LIST, SOURCE_LIST))
        with open(SOURCE_LIST, 'w') as fp:
            fp.write(new_source_list_content)

    @invoked_log
    @dbus.service.method(
        DSC_SERVICE_NAME, in_signature="", out_signature="(ss)")
    def RequestUpgradeStatus(self):
        if self.in_update_list:
            return ("cache-updating", json.dumps([]))
        elif self.is_upgrading:
            return ("upgrading", json.dumps([]))
        else:
            dist_upgrade_changes = self.pkg_cache.get_dist_upgrade_changes()
            return_infos = []
            for status in dist_upgrade_changes:
                for pkg in dist_upgrade_changes[status]:
                    return_infos.append(dict(
                        status=status,
                        name=pkg.name,
                        version=pkg.candidate.version,
                        size=pkg.candidate.size,
                        downloaded=parse_pkg.pkg_file_has_exist(pkg)
                        ))
            return ("normal", json.dumps(return_infos))

    @invoked_log
    @dbus.service.method(
        DSC_SERVICE_NAME, in_signature="a(si)", out_signature="")
    def RemoveWaitMissions(self, pkg_infos):
        self.apt_action_pool.remove_wait_missions(pkg_infos)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="s")
    def request_uninstall_pkgs(self):
        return json.dumps(self.pkg_cache.get_uninstall_pkgs())

    @invoked_log
    @dbus.service.method(
        DSC_SERVICE_NAME, in_signature="as", out_signature="as")
    def request_pkgs_install_version(self, pkg_names):
        pkg_versions = []
        for pkg_name in pkg_names:
            try:
                version = self.pkg_cache[pkg_name].versions[0].version
                pkg_versions.append(version)
            except:
                try:
                    version = self.pkg_cache[pkg_name+":i386"].versions[0].version
                    pkg_versions.append(version)
                except:
                    self.update_signal([("pkg-not-in-cache", pkg_name)])
        return pkg_versions

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="as")
    def is_pkg_in_cache(self, pkg_name):
        result = []
        try:
            self.pkg_cache[pkg_name]
            result.append(pkg_name)
        except:
            try:
                pkg_name += ":i386"
                self.pkg_cache[pkg_name]
                result.append(pkg_name)
            except:
                pass
        return result

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="as")
    def request_pkgs_uninstall_version(self, pkg_names):
        return self.pkg_cache.get_pkgs_uninstall_version(pkg_names)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def install_pkg(self, pkg_names):
        for pkg_name in pkg_names:
            real_pkg_name = self.get_real_pkg_name(pkg_name)
            if real_pkg_name:
                ThreadMethod(self.add_download, (real_pkg_name, ACTION_INSTALL, self.simulate)).start()
            else:
                self.update_signal([("pkg-not-in-cache", pkg_name)])

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="sb", out_signature="")
    def uninstall_pkg(self, pkg_name, purge):
        real_pkg_name = self.get_real_pkg_name(pkg_name)
        if real_pkg_name:
            self.apt_action_pool.add_uninstall_action(real_pkg_name, self.simulate, purge)
        else:
            self.update_signal([("pkg-not-in-cache", pkg_name)])

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="sb", out_signature="")
    def uninstall_pkg_from_desktop(self, desktop_path, purge):
        ThreadMethod(self.uninstall_pkg_from_desktop_thread, (desktop_path, purge)).start()

    def uninstall_pkg_from_desktop_thread(self, path, purge):
        pkg_name = self.get_pkg_name_from_path(path)
        if pkg_name:
            self.uninstall_pkg(pkg_name, purge)
        else:
            global_event.emit("action-failed", (path, ACTION_UNINSTALL, [], "no package found for path: %s" % path))

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="s")
    def get_pkg_name_from_path(self, path):
        pkg_name = utils.file_path_to_package_name(path)
        if pkg_name == "" and path.endswith(".desktop"):
            desktop_name = os.path.split(path)[1]
            path = utils.desktop_name_to_desktop_path(desktop_name)
            pkg_name = utils.file_path_to_package_name(path)
        return pkg_name

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def upgrade_pkg(self, pkg_names):
        for pkg_name in pkg_names:
            real_pkg_name = self.get_real_pkg_name(pkg_name)
            if real_pkg_name:
                self.update_signal([("ready-download-start", (real_pkg_name, ACTION_UPGRADE))])
                ThreadMethod(self.add_download, (real_pkg_name, ACTION_UPGRADE, self.simulate)).start()
            else:
                self.update_signal([("pkg-not-in-cache", pkg_name)])

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")
    def DistUpgrade(self):
        ThreadMethod(self.dist_upgrade).start()

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def stop_download_pkg(self, pkg_names):
        for pkg_name in pkg_names:
            self.download_manager.stop_wait_download(pkg_name)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")
    def cancel_upgrade_download(self):
        if getattr(self, 'upgrade_id'):
            self.download_manager.stop_wait_download(self.upgrade_id)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="")
    def remove_wait_downloads(self, pkg_names):
        for pkg_name in pkg_names:
            self.download_manager.stop_wait_download(pkg_name)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="s")
    def request_pkg_short_desc(self, pkg_name):
        return self.pkg_cache.get_pkg_short_desc(pkg_name)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="as")
    def request_status(self):
        download_status = {
            ACTION_INSTALL : [],
            ACTION_UPGRADE : []}
        for info_dict in self.download_manager.download_task_info.values():
            pkg_name = info_dict["task_name"]
            if info_dict["action_type"] == ACTION_INSTALL:
                download_status[ACTION_INSTALL].append((pkg_name, info_dict["status"]))
            elif info_dict["action_type"] == ACTION_UPGRADE:
                download_status[ACTION_UPGRADE].append((pkg_name, info_dict["status"]))

        action_status = {
            ACTION_INSTALL : [],
            ACTION_UPGRADE : [],
            ACTION_UNINSTALL : []}
        for info_dict in self.apt_action_pool.install_action_dict.values():
            pkg_name = info_dict["task_name"]
            action_status[ACTION_INSTALL].append((pkg_name, info_dict["status"]))

        for info_dict in self.apt_action_pool.upgrade_action_dict.values():
            pkg_name = info_dict["task_name"]
            action_status[ACTION_UPGRADE].append((pkg_name, info_dict["status"]))

        for info_dict in self.apt_action_pool.uninstall_action_dict.values():
            pkg_name = info_dict["task_name"]
            action_status[ACTION_UNINSTALL].append((pkg_name, info_dict["status"]))

        return [str(download_status), str(action_status)]

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="", out_signature="")
    def start_update_list(self):
        self.del_source_list_d()
        self.pkg_cache.open(apb.OpProgress())
        self.apt_action_pool.add_update_list_mission()

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="as", out_signature="ab")
    def request_pkgs_install_status(self, pkg_names):
        _status = []
        for pkg in pkg_names:
            _status.append(self.pkg_cache.is_pkg_installed(pkg))
        return _status

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="(si)", out_signature="")
    def set_pkg_status(self, pkg_status):
        pkg_name, status = pkg_status
        self.pkg_cache.set_pkg_status(pkg_name, pkg_status)

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="s", out_signature="i")
    def get_pkg_installed(self, pkg_name):
        if self.is_pkg_in_cache(pkg_name):
            if self.pkg_cache.is_pkg_installed(pkg_name):
                return 1
            else:
                return 0
        else:
            return -1

    @invoked_log
    @dbus.service.method(DSC_SERVICE_NAME, in_signature="ss", out_signature="s")
    def get_pkg_start_status(self, pkg_name, start_pkg_names):
        is_current_installed = self.get_pkg_installed(pkg_name)
        if is_current_installed == -1:
            return "unknown"
        elif is_current_installed == 0:
            return "uninstalled"
        else:
            desktops = self.get_desktops(pkg_name)
            names = start_pkg_names.split(",")
            for name in names:
                if self.get_pkg_installed(name) == 1:
                    desktops += self.get_desktops(name)
            return json.dumps(desktops)

    @dbus.service.signal(DSC_SERVICE_NAME, signature='a(sv)')
    # Use below command for test:
    # dbus-monitor --system "type='signal', interface='com.linuxdeepin.softwarecenter'"
    def update_signal(self, message):
        # The signal is emitted when this method exits
        # You can have code here if you wish
        info = str(message)
        logger.debug("dbus signal emit: %s" % info)