#!/usr/bin/python3 # -*- coding: utf-8 -*- import os import sys import logging from pathlib import Path from slpkg.checks import Check from slpkg.upgrade import Upgrade from slpkg.configs import Configs from slpkg.tracking import Tracking from slpkg.repo_info import RepoInfo from slpkg.dependees import Dependees from slpkg.utilities import Utilities from slpkg.cleanings import Cleanings from slpkg.search import SearchPackage from slpkg.views.cli_menu import Usage from slpkg.dialog_box import DialogBox from slpkg.views.version import Version from slpkg.download_only import Download from slpkg.sbos.queries import SBoQueries from slpkg.views.help_commands import Help from slpkg.repositories import Repositories from slpkg.binaries.install import Packages from slpkg.dialog_configs import FormConfigs from slpkg.check_updates import CheckUpdates from slpkg.sbos.slackbuild import Slackbuilds from slpkg.binaries.queries import BinQueries from slpkg.logging_config import LoggingConfig from slpkg.find_installed import FindInstalled from slpkg.views.view_package import ViewPackage from slpkg.remove_packages import RemovePackages from slpkg.update_repository import UpdateRepository class Argparse(Configs): def __init__(self, args: list): super(Configs).__init__() self.args: list = args self.flags: list = [] self.directory: Path = self.tmp_slpkg self.dialogbox = DialogBox() self.utils = Utilities() self.usage = Usage() self.form_configs = FormConfigs() self.repos = Repositories() self.repository: str = self.repos.default_repository if len(args) == 0 or '' in args: self.usage.help_short(1) self.data: dict = {} self.flag_yes: str = '--yes' self.flag_short_yes: str = '-y' self.flag_jobs: str = '--jobs' self.flag_short_jobs: str = '-j' self.flag_resolve_off: str = '--resolve-off' self.flag_short_resolve_off: str = '-O' self.flag_reinstall: str = '--reinstall' self.flag_short_reinstall: str = '-r' self.flag_skip_installed: str = '--skip-installed' self.flag_short_skip_installed: str = '-k' self.flag_install_data: str = '--install-data' self.flag_short_install_data: str = '-a' self.flag_full_reverse: str = '--full-reverse' self.flag_short_full_reverse: str = '-E' self.flag_search: str = '--search' self.flag_short_search: str = '-S' self.flag_no_silent: str = '--no-silent' self.flag_short_no_silent: str = '-n' self.flag_pkg_version: str = '--pkg-version' self.flag_short_pkg_version: str = '-p' self.flag_parallel: str = '--parallel' self.flag_short_parallel: str = '-P' self.flag_repository: str = '--repository=' self.flag_short_repository: str = '-o' self.flag_directory: str = '--directory=' self.flag_short_directory: str = '-z' self.flag_searches: list = [ self.flag_short_search, self.flag_search ] self.options: list = [ self.flag_yes, self.flag_short_yes, self.flag_jobs, self.flag_short_jobs, self.flag_resolve_off, self.flag_short_resolve_off, self.flag_reinstall, self.flag_short_reinstall, self.flag_skip_installed, self.flag_short_skip_installed, self.flag_install_data, self.flag_short_install_data, self.flag_full_reverse, self.flag_short_full_reverse, self.flag_search, self.flag_short_search, self.flag_no_silent, self.flag_short_no_silent, self.flag_pkg_version, self.flag_short_pkg_version, self.flag_parallel, self.flag_short_parallel, self.flag_repository, self.flag_short_repository, self.flag_directory, self.flag_short_directory, ] self.commands: dict = { '--help': [], '--version': [], 'help': [], 'update': [ self.flag_yes, self.flag_short_yes, self.flag_install_data, self.flag_short_install_data, self.flag_repository, self.flag_short_repository, self.flag_parallel, self.flag_short_parallel ], 'upgrade': [ self.flag_yes, self.flag_short_yes, self.flag_jobs, self.flag_short_jobs, self.flag_resolve_off, self.flag_short_resolve_off, self.flag_reinstall, self.flag_short_reinstall, self.flag_no_silent, self.flag_short_no_silent, self.flag_repository, self.flag_short_repository, self.flag_parallel, self.flag_short_parallel ], 'check-updates': [ self.flag_repository, self.flag_short_repository ], 'repo-info': [], 'configs': [], 'clean-logs': [ self.flag_yes, self.flag_short_yes ], 'clean-data': [ self.flag_yes, self.flag_short_yes ], 'clean-tmp': [], 'build': [ self.flag_yes, self.flag_short_yes, self.flag_jobs, self.flag_short_jobs, self.flag_resolve_off, self.flag_short_resolve_off, self.flag_search, self.flag_short_search, self.flag_no_silent, self.flag_short_no_silent, self.flag_repository, self.flag_short_repository, self.flag_parallel, self.flag_short_parallel ], 'install': [ self.flag_yes, self.flag_short_yes, self.flag_jobs, self.flag_short_jobs, self.flag_resolve_off, self.flag_short_resolve_off, self.flag_reinstall, self.flag_short_reinstall, self.flag_skip_installed, self.flag_short_skip_installed, self.flag_search, self.flag_short_search, self.flag_no_silent, self.flag_short_no_silent, self.flag_repository, self.flag_short_repository, self.flag_parallel, self.flag_short_parallel ], 'download': [ self.flag_yes, self.flag_short_yes, self.flag_search, self.flag_short_search, self.flag_directory, self.flag_short_directory, self.flag_repository, self.flag_short_repository, self.flag_parallel, self.flag_short_parallel ], 'remove': [ self.flag_yes, self.flag_short_yes, self.flag_resolve_off, self.flag_short_resolve_off, self.flag_search, self.flag_short_search, self.flag_no_silent, self.flag_short_no_silent, ], 'find': [ self.flag_search, self.flag_short_search, ], 'view': [ self.flag_search, self.flag_short_search, self.flag_repository, self.flag_short_repository, self.flag_pkg_version, self.flag_short_pkg_version ], 'search': [ self.flag_search, self.flag_short_search, self.flag_repository, self.flag_short_repository ], 'dependees': [ self.flag_full_reverse, self.flag_short_full_reverse, self.flag_search, self.flag_short_search, self.flag_repository, self.flag_short_repository, self.flag_pkg_version, self.flag_short_pkg_version ], 'tracking': [ self.flag_search, self.flag_short_search, self.flag_pkg_version, self.flag_short_pkg_version, self.flag_repository, self.flag_short_repository ] } self.commands['-h'] = self.commands['--help'] self.commands['-v'] = self.commands['--version'] self.commands['-u'] = self.commands['update'] self.commands['-U'] = self.commands['upgrade'] self.commands['-c'] = self.commands['check-updates'] self.commands['-I'] = self.commands['repo-info'] self.commands['-g'] = self.commands['configs'] self.commands['-L'] = self.commands['clean-logs'] self.commands['-D'] = self.commands['clean-tmp'] self.commands['-T'] = self.commands['clean-data'] self.commands['-b'] = self.commands['build'] self.commands['-i'] = self.commands['install'] self.commands['-d'] = self.commands['download'] self.commands['-R'] = self.commands['remove'] self.commands['-f'] = self.commands['find'] self.commands['-w'] = self.commands['view'] self.commands['-s'] = self.commands['search'] self.commands['-e'] = self.commands['dependees'] self.commands['-t'] = self.commands['tracking'] self.split_options() self.split_options_from_args() self.move_options() self.invalid_options() self.check_for_repositories() self.is_binary: bool = self.utils.is_binary_repo(self.repository) if self.repository != '*': if self.is_binary: self.data: dict = BinQueries(self.repository).repository_data() else: self.data: dict = SBoQueries(self.repository).repository_data() self.check = Check(self.repository, self.data) logging.basicConfig(filename=LoggingConfig.log_file, filemode=LoggingConfig.filemode, encoding=LoggingConfig.encoding, level=LoggingConfig.level) logger = logging.getLogger(LoggingConfig.date) logger.info(f'{self.__class__.__name__}: ' f'{self.__class__.__init__.__name__}: ' f'{args=}, {self.flags=}, {self.repository=}') def check_for_repositories(self) -> None: """ Checks combination for binaries use repositories only and if repository exists. """ except_options: list = [ '-s', 'search', ] if self.repository == '*' and not self.utils.is_option(except_options, self.args): self.usage.help_minimal(f"{self.prog_name}: invalid repository '{self.repository}'") elif self.repository not in list(self.repos.repositories.keys()) and self.repository != '*': self.usage.help_minimal(f"{self.prog_name}: invalid repository '{self.repository}'") if self.repository != '*': if not self.repos.repositories[self.repository][0]: self.usage.help_minimal(f"{self.prog_name}: repository '{self.repository}' is disabled") def invalid_options(self) -> None: """ Checks for invalid options. """ invalid, commands, repeat = [], [], [] for arg in self.args: if arg[0] == '-' and arg in self.commands.keys(): commands.append(arg) elif arg[0] == '-' and arg not in self.options: invalid.append(arg) # Counts the recurring options. for opt in self.flags: if self.flags.count(opt) > 1: repeat.append(opt) # Fixed for recurring options. if repeat: self.usage.help_minimal(f"{self.prog_name}: invalid recurring options '{', '.join(repeat)}'") # Fixed for invalid commands combination. if len(commands) > 1: self.usage.help_minimal(f"{self.prog_name}: invalid commands combination '{', '.join(commands)}'") # Fixed for correct options by command. try: options: list = self.commands[self.args[0]] for opt in self.flags: if opt not in options: invalid.append(opt) except (KeyError, IndexError): self.usage.help_short(1) # Prints error for invalid options. if invalid: self.usage.help_minimal(f"{self.prog_name}: invalid options '{','.join(invalid)}'") def split_options(self) -> None: """ Split options and commands, like: -iyjR slpkg -jyiR package Puts the command first and options after. Result: ['-i', '-y', '-j', '-R'] """ for args in self.args: if args[0] == '-' and args[:2] != '--' and len(args) >= 3 and '=' not in args: self.args.remove(args) for opt in list(map(lambda x: f'-{x}', [arg for arg in list(args[1:])])): if opt in self.commands.keys(): self.args.insert(0, opt) continue self.args.append(opt) def split_options_from_args(self) -> None: """ Split options from arguments. slpkg -d package --directory=/path/to/download Splits the option ['--directory'] and ['/path/to/download/'] """ for arg in self.args: if arg.startswith(self.flag_directory): self.directory: str = arg.split('=')[1] self.args.remove(arg) self.args.append(self.flag_directory) try: if arg.startswith(self.flag_short_directory): self.directory: str = self.args[self.args.index(arg) + 1] self.args.remove(self.directory) except IndexError: self.directory: Path = self.tmp_slpkg if arg.startswith(self.flag_repository): self.repository: str = arg.split('=')[1] self.args.remove(arg) self.args.append(self.flag_repository) try: if arg.startswith(self.flag_short_repository): self.repository: str = self.args[self.args.index(arg) + 1] self.args.remove(self.repository) except IndexError: self.repository: str = '' def move_options(self) -> None: """ Move options to the flags and removes from the arguments. """ new_args: list = [] for arg in self.args: if arg in self.options: self.flags.append(arg) else: new_args.append(arg) self.args: list = new_args def is_file_list_packages(self) -> list: """ Checks if the arg is filelist.pkgs. """ if self.args[1].endswith(self.file_list_suffix): file = Path(self.args[1]) packages: list = list(self.utils.read_packages_from_file(file)) else: packages: list = list(set(self.args[1:])) return packages def choose_packages(self, packages: list, method: str) -> list: """ Choose packages with dialog utility and -S, --search flag. """ height: int = 10 width: int = 70 list_height: int = 0 choices: list = [] title: str = f' Choose packages you want to {method} ' repo_packages: list = list(self.data.keys()) if method in ['remove', 'find']: installed: list = list(self.utils.installed_packages.values()) for package in installed: split_package: list = self.utils.split_binary_pkg(package) for pkg in packages: if pkg in package or pkg == '*': choices.extend([(split_package[0], split_package[1], False, f'Package: {package}')]) elif method == 'upgrade': for pkg in packages: for package in repo_packages: if pkg == package: inst_pkg: str = self.utils.is_package_installed(package) split_inst_pkg: list = self.utils.split_binary_pkg(inst_pkg) if self.is_binary: repo_ver: str = self.data[package][0] bin_pkg: str = self.data[package][1] repo_build_tag: str = self.utils.split_binary_pkg(bin_pkg[:-4])[3] else: repo_ver: str = self.data[package][2] repo_location: str = self.data[package][0] repo_build_tag: str = self.utils.read_sbo_build_tag(package, repo_location) choices.extend([(package, f'{split_inst_pkg[1]} -> {repo_ver}', True, f'Installed: {package}-{split_inst_pkg[1]} Build: {split_inst_pkg[3]} -> ' f'Available: {repo_ver} Build: {repo_build_tag}')]) else: for pkg in packages: for package in repo_packages: if pkg in package or pkg == '*': if self.is_binary: repo_ver: str = self.data[package][0] else: repo_ver: str = self.data[package][2] choices.extend([(package, repo_ver, False, f'Package: {package}-{repo_ver} ' f'> {self.repository}')]) if not choices: return packages text: str = f'There are {len(choices)} packages:' code, tags = self.dialogbox.checklist(text, packages, title, height, width, list_height, choices) if code == 'cancel': os.system('clear') raise SystemExit() if not tags or not code: return packages os.system('clear') return list(set(tags)) def help(self) -> None: if len(self.args) == 1: self.usage.help(0) self.usage.help_short(1) def version(self) -> None: if len(self.args) == 1: version = Version() version.view() raise SystemExit() self.usage.help_short(1) def update(self) -> None: if len(self.args) == 1: update = UpdateRepository(self.flags, self.repository) update.repositories() raise SystemExit() self.usage.help_short(1) def upgrade(self) -> None: command = Argparse.upgrade.__name__ if len(self.args) == 1: self.check.is_empty_database() upgrade = Upgrade(self.repository, self.data) packages: list = list(upgrade.packages()) packages: list = self.choose_packages(packages, command) if not packages: print('\nEverything is up-to-date!\n') raise SystemExit() if self.is_binary: install = Packages(self.repository, self.data, packages, self.flags, mode=command) install.execute() else: install = Slackbuilds(self.repository, self.data, packages, self.flags, mode=command) install.execute() raise SystemExit() self.usage.help_short(1) def check_updates(self) -> None: if len(self.args) == 1: check = CheckUpdates(self.flags, self.repository) check.updates() raise SystemExit() self.usage.help_short(1) def repo_info(self) -> None: if len(self.args) == 1: repo = RepoInfo() repo.info() raise SystemExit() self.usage.help_short(1) def edit_configs(self) -> None: if len(self.args) == 1: self.form_configs.edit() raise SystemExit() self.usage.help_short(1) def clean_logs(self) -> None: if len(self.args) == 1: clean = Cleanings(self.flags) clean.logs_deps() raise SystemExit() self.usage.help_short(1) def clean_tmp(self) -> None: if len(self.args) == 1: clean = Cleanings(self.flags) clean.tmp() raise SystemExit() self.usage.help_short(1) def clean_data(self) -> None: if len(self.args) == 1: clean = Cleanings(self.flags) clean.db_tables() raise SystemExit() self.usage.help_short(1) def build(self) -> None: command = Argparse.build.__name__ if len(self.args) >= 2: self.check.is_empty_database() packages: list = self.is_file_list_packages() if self.utils.is_option(self.flag_searches, self.flags): packages: list = self.choose_packages(packages, command) self.check.exists_in_the_database(packages) self.check.is_package_unsupported(packages) if self.repository in list(self.repos.repositories.keys())[:2]: build = Slackbuilds(self.repository, self.data, packages, self.flags, mode=command) build.execute() else: self.usage.help_minimal(f"{self.prog_name}: invalid repository '{self.repository}'") raise SystemExit() self.usage.help_short(1) def install(self) -> None: command = Argparse.install.__name__ if len(self.args) >= 2: self.check.is_empty_database() packages: list = self.is_file_list_packages() if self.utils.is_option(self.flag_searches, self.flags): packages: list = self.choose_packages(packages, command) if self.is_binary: self.check.exists_in_the_database(packages) install = Packages(self.repository, self.data, packages, self.flags, mode=command) install.execute() else: self.check.exists_in_the_database(packages) self.check.is_package_unsupported(packages) install = Slackbuilds(self.repository, self.data, packages, self.flags, mode=command) install.execute() raise SystemExit() self.usage.help_short(1) def download(self) -> None: command = Argparse.download.__name__ if len(self.args) >= 2: self.check.is_empty_database() packages: list = self.is_file_list_packages() if self.utils.is_option(self.flag_searches, self.flags): packages: list = self.choose_packages(packages, command) self.check.exists_in_the_database(packages) download = Download(self.directory, self.flags, self.data, self.repository) download.packages(packages) raise SystemExit() self.usage.help_short(1) def remove(self) -> None: command = Argparse.remove.__name__ if len(self.args) >= 2: packages: list = self.is_file_list_packages() if self.utils.is_option(self.flag_searches, self.flags): packages: list = self.choose_packages(packages, command) self.check.is_installed(packages) remove = RemovePackages(packages, self.flags) remove.remove() raise SystemExit() self.usage.help_short(1) def find(self) -> None: command = Argparse.find.__name__ if len(self.args) >= 2: self.check.is_empty_database() packages: list = self.is_file_list_packages() if self.utils.is_option(self.flag_searches, self.flags): packages: list = self.choose_packages(packages, command) find = FindInstalled() find.find(packages) raise SystemExit() self.usage.help_short(1) def view(self) -> None: command = Argparse.view.__name__ if len(self.args) >= 2: self.check.is_empty_database() packages: list = self.is_file_list_packages() if self.utils.is_option(self.flag_searches, self.flags): packages: list = self.choose_packages(packages, command) self.check.exists_in_the_database(packages) view = ViewPackage(self.flags, self.repository) if self.is_binary: view.package(self.data, packages) else: view.slackbuild(self.data, packages) raise SystemExit() self.usage.help_short(1) def search(self) -> None: command = Argparse.search.__name__ if len(self.args) >= 2: self.check.is_empty_database() packages: list = self.is_file_list_packages() if self.utils.is_option(self.flag_searches, self.flags): packages: list = self.choose_packages(packages, command) pkgs = SearchPackage(self.data, packages, self.repository) pkgs.search() raise SystemExit() self.usage.help_short(1) def dependees(self) -> None: command = Argparse.dependees.__name__ if len(self.args) >= 2: self.check.is_empty_database() packages: list = self.is_file_list_packages() if self.utils.is_option(self.flag_searches, self.flags): packages: list = self.choose_packages(packages, command) self.check.exists_in_the_database(packages) dependees = Dependees(self.data, packages, self.flags, self.repository) dependees.find() raise SystemExit() self.usage.help_short(1) def tracking(self) -> None: command = Argparse.tracking.__name__ if len(self.args) >= 2: self.check.is_empty_database() packages: list = self.is_file_list_packages() if self.utils.is_option(self.flag_searches, self.flags): packages: list = self.choose_packages(packages, command) self.check.exists_in_the_database(packages) tracking = Tracking(self.flags, self.repository) tracking.packages(self.data, packages) raise SystemExit() self.usage.help_short(1) def help_for_commands(self) -> None: """ Extra help information for commands. """ if len(self.args) == 2: try: flags = self.commands[self.args[1]] Help(self.args[1], flags).view() except KeyError: logger = logging.getLogger(LoggingConfig.date) logger.exception(f'{self.__class__.__name__}: ' f'{self.__class__.help_for_commands.__name__}') self.usage.help_minimal(f"{self.prog_name}: invalid argument '{''.join(self.args[1])}'") else: self.usage.help_short(1) def main() -> None: args: list = sys.argv args.pop(0) usage = Usage() argparse = Argparse(args) arguments: dict = { '-h': argparse.help, '--help': argparse.help, '-v': argparse.version, '--version': argparse.version, 'help': argparse.help_for_commands, 'update': argparse.update, '-u': argparse.update, 'upgrade': argparse.upgrade, '-U': argparse.upgrade, 'check-updates': argparse.check_updates, '-c': argparse.check_updates, 'repo-info': argparse.repo_info, '-I': argparse.repo_info, 'configs': argparse.edit_configs, '-g': argparse.edit_configs, 'clean-logs': argparse.clean_logs, '-L': argparse.clean_logs, 'clean-data': argparse.clean_data, '-T': argparse.clean_data, 'clean-tmp': argparse.clean_tmp, '-D': argparse.clean_tmp, 'build': argparse.build, '-b': argparse.build, 'install': argparse.install, '-i': argparse.install, 'download': argparse.download, '-d': argparse.download, 'remove': argparse.remove, '-R': argparse.remove, 'view': argparse.view, '-w': argparse.view, 'find': argparse.find, '-f': argparse.find, 'search': argparse.search, '-s': argparse.search, 'dependees': argparse.dependees, '-e': argparse.dependees, 'tracking': argparse.tracking, '-t': argparse.tracking } try: arguments[args[0]]() except (KeyError, IndexError): logger = logging.getLogger(LoggingConfig.date) logger.exception(main.__name__) usage.help_short(1) except KeyboardInterrupt: raise SystemExit(1) if __name__ == '__main__': main()