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))
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)
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
def validate(self, args: dict): """ Validate inserted arguments in command config frame loads command config from `config` function output next checks arguments and compares them with command config then, if an unknow option is inserted or more/less argument inserted, shows error to user. Args: args: command arguments as doctonary example: {'arguments': list, 'options': dict{ '--foo': 'value', '-x': None } } """ # load command config command_config = self.config() # add --help option as default command_config['options']['--help'] = [False, False] self.name = command_config['name'] self.cati_exec = sys.argv[0] # pop first argument (command self name) args['arguments'].pop(0) # check knowed options and value of them for k in args['options']: try: option_config = command_config['options'][k] except: self.message('unknow option "' + k + '"') return pr.exit(1) if option_config[1] == True: if args['options'][k] == None: self.message('option ' + k + ' requires value') return pr.exit(1) # check required options for option in command_config['options']: if command_config['options'][option][0] == True: try: args['options'][option] except: self.message('option ' + option + ' is required') return pr.exit(1) self.args = args self.arguments = self.args['arguments'] # check arguments count if not self.has_option('--help'): if command_config['max_args_count'] != None: if len(args['arguments']) > command_config['max_args_count']: self.message('this command requires less than ' + str(command_config['max_args_count'] + 1) + ' arguments') return pr.exit(1) if command_config['min_args_count'] != None: if len(args['arguments']) < command_config['min_args_count']: self.message('this command requires more than ' + str(command_config['min_args_count'] - 1) + ' arguments') return pr.exit(1)
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()