Exemplo n.º 1
0
    def download_once(self, pkg, output=None):
        """ Download once package """

        try:
            file_path = pkg.data['file_path']
        except:
            self.message('package "' + pkg.data['name'] + '" is local and cannot be downloaded' + ansi.reset, is_error=True, before=ansi.red)
            return False
        if not self.is_quiet():
            pr.p('Downloading ' + pkg.data['name'] + ':' + pkg.data['version'] + ':' + pkg.data['arch'] + '...')

        if output == None:
            output = file_path.split('/')[-1]

        if file_path[:7] == 'http://' or file_path[:8] == 'https://':
            i = 0
            while i < 5:
                res = DownloadProgress.download(file_path, output)
                if res == True:
                    break
                else:
                    pr.e(ansi.red + str(res) + ansi.reset)
                i += 1
            if i == 5:
                return False
        else:
            if not os.path.isfile(file_path):
                return False
            shutil.copy(file_path, output)

        return True
Exemplo n.º 2
0
 def directory_not_empty_event(self, package: BaseArchive, dirpath: str):
     """
     installer directory_not_empty event
     will run when package old directory is not empty
     """
     pr.e(ansi.yellow + 'warning: directory "' + dirpath +
          '" is not empty and will not be deleted' + ansi.reset)
Exemplo n.º 3
0
def handle(argv: list):
    """
    handle cli
    gets argv and runs entered command as subcommand (if not subcommand inserted, runs help command as default)

    Args:
        argv: the program arguments as list
    """
    # parse inserted arguments
    parsed_args = ArgParser.parse(argv)

    # find called subcommand by args
    if len(parsed_args['arguments']) == 0:
        # no subcommand called
        # call help command as default
        parsed_args['arguments'].append('help')

    try:
        command = commands[parsed_args['arguments'][0]]
    except:
        pr.e(sys.argv[0] + ': unknow command "' + parsed_args['arguments'][0] +
             '"')
        pr.exit(1)

    cmdobj = command()
    sys.exit(cmdobj.handle(parsed_args))
Exemplo n.º 4
0
 def arch_error_event(self, pkg: BaseArchive):
     """
     installer arch_error event
     will run when package architecture is not supported on the system
     for example while installing `amd64` package on `i386` system
     """
     pr.e(ansi.red + 'Architecture error while installing "' +
          pkg.data['name'] + '": your system does not support "' +
          pkg.data['arch'] + '" packages.' + ansi.reset)
     return 1
Exemplo n.º 5
0
    def run(self):
        """ Run command """

        if not os.path.exists(self.arguments[0]):
            pr.e('file "' + self.arguments[0] + '" not exists.')
            return 1

        filepath = os.path.abspath(self.arguments[0])

        return os.system(self.cati_exec + ' files --installed | grep ": ' + filepath + '"')
Exemplo n.º 6
0
def cati_installation_is_corrupt(filepath: str, filetype: str):
    """
    Will run when cati installation is corrupt
    shows error to user
    """
    pr.e(
        ansi.red +
        'Cati installation is corrupt. to repair it, just run cati with root access'
        + ansi.reset)
    pr.exit(1)
Exemplo n.º 7
0
def show(repos: list):
    """
    Shows errors in the repositories list

    Args:
        repos: list of loaded repositories (list[repo.Repo.Repo])
    """
    for repo in repos:
        if repo.syntax_errors:
            for error in repo.syntax_errors:
                pr.e('error in ' + repo.loaded_from_file + ':' +
                     str(repo.line_number) + ': ' + error)
Exemplo n.º 8
0
def show(state_list: list):
    """
    Shows and renders list of undoned transactions in state

    Args:
        state_list: loaded state from `transaction.BaseTransaction.state_list()` as (list)
    """
    pr.e(ansi.yellow + 'Error: state is not done')
    pr.p('\tthere is some undoned transactions:')
    for item in state_list:
        pr.p('\t\t' + BaseTransaction.state_item_to_string(item))
    pr.p('to complete them, run `' + sys.argv[0] + ' state --complete`')
    pr.p(ansi.reset, end='')
Exemplo n.º 9
0
    def message(self, msg, is_error=False, before=''):
        """
        Prints a message like this:
        `cati: <command-name>: <the-message>`

        Args:
            is_error: (bool) if this is True, message will print on stderr
            before: (str) before will print in the first of message
                    for example `message("hello world")` will print `cati: cmdname: hello world`
                    but `message("hello world", before="AAA ")` will print `AAA cati: cmdname: hello world`
        """
        msg = before + self.cati_exec + ': ' + self.name + ': ' + msg

        if is_error:
            pr.e(msg)
        else:
            pr.p(msg)
