From: Michael Tremer Date: Tue, 6 Jul 2021 16:03:55 +0000 (+0000) Subject: CLI: Remove pakfire cli into an extra file X-Git-Tag: 0.9.28~1093 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=73d0032770e4895e9e2ddf58d28c6f5fa777eaf3;p=pakfire.git CLI: Remove pakfire cli into an extra file Signed-off-by: Michael Tremer --- diff --git a/.gitignore b/.gitignore index 6493cbfc3..4079771e6 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /missing /contrib/pakfire.nm /src/pakfire/__version__.py +/src/scripts/pakfire /src/scripts/pakfire-builder /src/scripts/pakfire-client /src/scripts/pakfire-daemon diff --git a/Makefile.am b/Makefile.am index 8cc0f01c9..6bfe1c83e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -100,30 +100,25 @@ dist_doc_DATA = \ README # ------------------------------------------------------------------------------ - -dist_bin_SCRIPTS = \ - src/scripts/pakfire bin_SCRIPTS = \ + src/scripts/pakfire \ src/scripts/pakfire-builder \ src/scripts/pakfire-client \ src/scripts/pakfire-daemon EXTRA_DIST += \ + src/scripts/pakfire.in \ src/scripts/pakfire-builder.in \ src/scripts/pakfire-client.in \ src/scripts/pakfire-daemon.in CLEANFILES += \ + src/scripts/pakfire \ src/scripts/pakfire-builder \ src/scripts/pakfire-client \ src/scripts/pakfire-daemon -install-exec-local: - $(MKDIR_P) $(DESTDIR)/$(bindir) - cd $(DESTDIR)/$(bindir) && \ - $(LN_S) -vf pakfire pakfire-key - # ------------------------------------------------------------------------------ pakfire_PYTHON = \ diff --git a/src/pakfire/__init__.py b/src/pakfire/__init__.py index a9759336b..8b281b0fc 100644 --- a/src/pakfire/__init__.py +++ b/src/pakfire/__init__.py @@ -21,5 +21,7 @@ from ._pakfire import Pakfire +from .__version__ import PAKFIRE_VERSION as __version__ + # Import Exceptions from ._pakfire import CommandExecutionError diff --git a/src/pakfire/cli.py b/src/pakfire/cli.py index 98a9c224a..648f191fa 100644 --- a/src/pakfire/cli.py +++ b/src/pakfire/cli.py @@ -37,289 +37,6 @@ from .i18n import _ class Cli(object): default_path = "/" - def parse_cli(self): - parser = argparse.ArgumentParser( - description = _("Pakfire command line interface"), - ) - subparsers = parser.add_subparsers() - - # Add common arguments - self._add_common_arguments(parser) - - parser.add_argument("--arch", "-a", nargs="?", - help=_("Run pakfire for the given architecture")) - parser.add_argument("--root", metavar="PATH", default="/", - help=_("The path where pakfire should operate in")) - - # check - check = subparsers.add_parser("check", help=_("Check the system for any errors")) - check.set_defaults(func=self.handle_check) - - # clean - clean = subparsers.add_parser("clean", help=_("Cleanup all temporary files")) - clean.set_defaults(func=self.handle_clean) - - # execute - execute = subparsers.add_parser("execute", - help=_("Executes a command in the pakfire environment (useful for development)")) - execute.add_argument("--bind", action="append", default=[], dest="binds", - help=_("Bind-mounts the given directory")) - execute.add_argument("command", nargs=argparse.REMAINDER) - execute.set_defaults(func=self.handle_execute) - - # info - info = subparsers.add_parser("info", - help=_("Print some information about the given package(s)")) - info.add_argument("--long", action="store_true", - help=_("Show more information")) - info.add_argument("package", help=_("Give at least the name of one package")) - info.set_defaults(func=self.handle_info) - - # install - install = subparsers.add_parser("install", - help=_("Install one or more packages to the system")) - install.add_argument("package", nargs="+", - help=_("Give name of at least one package to install")) - install.add_argument("--without-recommended", action="store_true", - help=_("Don't install recommended packages")) - install.add_argument("--allow-uninstall", action="store_true", - help=_("Allow uninstalling packages")) - install.add_argument("--allow-downgrade", action="store_true", - help=_("Allow downgrading packages")) - install.set_defaults(func=self.handle_install) - - # provides - provides = subparsers.add_parser("provides", - help=_("Get a list of packages that provide a given file or feature")) - provides.add_argument("pattern", help=_("File or feature to search for")) - provides.set_defaults(func=self.handle_provides) - - # requires - requires = subparsers.add_parser("requires", - help=_("Get a list of packages that require this dependency")) - requires.add_argument("pattern", help=_("File or feature to search for")) - requires.set_defaults(func=self.handle_requires) - - # reinstall - reinstall = subparsers.add_parser("reinstall", - help=_("Reinstall one or more packages")) - reinstall.add_argument("package", nargs="+", - help=_("Give name of at least one package to reinstall")) - reinstall.set_defaults(func=self.handle_reinstall) - - # remove - remove = subparsers.add_parser("remove", - help=_("Remove one or more packages from the system")) - remove.add_argument("package", nargs="+", - help=_("Give name of at least one package to remove")) - remove.add_argument("--keep-dependencies", action="store_true", - help=_("Keep dependencies installed")) - remove.set_defaults(func=self.handle_remove) - - # repolist - repolist = subparsers.add_parser("repolist", - help=_("List all currently enabled repositories")) - repolist.set_defaults(func=self.handle_repolist) - - # search - search = subparsers.add_parser("search", help=_("Search for a given pattern")) - search.add_argument("pattern", help=_("A pattern to search for")) - search.set_defaults(func=self.handle_search) - - # sync - sync = subparsers.add_parser("sync", - help=_("Sync all installed with the latest one in the distribution")) - sync.add_argument("--keep-orphaned", action="store_true", - help=_("Keep orphaned packages")) - sync.set_defaults(func=self.handle_sync) - - # update - update = subparsers.add_parser("update", - help=_("Update the whole system or one specific package")) - update.add_argument("package", nargs="*", - help=_("Give a name of a package to update or leave emtpy for all")) - update.add_argument("--exclude", "-x", nargs="+", default=[], - help=_("Exclude package from update")) - update.add_argument("--allow-uninstall", action="store_true", - help=_("Allow uninstalling packages")) - update.add_argument("--allow-downgrade", action="store_true", - help=_("Allow downgrading packages")) - update.set_defaults(func=self.handle_update) - - return parser.parse_args() - - def _add_common_arguments(self, parser, offline_switch=True): - parser.add_argument("--version", action="version", - version="%(prog)s " + PAKFIRE_VERSION) - - parser.add_argument("-v", "--verbose", action="store_true", - help=_("Enable verbose output.")) - - parser.add_argument("-c", "--config", nargs="?", - help=_("Path to a configuration file to load.")) - - parser.add_argument("--disable-repo", nargs="*", metavar="REPO", - help=_("Disable a repository temporarily."), default=[]) - - parser.add_argument("--enable-repo", nargs="*", metavar="REPO", - help=_("Enable a repository temporarily."), default=[]) - - if offline_switch: - parser.add_argument("--offline", action="store_true", - help=_("Run pakfire in offline mode.")) - - def pakfire(self, ns): - p = _pakfire.Pakfire( - arch=ns.arch, - conf=ns.config, - path=ns.root if "root" in ns else self.default_path, - offline=ns.offline, - ) - - # Disable repositories. - for repo_name in ns.disable_repo: - repo = p.get_repo(repo_name) - repo.enabled = False - - # Enable repositories. - for repo_name in ns.enable_repo: - repo = p.get_repo(repo_name) - repo.enabled = True - - return p - - def handle_execute(self, ns): - pakfire = self.pakfire(ns) - - # Bind-mount everything - for bind in ns.binds: - pakfire.bind(bind) - - # Log everything to the console - def logging_callback(level, line): - if level >= logging.ERROR: - sys.stderr.write("%s\n" % line) - else: - sys.stdout.write("%s\n" % line) - - return pakfire.execute(ns.command, logging_callback=logging_callback) - - def run(self): - args = self.parse_cli() - assert args.func, "Argument function not defined" - - try: - return args.func(args) - - except KeyboardInterrupt: - return 128 + signal.SIGINT - - except DependencyError as e: - print(_("One or more dependencies could not been resolved")) - print("") # empty line - - # This exception provides a list of all problems - problems, = e.args - - # List all problems - for problem in problems: - print(" * %s" % problem) - - print(" %s" % _("Possible solutions are:")) - for solution in problem.solutions: - print(" * %s" % solution) - - # Add another empty line - print("") - - return 4 - - # Catch all errors and show a user-friendly error message. - except Error as e: - print(_("An error has occured when running Pakfire")) - print(_("%s: %s") % (e.__class__.__name__, e.message)) - - return e.exit_code - - def handle_info(self, ns): - p = self.pakfire(ns) - - for pkg in p.search(ns.package, name_only=True): - s = pkg.dump(long=ns.long) - print(s) - - def handle_search(self, ns): - p = self.pakfire(ns) - - for pkg in p.search(ns.pattern): - # Skip any -debuginfo packages - if pkg.name.endswith("-debuginfo"): - continue - - print("%-24s: %s" % (pkg.name, pkg.summary)) - - def handle_update(self, ns): - p = self.pakfire(ns) - p.update( - ns.package, - excludes=ns.exclude, - allow_uninstall=ns.allow_uninstall, - allow_downgrade=ns.allow_downgrade, - ) - - def handle_sync(self, ns): - self.pakfire(ns).sync(keep_orphaned=ns.keep_orphaned) - - def handle_install(self, ns): - p = self.pakfire(ns) - p.install( - ns.package, - without_recommended=ns.without_recommended, - allow_uninstall=ns.allow_uninstall, - allow_downgrade=ns.allow_downgrade, - ) - - def handle_reinstall(self, ns): - with self.pakfire(ns) as p: - transaction = p.reinstall(ns.package) - - # Execute the transaction - self._execute_transaction(transaction) - - def handle_remove(self, ns): - p = self.pakfire(ns) - p.erase(ns.package, keep_dependencies=ns.keep_dependencies) - - def handle_provides(self, ns, long=False): - for pkg in self.pakfire(ns).whatprovides(ns.pattern): - s = pkg.dump(long=long) - print(s) - - def handle_requires(self, ns): - for pkg in self.pakfire(ns).whatrequires(ns.pattern): - s = pkg.dump(long=True) - print(s) - - def handle_repolist(self, ns): - p = self.pakfire(ns) - - FORMAT = " %-20s %8s %12s %12s " - title = FORMAT % (_("Repository"), _("Enabled"), _("Priority"), _("Packages")) - print(title) - print("=" * len(title)) # spacing line - - for repo in p.repos: - print(FORMAT % (repo.name, repo.enabled, repo.priority, len(repo))) - - def handle_clean(self, ns): - print(_("Cleaning up everything...")) - - p = self.pakfire(ns) - p.clean() - - def handle_check(self, ns): - self.pakfire(ns).check() - class CliKey(Cli): def parse_cli(self): diff --git a/src/scripts/pakfire b/src/scripts/pakfire deleted file mode 100755 index 7004cccb3..000000000 --- a/src/scripts/pakfire +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/python3 -############################################################################### -# # -# Pakfire - The IPFire package management system # -# Copyright (C) 2017 Pakfire development team # -# # -# This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see . # -# # -############################################################################### - -import os -import sys - -# Catch ImportError and show a more user-friendly message about what went wrong -try: - import pakfire.cli - -except ImportError as e: - # Try to load at least the i18n support, but when this fails as well we can - # go with an English error message. - try: - from pakfire.i18n import _ - except ImportError: - _ = lambda x: x - - print(_("There has been an error when trying to import one or more of the" - " modules, that are required to run Pakfire.")) - print(_("Please check your installation of Pakfire.")) - print() - print(_("The error that lead to this:")) - print(" ", e) - print() - - # Exit immediately. - sys.exit(1) - -basename2cls = { - "pakfire" : pakfire.cli.Cli, - "pakfire-client" : pakfire.cli.CliClient, - "pakfire-key" : pakfire.cli.CliKey, -} - -# Get the basename of the program -basename = os.path.basename(sys.argv[0]) - -# Check if the program was called with a weird basename. -# If so, we exit immediately. -if basename not in basename2cls: - sys.exit(127) - -cli = basename2cls[basename]() -ret = cli.run() - -sys.exit(ret) diff --git a/src/scripts/pakfire.in b/src/scripts/pakfire.in new file mode 100644 index 000000000..032b10536 --- /dev/null +++ b/src/scripts/pakfire.in @@ -0,0 +1,278 @@ +#!/usr/bin/python3 +############################################################################## +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2021 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +import argparse +import sys + +import pakfire +from pakfire.i18n import _ + +class Cli(object): + def parse_cli(self): + parser = argparse.ArgumentParser( + description = _("Pakfire command line interface"), + ) + + # Version + parser.add_argument("--version", action="version", + version="%%(prog)s %s" % pakfire.__version__) + + # Which configuration file to load? + parser.add_argument("--config", "-c", nargs="?", + help=_("Configuration file")) + + # Enable/disable repositories + parser.add_argument("--disable-repo", nargs="*", metavar="REPO", + help=_("Disable a repository"), default=[]) + parser.add_argument("--enable-repo", nargs="*", metavar="REPO", + help=_("Enable a repository"), default=[]) + + # Offline mode + parser.add_argument("--offline", action="store_true", + help=_("Run pakfire in offline mode")) + + # Architecture + parser.add_argument("--arch", "-a", nargs="?", + help=_("Run pakfire for the given architecture")) + + # Root + parser.add_argument("--root", metavar="PATH", default="/", + help=_("The path where pakfire should operate in")) + + subparsers = parser.add_subparsers() + + # check + check = subparsers.add_parser("check", + help=_("Check the system for any errors")) + check.set_defaults(func=self._check) + + # clean + clean = subparsers.add_parser("clean", + help=_("Cleanup all temporary files")) + clean.set_defaults(func=self._clean) + + # execute + execute = subparsers.add_parser("execute", + help=_("Executes a command in the pakfire environment (useful for development)")) + execute.add_argument("--bind", action="append", default=[], dest="binds", + help=_("Bind-mounts the given directory")) + execute.add_argument("command", nargs=argparse.REMAINDER) + execute.set_defaults(func=self._execute) + + # info + info = subparsers.add_parser("info", + help=_("Print some information about the given package(s)")) + info.add_argument("--long", action="store_true", + help=_("Show more information")) + info.add_argument("package", help=_("Give at least the name of one package")) + info.set_defaults(func=self._info) + + # install + install = subparsers.add_parser("install", + help=_("Install one or more packages to the system")) + install.add_argument("package", nargs="+", + help=_("Give name of at least one package to install")) + install.add_argument("--without-recommended", action="store_true", + help=_("Don't install recommended packages")) + install.add_argument("--allow-uninstall", action="store_true", + help=_("Allow uninstalling packages")) + install.add_argument("--allow-downgrade", action="store_true", + help=_("Allow downgrading packages")) + install.set_defaults(func=self._install) + + # provides + provides = subparsers.add_parser("provides", + help=_("Get a list of packages that provide a given file or feature")) + provides.add_argument("pattern", help=_("File or feature to search for")) + provides.set_defaults(func=self._provides) + + # requires + requires = subparsers.add_parser("requires", + help=_("Get a list of packages that require this dependency")) + requires.add_argument("pattern", help=_("File or feature to search for")) + requires.set_defaults(func=self._requires) + + # remove + remove = subparsers.add_parser("remove", + help=_("Remove one or more packages from the system")) + remove.add_argument("package", nargs="+", + help=_("Give name of at least one package to remove")) + remove.add_argument("--keep-dependencies", action="store_true", + help=_("Keep dependencies installed")) + remove.set_defaults(func=self._remove) + + # repolist + repolist = subparsers.add_parser("repolist", + help=_("List all currently enabled repositories")) + repolist.set_defaults(func=self._repolist) + + # search + search = subparsers.add_parser("search", + help=_("Search for a given pattern")) + search.add_argument("pattern", + help=_("A pattern to search for")) + search.set_defaults(func=self._search) + + # sync + sync = subparsers.add_parser("sync", + help=_("Sync all installed with the latest one in the distribution")) + sync.add_argument("--keep-orphaned", action="store_true", + help=_("Keep orphaned packages")) + sync.set_defaults(func=self._sync) + + # update + update = subparsers.add_parser("update", + help=_("Update the whole system or one specific package")) + update.add_argument("package", nargs="*", + help=_("Give a name of a package to update or leave emtpy for all")) + update.add_argument("--exclude", "-x", nargs="+", default=[], + help=_("Exclude package from update")) + update.add_argument("--allow-uninstall", action="store_true", + help=_("Allow uninstalling packages")) + update.add_argument("--allow-downgrade", action="store_true", + help=_("Allow downgrading packages")) + update.set_defaults(func=self._update) + + args = parser.parse_args() + + # Print usage if no action was given + if not "func" in args: + parser.print_usage() + sys.exit(2) + + return args + + def __call__(self): + # Parse command line arguments + args = self.parse_cli() + + # Create Pakfire instance + p = pakfire.Pakfire( + conf=args.config, + arch=args.arch, + path=args.root, + offline=args.offline, + ) + + # Disable repositories + for name in args.disable_repo: + repo = p.get_repo(name) + repo.enabled = False + + # Enable repositories + for name in args.enable_repo: + repo = p.get_repo(name) + repo.enabled = True + + # Call function + try: + ret = args.func(p, args) + + # Catch invalid inputs + except ValueError as e: + sys.stderr.write("%s\n" % e) + ret = 2 + + # Return with exit code + sys.exit(ret or 0) + + def _check(self, p, args): + p.check() + + def _clean(self, p, args): + print(_("Cleaning up everything...")) + p.clean() + + def _execute(self, p, args): + """ + Executes a command + """ + # Bind-mount everything + for bind in args.binds: + p.bind(bind) + + # Log everything to the console + def logging_callback(level, line): + if level >= logging.ERROR: + sys.stderr.write("%s\n" % line) + else: + sys.stdout.write("%s\n" % line) + + return p.execute(args.command, logging_callback=logging_callback) + + def _info(self, p, args): + for pkg in p.search(args.package, name_only=True): + s = pkg.dump(long=args.long) + print(s) + + def _install(self, p, args): + p.install( + args.package, + without_recommended=args.without_recommended, + allow_uninstall=args.allow_uninstall, + allow_downgrade=args.allow_downgrade, + ) + + def _provides(self, p, args): + for pkg in p.whatprovides(args.pattern): + s = pkg.dump(long=True) + print(s) + + def _remove(self, p, args): + p.erase(args.package, keep_dependencies=args.keep_dependencies) + + def _repolist(self, p, args): + FORMAT = " %-20s %8s %12s %12s " + title = FORMAT % (_("Repository"), _("Enabled"), _("Priority"), _("Packages")) + print(title) + print("=" * len(title)) # spacing line + + for repo in p.repos: + print(FORMAT % (repo.name, repo.enabled, repo.priority, len(repo))) + + def _requires(self, p, args): + for pkg in p.whatrequires(args.pattern): + s = pkg.dump(long=True) + print(s) + + def _search(self, p, args): + for pkg in p.search(args.pattern): + # Skip any -debuginfo packages + if pkg.name.endswith("-debuginfo"): + continue + + print("%-24s: %s" % (pkg.name, pkg.summary)) + + def _sync(self, p, args): + p.sync(keep_orphaned=args.keep_orphaned) + + def _update(self, p, args): + p.update( + args.package, + excludes=args.exclude, + allow_uninstall=args.allow_uninstall, + allow_downgrade=args.allow_downgrade, + ) + + +if __name__ == "__main__": + c = Cli() + c()