Example #1
0
def update_indexes(events: dict):
    """
    This function loads available versions of a package and index them in index file
    and do this action for all of packages in lists.

    Args:
        events: (dict) the `events` argument should be a dictonary from functions. this will use to handle errors
                for example if some thing went wrong, the spesific function in events
                will run.
                events:
                - cannot_read_file: if in this process, an error happened while reading a file, this will run with file path arg
                - invalid_json_data: if json content of a file is curropt, this will run with file path and content args
    """

    require_root_permission()

    for pkg in os.listdir(Env.packages_lists()):
        pkg_index = {}
        if os.path.isdir(Env.packages_lists('/' + pkg)):
            for version in os.listdir(Env.packages_lists('/' + pkg)):
                if version != 'index':
                    if os.path.isfile(
                            Env.packages_lists('/' + pkg + '/' + version)):
                        content = None
                        try:
                            f = open(
                                Env.packages_lists('/' + pkg + '/' + version),
                                'r')
                            content = f.read()
                        except:
                            events['cannot_read_file'](
                                Env.packages_lists('/' + pkg + '/' + version))

                        if content != None:
                            try:
                                content_json = json.loads(content)
                                try:
                                    tmp = pkg_index[content_json['arch']]
                                    del tmp
                                except:
                                    pkg_index[content_json['arch']] = []
                                pkg_index[content_json['arch']].append(
                                    content_json['version'])
                            except:
                                events['invalid_json_data'](
                                    Env.packages_lists('/' + pkg + '/' +
                                                       version), content)
        # write generated index to index file
        f_index = open(Env.packages_lists('/' + pkg + '/index'), 'w')
        f_index.write(json.dumps(pkg_index))
        f_index.close()
Example #2
0
    def run(self):
        """ Run command """

        # require root permission
        require_root_permission()

        result_code = 0

        packages_to_reinstall = []

        if not self.is_quiet():
            pr.p('Starting checking system health and security...')
            pr.p('===============================================')

        # check state
        state_cmd = StateCommand()
        out = state_cmd.handle(ArgParser.parse(['cati', 'state']))
        if out > 0:
            return out

        # search for conflict and dependency corruptions
        if not self.is_quiet():
            pr.p('Checking dependency and conflict corruptions...')
        dependency_problems = []
        conflict_problems = []
        installed_packages = Pkg.installed_list()['list']
        for pkg in installed_packages:
            if self.is_verbose():
                pr.p('[info] checking dependencies and conflicts for ' +
                     pkg.data['name'] + '...')
            for dp in pkg.get_depends():
                if not Pkg.check_state(dp):
                    dependency_problems.append([pkg, dp])
            for conflict in pkg.get_conflicts():
                if Pkg.check_state(conflict):
                    conflict_problems.append([pkg, conflict])

        if dependency_problems or conflict_problems:
            for depend in dependency_problems:
                pr.p(ansi.red + 'dependency problem for ' +
                     depend[0].data['name'] + ': ' + depend[1] + ansi.reset)
                packages_to_reinstall.append(depend[0])
            for conflict in conflict_problems:
                pr.p(ansi.red + 'conflict problem for ' +
                     conflict[0].data['name'] + ': ' + conflict[1] +
                     ansi.reset)
                packages_to_reinstall.append(conflict[0])
            result_code = 1
        else:
            pr.p(
                ansi.green +
                'There is not any conflict or dependnecy problem and everything is ok'
                + ansi.reset)

        # check static files
        if not self.is_quiet():
            pr.p('Checking packages static files...')
        staticfile_problems = []
        for pkg in installed_packages:
            if self.is_verbose():
                pr.p('[info] checking static files for ' + pkg.data['name'] +
                     '...')
            files = pkg.installed_static_files()
            for f in files:
                f[1] = Env.base_path(f[1])
                if os.path.isfile(f[1]):
                    wanted_hash = f[0]
                    current_hash = calc_file_sha256(f[1])
                    if wanted_hash != current_hash:
                        staticfile_problems.append([pkg, f, 'file is changed'])
                else:
                    staticfile_problems.append([pkg, f, 'file is deleted'])
        if staticfile_problems:
            for problem in staticfile_problems:
                pr.p(ansi.red + 'staticfile problem in package ' +
                     problem[0].data['name'] + ': ' + problem[1][1] + ': ' +
                     problem[2] + ansi.reset)
                packages_to_reinstall.append(problem[0])
            result_code = 1
        else:
            pr.p(ansi.green + 'all of static files are ok' + ansi.reset)

        # check repos config files health
        if not self.is_quiet():
            pr.p('Checking cati configuration files...')
        if self.is_verbose():
            pr.p('[info] checking repositories config...')
        repos = Repo.get_list()
        pr.p(ansi.red, end='')
        ReposListErrorShower.show(repos)
        pr.p(ansi.reset, end='')
        is_any_repo_error = False
        for repo in repos:
            if repo.syntax_errors:
                is_any_repo_error = True
                result_code = 1
        if not is_any_repo_error:
            pr.p(ansi.green + 'all of cati configuration files are ok' +
                 ansi.reset)

        # check database files
        if not self.is_quiet():
            pr.p('Checking cati database...')
        database_problems = []
        for f in os.listdir(Env.installed_lists()):
            if self.is_verbose():
                pr.p('[info] checking database install dir for ' + f + '...')
            if not os.path.isfile(Env.installed_lists(
                    '/' + f + '/files')) or not os.path.isfile(
                        Env.installed_lists('/' + f + '/ver')):
                database_problems.append(
                    'installed packages database: directory ' +
                    Env.installed_lists('/' + f) + ' is corrupt')
        for f in os.listdir(Env.security_blacklist()):
            if self.is_verbose():
                pr.p('[info] checking security blacklist part ' + f + '...')
            if not os.path.isfile(Env.security_blacklist('/' + f)):
                database_problems.append(
                    'security blacklist: an directory detected: ' +
                    Env.security_blacklist('/' + f))
            else:
                tmp = open(Env.security_blacklist('/' + f), 'r')
                try:
                    json.loads(tmp.read())
                except:
                    database_problems.append(
                        'security blacklist: invalid json data in ' +
                        Env.security_blacklist('/' + f))
        if database_problems:
            for problem in database_problems:
                pr.p(ansi.red + 'database: ' + problem + ansi.reset)
            result_code = 1
        else:
            pr.p(ansi.green + 'all of cati database is ok' + ansi.reset)

        if not self.is_quiet():
            if packages_to_reinstall:
                pr.p(ansi.blue + 'We suggest re-install this packages:')
                for pkg in packages_to_reinstall:
                    pr.p('- ' + pkg.data['name'])
                if not self.has_option('--autofix'):
                    pr.p(
                        'use --autofix option to re-install them or do this manually'
                    )
                    pr.p(ansi.reset, end='')
                else:
                    pr.p(ansi.reset, end='')
                    packages_names = [
                        pkg.data['name'] for pkg in packages_to_reinstall
                    ]
                    install_cmd = InstallCommand()
                    args = ['cati', 'install', '--reinstall', *packages_names]
                    cmd_str = ''
                    for arg in args:
                        cmd_str += arg + ' '
                    cmd_str = cmd_str.strip()
                    pr.p(cmd_str)
                    return install_cmd.handle(ArgParser.parse(args))

        return result_code