Exemplo n.º 10
0
    def dep_and_conflict_error_event(self, pkg: BaseArchive, ex: Exception):
        """
        installer dep_and_conflict_error event
        will run when package has conflict/dependency error while installing it
        `ex` argument can be DependencyError or ConflictError
        """
        pr.e(
            ansi.red +\
            'Error while installing ' + pkg.data['name'] + ' (' + pkg.data['version'] + '):',
        )
        if isinstance(ex, DependencyError):
            pr.e('\tdependency error:')
        elif isinstance(ex, ConflictError):
            pr.e('\tconflict error:')
        pr.e('\t\t' + str(ex))
        pr.e(ansi.reset)

        return 1
Exemplo n.º 11
0
def require_root_permission(is_cli=True, die_action=None):
    """
    checks root premission.

    Args:
        is_cli (bool): if is True, when user have not root permission,
            error will print in terminal. but if is False,
            the `die_action` will run as a function.
            (will be disable in testing environment)
        die_action (callable): the function will be run when `is_cli` is False
    """

    # if program is in testing mode don't check permission
    if is_testing:
        return

    if os.getuid() == 0:
        return

    # check write and read access for needed files
    files_to_check = [
        Env.packages_lists(),
        Env.installed_lists(),
        Env.state_file(),
        Env.unremoved_conffiles(),
        Env.security_blacklist(),
        Env.any_scripts(),
        Env.repos_config(),
        Env.repos_config_dir(),
        Env.cache_dir(),
        Env.allowed_archs(),
    ]
    for f in files_to_check:
        if not os.access(f, os.W_OK) or not os.access(f, os.R_OK):
            if is_cli:
                pr.e(ansi.red + sys.argv[0] + ': permission is denied' +
                     ansi.reset)
                pr.exit(1)
                return
            else:
                die_action()
                return
Exemplo n.º 12
0
    def run(self):
        """ Run command """

        RootRequired.require_root_permission()

        if not self.is_quiet():
            pr.p('Loading repositories list...')
        repos = Repo.get_list()
        ReposListErrorShower.show(repos)

        if not self.is_quiet():
            pr.p('Prepairing to update repos...')
        orig_repos = []
        for repo in repos:
            if repo.successful_loaded:
                if repo.test():
                    orig_repos.append(repo)
                else:
                    pr.e(ansi.red + 'Cannot make connection to repo "' +
                         repo.full_string + '"' + ansi.reset)

        if not self.is_quiet():
            pr.p('Updating repositories...')
            pr.p('=============================')

        # downloaded repos data files paths
        downloaded_paths = []

        # update repos
        for repo in list(reversed(orig_repos)):
            if not self.is_quiet():
                pr.p('Fetching ' + repo.name + ' (' + repo.url + ') data...')
            data = repo.get_data(download_event=self.download_event)
            if type(data) == int:
                pr.e(ansi.red + 'Cannot update ' + repo.name + ' (' +
                     repo.url + '): error code ' + str(data) + ansi.reset)
            elif isinstance(data, Exception):
                pr.e(ansi.red + 'Cannot update ' + repo.name + ' (' +
                     repo.url + '): ' + str(data) + ansi.reset)
            else:
                # validate data
                try:
                    tmp = json.loads(data)
                    # save data in an file
                    path = Env.cache_dir('/' + repo.name + '-' +
                                         str(time.time()) +
                                         str(random.random())) + '.json'
                    f = open(path, 'w')
                    f.write(data)
                    f.close()
                    downloaded_paths.append(path)
                except:
                    pr.e(ansi.red + 'Cannot update ' + repo.name + ' (' +
                         repo.url + '): invalid json data recived' +
                         ansi.reset)

        if not self.is_quiet():
            pr.p('Updating packages list...')

        # load downloaded data
        packages = []
        for path in downloaded_paths:
            f = open(path, 'r')
            data = f.read().strip()
            f.close()
            items = json.loads(data)
            for item in items:
                if PackageJsonValidator.validate(item):
                    packages.append(item)
                else:
                    pass

        for pkg in packages:
            if PackageJsonValidator.validate(pkg):
                if self.is_verbose():
                    pr.p('adding ' + pkg['name'] + ':' + pkg['version'] + ':' +
                         pkg['arch'] + '...')
                # write package on list
                if not os.path.isdir(Env.packages_lists('/' + pkg['name'])):
                    os.mkdir(Env.packages_lists('/' + pkg['name']))
                try:
                    f = open(
                        Env.packages_lists('/' + pkg['name'] + '/' +
                                           pkg['version'] + '-' + pkg['arch']),
                        'w')
                    f.write(json.dumps(pkg))
                    f.close()
                except:
                    pr.e(ansi.red + 'error while adding ' + pkg['name'] + ':' +
                         pkg['version'] + ':' + pkg['arch'] + ansi.reset)
            else:
                if self.is_verbose():
                    pr.p(ansi.yellow +
                         'invalid json data in an item. ignored...' +
                         ansi.reset)

        if self.is_quiet():
            pr.p('Finishing update...')
        ListUpdater.update_indexes({
            'cannot_read_file': self.empty_method,
            'invalid_json_data': self.empty_method,
        })

        pr.p(ansi.green + 'Done.' + ansi.reset)
