]> git.ipfire.org Git - people/stevee/pakfire.git/blobdiff - python/pakfire/cli.py
Implement distro-sync.
[people/stevee/pakfire.git] / python / pakfire / cli.py
index 825c127ecb323f64c83a12ffdaab295d226cc3de..01e0f024649f0ea64a016f9901a07b5182ef2100 100644 (file)
@@ -29,6 +29,7 @@ import tempfile
 import base
 import client
 import config
+import daemon
 import logger
 import packages
 import repository
@@ -67,6 +68,7 @@ class Cli(object):
                self.parse_command_info()
                self.parse_command_search()
                self.parse_command_check_update()
+               self.parse_command_distro_sync()
                self.parse_command_update()
                self.parse_command_downgrade()
                self.parse_command_provides()
@@ -76,6 +78,7 @@ class Cli(object):
                self.parse_command_clean()
                self.parse_command_check()
                self.parse_command_resolvdep()
+               self.parse_command_extract()
 
                # Finally parse all arguments from the command line and save them.
                self.args = self.parser.parse_args()
@@ -85,6 +88,7 @@ class Cli(object):
                        "reinstall"    : self.handle_reinstall,
                        "remove"       : self.handle_remove,
                        "check_update" : self.handle_check_update,
+                       "distro_sync"  : self.handle_distro_sync,
                        "update"       : self.handle_update,
                        "downgrade"    : self.handle_downgrade,
                        "info"         : self.handle_info,
@@ -96,6 +100,7 @@ class Cli(object):
                        "clean_all"    : self.handle_clean_all,
                        "check"        : self.handle_check,
                        "resolvdep"    : self.handle_resolvdep,
+                       "extract"      : self.handle_extract,
                }
 
        @property
@@ -183,15 +188,17 @@ class Cli(object):
                sub_remove.add_argument("action", action="store_const", const="remove")
 
        @staticmethod
-       def _parse_command_update(parser):
-               parser.add_argument("package", nargs="*",
-                       help=_("Give a name of a package to update or leave emtpy for all."))
+       def _parse_command_update(parser, package=True):
+               if package:
+                       parser.add_argument("package", nargs="*",
+                               help=_("Give a name of a package to update or leave emtpy for all."))
+
                parser.add_argument("--exclude", "-x", nargs="+",
                        help=_("Exclude package from update."))
                parser.add_argument("--allow-vendorchange", action="store_true",
                        help=_("Allow changing the vendor of packages."))
-               parser.add_argument("--allow-archchange", action="store_true",
-                       help=_("Allow changing the architecture of packages."))
+               parser.add_argument("--disallow-archchange", action="store_true",
+                       help=_("Disallow changing the architecture of packages."))
 
        def parse_command_update(self):
                # Implement the "update" command.
@@ -200,6 +207,13 @@ class Cli(object):
                sub_update.add_argument("action", action="store_const", const="update")
                self._parse_command_update(sub_update)
 
+       def parse_command_distro_sync(self):
+               # Implement the "distro-sync" command.
+               sub_distro_sync = self.sub_commands.add_parser("distro-sync",
+                       help=_("Sync all installed with the latest one in the distribution."))
+               sub_distro_sync.add_argument("action", action="store_const", const="distro_sync")
+               self._parse_command_update(sub_distro_sync, package=False)
+
        def parse_command_check_update(self):
                # Implement the "check-update" command.
                sub_check_update = self.sub_commands.add_parser("check-update",
@@ -215,8 +229,8 @@ class Cli(object):
                        help=_("Give a name of a package to downgrade."))
                sub_downgrade.add_argument("--allow-vendorchange", action="store_true",
                        help=_("Allow changing the vendor of packages."))
-               sub_downgrade.add_argument("--allow-archchange", action="store_true",
-                       help=_("Allow changing the architecture of packages."))
+               sub_downgrade.add_argument("--disallow-archchange", action="store_true",
+                       help=_("Disallow changing the architecture of packages."))
                sub_downgrade.add_argument("action", action="store_const", const="downgrade")
 
        def parse_command_info(self):
@@ -291,6 +305,16 @@ class Cli(object):
                        help=_("Give name of at least one package to check."))
                sub_resolvdep.add_argument("action", action="store_const", const="resolvdep")
 
+       def parse_command_extract(self):
+               # Implement the "extract" command.
+               sub_extract = self.sub_commands.add_parser("extract",
+                       help=_("Extract a package to a directory."))
+               sub_extract.add_argument("package", nargs="+",
+                       help=_("Give name of the file to extract."))
+               sub_extract.add_argument("--target", nargs="?",
+                       help=_("Target directory where to extract to."))
+               sub_extract.add_argument("action", action="store_const", const="extract")
+
        def run(self):
                action = self.args.action
 