Example #3
0
    def run(self):
        """ Run command """

        if self.has_option('--abort'):
            require_root_permission()
            state_list = BaseTransaction.state_list()
            if not state_list:
                pr.p(
                    ansi.green +
                    'There is not any undoned transaction and everything is ok'
                    + ansi.reset)
                return 0
            user_answer = 'y'
            if not self.has_option('-y') and not self.has_option('--yes'):
                pr.p(ansi.yellow +
                     'WARNING: this process maybe dangerous and ' +
                     str(len(state_list)) +
                     ' transactions will be igonred. are you sure? [y/N] ' +
                     ansi.reset,
                     end='')
                user_answer = input()
            if user_answer in ['Y', 'y']:
                BaseTransaction.finish_all_state()
                pr.p(ansi.green + 'state was empty successfully' + ansi.reset)
            else:
                return
        elif self.has_option('--complete'):
            require_root_permission()
            state_list = BaseTransaction.state_list()
            if not state_list:
                pr.p(
                    ansi.green +
                    'There is not any undoned transaction and everything is ok'
                    + ansi.reset)
                return 0
            BaseTransaction.finish_all_state()
            # complete transactions
            for item in state_list:
                if item['action'] == 'remove':
                    tmp_arguments = [item['pkg'], '-y']
                    tmp_arguments.insert(0, 'cati')
                    tmp_arguments.insert(1, 'remove')
                    cmd = RemoveCommand()
                    cmd.handle(ArgParser.parse(tmp_arguments))
                elif item['action'] == 'install':
                    tmp_arguments = ['install', item['file']]
                    tmp_arguments.insert(0, 'cati')
                    tmp_arguments.insert(1, 'pkg')
                    cmd = PkgCommand()
                    cmd.handle(ArgParser.parse(tmp_arguments))
            return
        else:
            # show list of undoned transactions
            state_list = BaseTransaction.state_list()
            if state_list:
                StateContentShower.show(state_list)
                return 1
            else:
                pr.p(
                    ansi.green +
                    'There is not any undoned transaction and everything is ok'
                    + ansi.reset)
                return 0
