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
def run_command(self, command_name: str, arguments=[]): """ Runs cmdline command """ arguments.insert(0, 'cati') arguments.insert(1, command_name) cmd = commands[command_name]() out = cmd.handle(ArgParser.parse(arguments)) if out == None: out = 0 return int(out)
def run(self): """ Run command """ options = [] if self.has_option('-y') or self.has_option('--yes'): options = ['-y'] update_cmd = UpdateCommand() res = update_cmd.handle(ArgParser.parse(['cati', 'update'])) if res != 0 and res != None: return res upgrade_cmd = UpgradeCommand() res = upgrade_cmd.handle(ArgParser.parse(['cati', 'upgrade', *options])) if res != 0 and res != None: return res autoremove_cmd = AutoremoveCommand() res = autoremove_cmd.handle(ArgParser.parse(['cati', 'autoremove', *options])) if res != 0 and res != None: return res
def run(self): """ Run command """ # join all of arguments as one argument full_query_string = '' if len(self.arguments) > 1: for arg in self.arguments: full_query_string += arg + ' ' full_query_string = full_query_string[:len(full_query_string) - 1] else: full_query_string = self.arguments[0] # search arguments with `list --search` command arguments = ['--search=' + full_query_string] arguments.insert(0, 'cati') arguments.insert(1, 'list') list_command = ListCommand() return list_command.handle(ArgParser.parse(arguments))
def run(self): """ Run command """ if not self.is_quiet(): pr.p('Checking unused packages...') self.unused_packages = [] self.find_unused_packages() unused_packages = self.unused_packages package_names = [pkg.data['name'] for pkg in unused_packages] options = [op for op in self.args['options']] if not package_names: pr.p('There is not any unused package') return 0 remove_cmd = RemoveCommand() return remove_cmd.handle( ArgParser.parse(['cati', 'remove', *package_names, *options]))
def run(self): """ Run command """ pr.p('Checking upgradable packages...') installed_packages = Pkg.installed_list()['list'] upgradable_packages = [] for pkg in installed_packages: installed_version = pkg.installed() latest_version = pkg.data['version'] if Pkg.compare_version(latest_version, installed_version) == 1: upgradable_packages.append(pkg) if not upgradable_packages: pr.p(ansi.green + 'all of packages are up to date' + ansi.reset) return 0 packages_names = [pkg.data['name'] for pkg in upgradable_packages] install_cmd = InstallCommand() return install_cmd.handle(ArgParser.parse(['cati', 'install', *self.args['options'], *packages_names]))
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
def deb2cati(file_path: str) -> str: """ Converts deb package to cati package and returns generated cati package file path Args: file_path: deb package filepath Returns: returns generated cati package filepath """ file_path = os.path.abspath(file_path) tmp_dir = Temp.make_dir() cwd = os.getcwd() os.chdir(tmp_dir) try: shutil.copy(file_path, './package.deb') script = ''' ar -x package.deb mkdir cati mkdir cati/control cati/scripts mv control.tar.* cati/control mkdir cati/files mv data.tar.* cati/files rm debian-binary package.deb touch cati/data.json '''.strip().split('\n') script = [l.strip() for l in script] for line in script: result = os.system(line) if result != 0: # script has error, return current filepath os.chdir(cwd) return file_path os.chdir('cati/control') os.system('tar -xf control.tar.*') os.system('rm control.tar.*') os.chdir('..') os.chdir('files') os.system('tar -xf data.tar.*') os.system('rm data.tar.*') os.chdir('..') # convert content data to cati json control_f = open('control/control', 'r').read() control_f_lines = control_f.strip().split('\n') control_fields = {} tmp_last_key = None for line in control_f_lines: if line != '': if line[0] == ' ': if tmp_last_key != None: control_fields[tmp_last_key] += '\n' + line else: key = line.split(':', 1)[0] value = line.split(':', 1)[1].strip() tmp_last_key = key control_fields[key] = value # convert scripts if os.path.isfile('control/preinst'): shutil.copy('control/preinst', 'scripts/ins-before') if os.path.isfile('control/postinst'): shutil.copy('control/postinst', 'scripts/ins-after') if os.path.isfile('control/prerm'): shutil.copy('control/prerm', 'scripts/rm-before') if os.path.isfile('control/postrm'): shutil.copy('control/postrm', 'scripts/rm-after') # convert control fields to cati data.json cati_data = {} for k in control_fields: if k == 'Package': cati_data['name'] = control_fields[k].strip() elif k == 'Version': cati_data['version'] = control_fields[k].strip() elif k == 'Architecture': cati_data['arch'] = control_fields[k].strip() elif k == 'Maintainer': cati_data['maintainer'] = control_fields[k].strip() elif k == 'Original-Maintainer': cati_data['X-Original-Maintainer'] = control_fields[k].strip() elif k == 'Uploaders': cati_data['uploaders'] = control_fields[k].strip().split(',') cati_data['uploaders'] = [ a.strip() for a in cati_data['uploaders'] ] elif k == 'Description': cati_data['description'] = control_fields[k] elif k == 'Changed-By': cati_data['changed-by'] = control_fields[k] elif k == 'Changes': cati_data['changes'] = control_fields[k] elif k == 'Date': cati_data['date'] = control_fields[k] elif k == 'Urgency': cati_data['urgency'] = control_fields[k] elif k == 'Essential': cati_data['essential'] = control_fields[k] if cati_data['essential'] == 'yes' or cati_data[ 'essential'] == 'Yes': cati_data['essential'] = True else: cati_data['essential'] = False elif k == 'Homepage': cati_data['homepage'] = control_fields[k].strip() elif k == 'Section': cati_data['category'] = [control_fields[k].strip()] elif k == 'Depends' or k == 'Pre-Depends': try: cati_data['depends'] except: cati_data['depends'] = [] cati_data['depends'] = [ *cati_data['depends'], *convert_depends_list(control_fields[k].strip()) ] elif k == 'Conflicts' or k == 'Breaks': try: cati_data['conflicts'] except: cati_data['conflicts'] = [] cati_data['conflicts'] = [ *cati_data['conflicts'], *convert_depends_list(control_fields[k].strip()) ] elif k == 'Recommends': cati_data['recommends'] = convert_depends_list( control_fields[k].strip()) elif k == 'Replaces': cati_data['replaces'] = convert_depends_list( control_fields[k].strip()) elif k == 'Suggests': cati_data['suggests'] = convert_depends_list( control_fields[k].strip()) cati_data['suggests'] = [ item_tmp.split(' ')[0] for item_tmp in cati_data['suggests'] ] elif k == 'Enhances': cati_data['enhances'] = convert_depends_list( control_fields[k].strip()) cati_data['enhances'] = [ item_tmp.split(' ')[0] for item_tmp in cati_data['enhances'] ] elif k == 'Provides': cati_data['provides'] = convert_depends_list( control_fields[k].strip()) cati_data['provides'] = [ item_tmp.split(' ')[0] for item_tmp in cati_data['provides'] ] elif k[0] == 'X' or k[0] == 'x': cati_data[k] = control_fields[k].strip() os.system('rm control -rf') cati_data_f = open('data.json', 'w') cati_data_f.write(json.dumps(cati_data)) cati_data_f.close() os.chdir('..') # build pkg pkg_command = PkgCommand.PkgCommand() pkg_command.handle( ArgParser.parse(['cati', 'pkg', 'build', 'cati', '-q'])) if os.path.isfile('cati.cati'): try: shutil.copy('cati.cati', file_path + '.cati') os.chdir(cwd) return file_path + '.cati' except: tmp_file_path = Temp.make_file() shutil.copy('cati.cati', tmp_file_path) return tmp_file_path except Exception as ex: print('error: ' + str(ex)) os.chdir(cwd) return file_path os.chdir(cwd) return file_path
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)