@@ -315,13 +339,19 @@ class Cli(object):
 
        def handle_update(self, **args):
                p = self.create_pakfire()
-               p.update(
-                       self.args.package,
-                       excludes=self.args.exclude,
-                       allow_vendorchange=self.args.allow_vendorchange,
-                       allow_archchange=self.args.allow_archchange,
-                       **args
-               )
+
+               packages = getattr(self.args, "package", [])
+
+               args.update({
+                       "allow_archchange"   : not self.args.disallow_archchange,
+                       "allow_vendorchange" : self.args.allow_vendorchange,
+                       "excludes"           : self.args.exclude,
+               })
+
+               p.update(packages, **args)
+
+       def handle_distro_sync(self):
+               self.handle_update(sync=True)
 
        def handle_check_update(self):
                self.handle_update(check=True)
@@ -331,7 +361,7 @@ class Cli(object):
                p.downgrade(
                        self.args.package,
                        allow_vendorchange=self.args.allow_vendorchange,
-                       allow_archchange=self.args.allow_archchange,
+                       allow_archchange=not self.args.disallow_archchange,
                        **args
                )
 
@@ -398,6 +428,41 @@ class Cli(object):
                t = transaction.Transaction.from_solver(p, solver)
                t.dump()
 
+       def handle_extract(self):
+               p = self.create_pakfire()
+
+               # Open all packages.
+               pkgs = []
+               for pkg in self.args.package:
+                       pkg = packages.open(self, None, pkg)
+                       pkgs.append(pkg)
+
+               target_prefix = self.args.target
+
+               # Search for binary packages.
+               binary_packages = any([p.type == "binary" for p in pkgs])
+               source_packages = any([p.type == "source" for p in pkgs])
+
+               if binary_packages and source_packages:
+                       raise Error, _("Cannot extract mixed package types")
+
+               if binary_packages and not target_prefix:
+                       raise Error, _("You must provide an install directory with --target=...")
+
+               elif source_packages and not target_prefix:
+                       target_prefix = "/usr/src/packages/"
+
+               if target_prefix == "/":
+                       raise Error, _("Cannot extract to /.")
+
+               for pkg in pkgs:
+                       if pkg.type == "binary":
+                               target_dir = target_prefix
+                       elif pkg.type == "source":
+                               target_dir = os.path.join(target_prefix, pkg.friendly_name)
+
+                       pkg.extract(message=_("Extracting"), prefix=target_dir)
+
 
 class CliBuilder(Cli):
        pakfire = base.PakfireBuilder
@@ -428,6 +493,7 @@ class CliBuilder(Cli):
                self.parse_command_repolist()
                self.parse_command_clean()
                self.parse_command_resolvdep()
+               self.parse_command_extract()
 
                # Finally parse all arguments from the command line and save them.
                self.args = self.parser.parse_args()
@@ -444,6 +510,7 @@ class CliBuilder(Cli):
                        "repolist"    : self.handle_repolist,
                        "clean_all"   : self.handle_clean_all,
                        "resolvdep"   : self.handle_resolvdep,
+                       "extract"     : self.handle_extract,
                }
 
        @property
@@ -493,6 +560,8 @@ class CliBuilder(Cli):
                        help=_("Run a shell after a successful build."))
                sub_build.add_argument("--no-install-test", action="store_true",
                        help=_("Do not perform the install test."))
+               sub_build.add_argument("--private-network", action="store_true",
+                       help=_("Disable network in container."))
 
        def parse_command_shell(self):
                # Implement the "shell" command.
@@ -504,6 +573,8 @@ class CliBuilder(Cli):
 
                sub_shell.add_argument("-m", "--mode", nargs="?", default="development",
                        help=_("Mode to run in. Is either 'release' or 'development' (default)."))
+               sub_shell.add_argument("--private-network", action="store_true",
+                       help=_("Disable network in container."))
 
        def parse_command_dist(self):
                # Implement the "dist" command.
@@ -530,22 +601,25 @@ class CliBuilder(Cli):
                else:
                        raise FileNotFoundError, pkg
 
-               # Check whether to enable the install test.
-               install_test = not self.args.no_install_test
+               # Build argument list.
+               kwargs = {
+                       "after_shell"   : self.args.after_shell,
+                       # Check whether to enable the install test.
+                       "install_test"  : not self.args.no_install_test,
+                       "result_dir"    : [self.args.resultdir,],
+                       "shell"         : True,
+               }
 
                if self.args.mode == "release":