Exemplo n.º 13
0
    def run(self):
        """ Run command """

        RootRequired.require_root_permission()

        pr.p('Loading packages list...')
        pr.p('========================')

        loaded_packages = []

        for argument in self.arguments:
            arg_parts = argument.split('=')
            if len(arg_parts) == 1:
                # load last version as default
                pkg = Pkg.load_last(argument)
            else:
                # load specify version
                pkg = Pkg.load_version(arg_parts[0], arg_parts[1])
                if pkg == 1:
                    pkg = False
                elif pkg == 2:
                    self.message('package "' + arg_parts[0] +
                                 '" has not version "' + arg_parts[1] + '"' +
                                 ansi.reset,
                                 before=ansi.red)
                    continue
            if pkg:
                loaded_packages.append(pkg)
            else:
                self.message('unknow package "' + argument + '"' + ansi.reset,
                             before=ansi.red)

        # remove local packages from list
        new_loaded_packages = []
        for pkg in loaded_packages:
            try:
                file_path = pkg.data['file_path']
                new_loaded_packages.append(pkg)
            except:
                self.message('package "' + pkg.data['name'] +
                             '" is a local package',
                             is_error=True)
        loaded_packages = new_loaded_packages

        if not loaded_packages:
            return 1

        # calculate transactions
        pr.p('Calculating transactions...')
        calc = Calculator(with_recommends=self.has_option('--with-recommends'))
        i = 0
        while i < len(loaded_packages):
            loaded_packages[i].is_manual = True
            i += 1
        try:
            calc.install(list(reversed(loaded_packages)))
        except:
            pr.e(ansi.red + 'ERROR: There is some dependnecy problems.' +
                 ansi.reset)
            return 1

        # handle reinstallable packages
        i = 0
        while i < len(calc.to_install):
            if calc.to_install[i].installed():
                if calc.to_install[i].installed(
                ) == calc.to_install[i].wanted_version:
                    if not self.has_option('--reinstall'):
                        pr.p(
                            'Package ' + calc.to_install[i].data['name'] +
                            '=' + calc.to_install[i].wanted_version +
                            ' is currently installed. use --reinstall option to re-install it.'
                        )
                        if calc.to_install[i].is_manual:
                            try:
                                pr.p(
                                    'Setting it as manual installed package...'
                                )
                                manual_f = open(
                                    Env.installed_lists('/' +
                                                        pkg.data['name'] +
                                                        '/manual'), 'w')
                                manual_f.write('')
                                manual_f.close()
                            except:
                                pass
                        calc.to_install.pop(i)
            i += 1

        # check transactions exists
        if not calc.has_any_thing():
            pr.p('Nothing to do.')
            return 0

        # show transaction
        TransactionShower.show(calc)

        if not self.has_option('-y') or self.has_option('--yes'):
            pr.p('Do you want to continue? [Y/n] ', end='')
            answer = input()
            if answer == 'y' or answer == 'Y' or answer == '':
                pass
            else:
                pr.p('Abort.')
                return 1

        # start download packages
        pr.p('Downloading packages...')
        downloaed_paths = []
        for pkg in calc.to_install:
            download_path = Env.cache_dir('/archives/' + pkg.data['name'] +
                                          '-' + pkg.wanted_version + '-' +
                                          pkg.data['arch'])
            if os.path.isfile(download_path):
                file_sha256 = calc_file_sha256(download_path)
                file_md5 = calc_file_md5(download_path)
                valid_sha256 = None
                valid_md5 = None
                try:
                    valid_sha256 = pkg.data['file_sha256']
                except:
                    valid_sha256 = file_sha256
                try:
                    valid_md5 = pkg.data['file_md5']
                except:
                    valid_md5 = file_md5
                if file_md5 != valid_md5 or file_sha256 != valid_sha256:
                    # file is corrupt and should be download again
                    os.remove(download_path)
                else:
                    pr.p('Using Cache for ' + pkg.data['name'] + ':' +
                         pkg.data['version'] + ':' + pkg.data['arch'] + '...')
                    downloaed_paths.append(download_path)
                    continue
            download_cmd = DownloadCommand()
            i = 0
            res = 1
            tmp = True
            while tmp:
                if i > 5:
                    pr.e(ansi.red + 'Failed to download packages' + ansi.reset)
                    return res
                pr.p('Downloading ' + pkg.data['name'] + ':' +
                     pkg.data['version'] + ':' + pkg.data['arch'] + '...')
                res = download_cmd.handle(
                    ArgParser.parse([
                        'cati', 'download', '-q',
                        pkg.data['name'] + '=' + pkg.wanted_version,
                        '--output=' + download_path
                    ]))
                if res == 1 or res == None:
                    tmp = False
                i += 1
            downloaed_paths.append(download_path)
        pr.p('Download completed.')

        # check --download-only option
        if self.has_option('--download-only'):
            return 0

        cati_pkg_cmd_options = []
        remove_cmd_options = []
        if self.has_option('--keep-conffiles'):
            cati_pkg_cmd_options.append('--keep-conffiles')
        if self.has_option('--target'):
            cati_pkg_cmd_options.append('--target')
        if self.has_option('--without-scripts'):
            cati_pkg_cmd_options.append('--without-scripts')
            remove_cmd_options.append('--without-scripts')

        # remove packages
        if calc.to_remove:
            pr.p('Removing packages...')
            package_names = [pkg.data['name'] for pkg in calc.to_remove]
            remove_cmd = RemoveCommand()
            res = remove_cmd.handle(
                ArgParser.parse([
                    'cati', 'remove', *package_names, '-y', *remove_cmd_options
                ]))
            if res != 0 and res != None:
                pr.e(ansi.red + 'Failed to remove packages' + ansi.reset)
                return res

        # install packages
        pr.p('Installing packages...')
        pkg_cmd = PkgCommand()
        res = pkg_cmd.handle(
            ArgParser.parse([
                'cati', 'pkg', 'install', *downloaed_paths,
                *cati_pkg_cmd_options
            ]))
        if res != 0 and res != None:
            self.set_manual_installs(calc.to_install)
            pr.e(ansi.red + 'Failed to install packages' + ansi.reset)
            return res

        self.set_manual_installs(calc.to_install)

        pr.p(ansi.green + 'Done.' + ansi.reset)