Example #4
0
    def run(self):
        """ Run command """

        require_root_permission()

        # check transactions state before run new transactions
        pr.p('Checking transactions state...')
        state_list = BaseTransaction.state_list(
        )  # get list of undoned transactions
        if state_list:
            # the list is not empty
            StateContentShower.show(state_list)
            return 1

        pr.p('Loading packages list...')
        pr.p('==============================')
        # load list of packages
        packages = []
        for arg in self.arguments:
            pkg = Pkg.load_last(arg)
            if pkg == False:
                self.message('unknow package "' + arg + '"' + ansi.reset,
                             before=ansi.red)
            else:
                if pkg.installed():
                    packages.append(pkg)
                else:
                    self.message('package "' + pkg.data['name'] +
                                 '" is not installed' + ansi.reset,
                                 before=ansi.red)

        # start removing loaded packages
        calc = Calculator()
        calc.remove(packages)

        # show transactions
        TransactionShower.show(calc)

        essential_packages = []
        for pkg in calc.to_remove:
            try:
                if pkg.data['essential']:
                    essential_packages.append(pkg)
            except:
                pass

        if not self.has_option('--force') and not self.has_option('-f'):
            for pkg in essential_packages:
                pr.p(
                    ansi.red + 'Package "' + pkg.data['name'] +
                    '" is a essential package and cannot be remove. use --force|-f option to force remove them'
                    + ansi.reset)
            if essential_packages:
                return 1

        if not calc.has_any_thing():
            return

        # check user confirmation
        if not self.has_option('-y') and not self.has_option('--yes'):
            pr.p('Do you want to continue? [Y/n] ', end='')
            answer = input()
            if not (answer == 'y' or answer == 'Y' or answer == ''):
                pr.p(ansi.yellow + 'Abort.' + ansi.reset)
                pr.exit(1)

        # add packages to state
        BaseTransaction.add_to_state(calc)

        packages_to_remove_names_and_versions = [
            pkg.data['name'] + '@' + pkg.data['version']
            for pkg in calc.to_remove
        ]

        # run transactions
        for pkg in calc.to_remove:
            Remove.run(pkg, {
                'removing_package': self.removing_package_event,
                'package_remove_finished': self.package_remove_finished_event,
                'dir_is_not_empty': self.dir_is_not_empty_event,
            },
                       self.has_option('--conffiles'),
                       run_scripts=(not self.has_option('--without-scripts')))
            BaseTransaction.pop_state()

        BaseTransaction.run_any_scripts(
            ['remove', packages_to_remove_names_and_versions],
            events={
                'start_run_script': self.start_run_any_script_event,
            })

        BaseTransaction.finish_all_state()
Example #5
0
    def sub_install(self):
        """ install sub command (cati pkg install) """
        if len(self.arguments) <= 1:
            self.message('argument package file(s) required')
            return 1

        require_root_permission()

        # check transactions state before run new transactions
        pr.p('Checking transactions state...')
        state_list = BaseTransaction.state_list(
        )  # get list of undoned transactions
        if state_list:
            # the list is not empty
            StateContentShower.show(state_list)
            return 1

        packages_to_install = []
        i = 1
        while i < len(self.arguments):
            try:
                pkg = archive_factory(self.arguments[i], 'r')
                pkg.read()
                pkg.package_file_path = os.path.abspath(self.arguments[i])
                packages_to_install.append(pkg)
            except FileNotFoundError as ex:
                self.message('file "' + self.arguments[i] + '" not found' +
                             ansi.reset,
                             before=ansi.red)
                return 1
            except:
                self.message('cannot open "' + self.arguments[i] +
                             '": file is corrupt' + ansi.reset,
                             before=ansi.red)
                return 1

            i += 1

        # add packages to state
        state_f = open(Env.state_file(), 'w')
        tmp = ''
        for pkg in packages_to_install:
            tmp += ('install%' + pkg.data['name'] + '%' + pkg.data['version'] +
                    '%' + pkg.data['arch'] + '%' + pkg.package_file_path +
                    '\n')
        state_f.write(tmp)
        state_f.close()

        packages_to_install_names_and_versions = [
            pkg.data['name'] + '@' + pkg.data['version']
            for pkg in packages_to_install
        ]
        i = 0
        while i < len(packages_to_install):
            try:
                pkg = packages_to_install[i]
                tmp = self.install_once(pkg)
                if type(tmp) == int and tmp != 0:
                    if not self.has_option('--dont-ignore-state'):
                        BaseTransaction.finish_all_state()
                    return tmp
                pkg.close()
            except:
                if not self.has_option('--dont-ignore-state'):
                    BaseTransaction.finish_all_state()
                self.message('cannot install "' +
                             packages_to_install[i].data['name'] + '"' +
                             ansi.reset,
                             before=ansi.red)
                return 1
            i += 1
        BaseTransaction.run_any_scripts(
            ['install', packages_to_install_names_and_versions],
            events={
                'start_run_script': self.start_run_any_script_event,
            })
        BaseTransaction.finish_all_state()