-                       release_build = True
+                       kwargs["release_build"] = True
                else:
-                       release_build = False
+                       kwargs["release_build"] = False
+
+               if self.args.private_network:
+                       kwargs["private_network"] = True
 
                p = self.create_pakfire()
-               p.build(pkg,
-                       install_test=install_test,
-                       resultdirs=[self.args.resultdir,],
-                       shell=True,
-                       after_shell=self.args.after_shell,
-                       release_build=release_build,
-               )
+               p.build(pkg, **kwargs)
 
        def handle_shell(self):
                pkg = None
@@ -567,7 +641,16 @@ class CliBuilder(Cli):
                        release_build = False
 
                p = self.create_pakfire()
-               p.shell(pkg, release_build=release_build)
+
+               kwargs = {
+                       "release_build" : release_build,
+               }
+
+               # Private network
+               if self.args.private_network:
+                       kwargs["private_network"] = True
+
+               p.shell(pkg, **kwargs)
 
        def handle_dist(self):
                # Get the packages from the command line options
@@ -616,7 +699,7 @@ class CliServer(Cli):
                # Finally parse all arguments from the command line and save them.
                self.args = self.parser.parse_args()
 
-               self.server = server.Server(**self.pakfire_args)
+               #self.server = server.Server(**self.pakfire_args)
 
                self.action2func = {
                        "build"      : self.handle_build,
@@ -721,7 +804,7 @@ class CliServer(Cli):
        def handle_repo_create(self):
                path = self.args.path[0]
 
-               p = self.pakfire(**self.pakfire_args)
+               p = self.create_pakfire()
                p.repo_create(path, self.args.inputs, key_id=self.args.key)
 
        def handle_info(self):
@@ -797,12 +880,14 @@ class CliBuilderIntern(Cli):
 
 
 class CliClient(Cli):
+       pakfire = base.PakfireClient
+
        def __init__(self):
                self.parser = argparse.ArgumentParser(
                        description = _("Pakfire client command line interface."),
                )
 
-               self.parse_common_arguments(repo_manage_switches=True, offline_switch=True)
+               self.parse_common_arguments(offline_switch=True)
 
                # Add sub-commands.
                self.sub_commands = self.parser.add_subparsers()
@@ -828,15 +913,17 @@ class CliClient(Cli):
                        "test"        : self.handle_test,
                }
 
-               # Read configuration for the pakfire client.
-               self.conf = conf = config.ConfigClient()
+               # Read configuration.
+               self.config = config.ConfigClient()
 
                # Create connection to pakfire hub.
-               self.client = client.PakfireUserClient(
-                       conf.get("client", "server"),
-                       conf.get("client", "username"),
-                       conf.get("client", "password"),
-               )
+               self.client = client.PakfireClient(self.config)
+
+       @property
+       def pakfire_args(self):
+               return {
+                       "config" : self.config,
+               }
 
        def parse_command_build(self):
                # Parse "build" command.
@@ -932,21 +1019,23 @@ class CliClient(Cli):
 
                        # Format arches.
                        if self.args.arch:
-                               arches = self.args.arch.replace(",", " ")
+                               arches = self.args.arch.split(",")
                        else:
                                arches = None
 
                        # Create a new build on the server.
-                       build = self.client.build_create(package, arches=arches)
-
-                       # XXX Print the resulting build.
-                       print build
+                       build_id = self.client.build_create(package, build_type="scratch",
+                               arches=arches)
 
                finally:
                        # Cleanup the temporary directory and all files.
                        if os.path.exists(temp_dir):
                                shutil.rmtree(temp_dir, ignore_errors=True)
 
+               # Monitor the build.
+               if build_id:
+                       self.watch_build(build_id)
+
        def handle_info(self):
                ret = []
 
@@ -954,10 +1043,10 @@ class CliClient(Cli):
                ret.append("  PAKFIRE %s" % PAKFIRE_VERSION)
                ret.append("")
                ret.append("  %-20s: %s" % (_("Hostname"), system.hostname))
-               ret.append("  %-20s: %s" % (_("Pakfire hub"), self.conf.get("client", "server")))
-               if self.conf.get("client", "username") and self.conf.get("client", "password"):
+               ret.append("  %-20s: %s" % (_("Pakfire hub"), self.config.get("client", "server")))
+               if self.config.get("client", "username") and self.config.get("client", "password"):
                        ret.append("  %-20s: %s" % \
-                               (_("Username"), self.conf.get("client", "username")))
+                               (_("Username"), self.config.get("client", "username")))
                ret.append("")
 
                # Hardware information