Exemplo n.º 14
0
    def install_once(self, pkg: BaseArchive):
        """
        installs once package
        is called from install sub command
        """
        target_path = self.option_value('--target')
        if target_path == None:
            target_path = ''
        installer = Installer()

        try:
            out = installer.install(
                pkg, {
                    'cannot_read_file': self.cannot_read_file_event,
                    'invalid_json_data': self.invalid_json_data_event,
                }, {
                    'package_currently_installed':
                    self.package_currently_installed_event,
                    'package_new_installs': self.package_new_installs_event,
                    'package_installed': self.package_installed_event,
                    'directory_not_empty': self.directory_not_empty_event,
                    'dep_and_conflict_error':
                    self.dep_and_conflict_error_event,
                    'arch_error': self.arch_error_event,
                }, (not self.has_option('--auto')),
                run_scripts=(not self.has_option('--without-scripts')),
                target_path=str(target_path),
                keep_conffiles=self.has_option('--keep-conffiles'),
                check_security_blacklist=(not self.has_option('--force')
                                          and not self.has_option('-f')))

            if type(out) == int:
                return out
        except PackageScriptError as ex:
            pr.e(ansi.red + 'cannot install "' + pkg.data['name'] + ':' +
                 pkg.data['version'] + '": ' + str(ex) + ansi.reset)
            return 1
        except PackageIsInSecurityBlacklist as ex:
            pr.e(ansi.red + 'cannot install ' + pkg.data['name'] + ':' +
                 pkg.data['version'] +
                 ' because this is in security blacklist:')
            pr.e('  ' + ex.blacklist_item['title'] + ':')
            for l in ex.blacklist_item['description'].split('\n'):
                pr.e('\t' + l)
            pr.p(ansi.reset, end='')
            return 1
        except CannotReadFileException as ex:
            self.message(ansi.red + str(ex), True, before=ansi.reset)
            return 1
        except FileConflictError as ex:
            pr.e(ansi.red + '\nCannot install ' + pkg.data['name'] + ':' +
                 pkg.data['version'] + ': File conflict error:')
            pr.e('    ' + str(ex))
            pr.p(ansi.reset, end='')
            return 1