@@ -1126,6 +1215,11 @@ class CliClient(Cli):
                res = self.client.test_code(error_code)
                print _("Reponse from the server: %s") % res
 
+       def watch_build(self, build_id):
+               print self.client.build_get(build_id)
+               # XXX TODO
+               print build_id
+
 
 class CliDaemon(Cli):
        def __init__(self):
@@ -1133,7 +1227,7 @@ class CliDaemon(Cli):
                        description = _("Pakfire daemon command line interface."),
                )
 
-               self.parse_common_arguments(repo_manage_switches=True, offline_switch=True)
+               self.parse_common_arguments(offline_switch=True)
 
                # Finally parse all arguments from the command line and save them.
                self.args = self.parser.parse_args()
@@ -1143,10 +1237,11 @@ class CliDaemon(Cli):
                        Runs the pakfire daemon with provided settings.
                """
                # Read the configuration file for the daemon.
-               conf = config.ConfigDaemon()
+               self.config = config.ConfigDaemon()
+               logger.setup_logging(self.config)
 
                # Create daemon instance.
-               d = pakfire.client.PakfireDaemon()
+               d = daemon.PakfireDaemon(self.config)
                try:
                        d.run()
 
@@ -1156,13 +1251,14 @@ class CliDaemon(Cli):
 
 
 class CliKey(Cli):
+       pakfire = base.PakfireKey
+
        def __init__(self):
                self.parser = argparse.ArgumentParser(
                        description = _("Pakfire key command line interface."),
                )
 
-               self.parse_common_arguments(repo_manage_switches=False,
-                       offline_switch=True)
+               self.parse_common_arguments(offline_switch=True)
 
                # Add sub-commands.
                self.sub_commands = self.parser.add_subparsers()
@@ -1218,8 +1314,6 @@ class CliKey(Cli):
                        help=_("The ID of the key to export."))
                sub_export.add_argument("filename", nargs=1,
                        help=_("Write the key to this file."))
-               sub_export.add_argument("--secret", action="store_true",
-                       help=_("Export the secret key, too."))
                sub_export.add_argument("action", action="store_const", const="export")
 
        def parse_command_delete(self):
@@ -1264,33 +1358,32 @@ class CliKey(Cli):
                print
 
                # Generate the key.
-               p = self.pakfire(**self.pakfire_args)
-               p.key_generate(realname, email)
+               p = self.create_pakfire()
+               p.keyring.gen_key(realname, email)
 
        def handle_import(self):
                filename = self.args.filename[0]
 
                # Simply import the file.
-               p = self.pakfire(**self.pakfire_args)
-               p.key_import(filename)
+               p = self.create_pakfire()
+               p.keyring.import_key(filename)
 
        def handle_export(self):
                keyid    = self.args.keyid[0]
                filename = self.args.filename[0]
-               secret   = self.args.secret
 
-               p = self.pakfire(**self.pakfire_args)
-               p.key_export(keyid, filename, secret=secret)
+               p = self.create_pakfire()
+               p.keyring.export_key(keyid, filename)
 
        def handle_delete(self):
                keyid = self.args.keyid[0]
 
-               p = self.pakfire(**self.pakfire_args)
-               p.key_delete(keyid)
+               p = self.create_pakfire()
+               p.keyring.delete_key(keyid)
 
        def handle_list(self):
-               p = self.pakfire(**self.pakfire_args)
-               for line in p.key_list():
+               p = self.create_pakfire()
+               for line in p.keyring.list_keys():
                        print line
 
        def handle_sign(self):
@@ -1309,7 +1402,7 @@ class CliKey(Cli):
                key = self.args.key[0]
 
                # Create pakfire instance.
-               p = self.pakfire(**self.pakfire_args)
+               p = self.create_pakfire()
 
                for file in files:
                        # Open the package.
@@ -1329,7 +1422,7 @@ class CliKey(Cli):
                                files.append(file)
 
                # Create pakfire instance.
-               p = self.pakfire(**self.pakfire_args)
+               p = self.create_pakfire()
 
                for file in files:
                        # Open the package.
@@ -1339,7 +1432,7 @@ class CliKey(Cli):
                        sigs = pkg.verify()
 
                        for sig in sigs:
-                               key = self.pakfire.keyring.get_key(sig.fpr)
+                               key = p.keyring.get_key(sig.fpr)
                                if key:
                                        subkey = key.subkeys[0]