]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
Initial commit of the pakfire server stuff.
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 6 Apr 2011 11:22:23 +0000 (13:22 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 6 Apr 2011 11:22:23 +0000 (13:22 +0200)
17 files changed:
examples/pakfire.conf
pakfire/__init__.py
pakfire/builder.py
pakfire/cli.py
pakfire/config.py
pakfire/packages/__init__.py
pakfire/packages/base.py
pakfire/packages/packager.py
pakfire/repository/__init__.py
pakfire/repository/index.py
pakfire/repository/local.py
pakfire/server/__init__.py [new file with mode: 0644]
pakfire/server/master.py [new file with mode: 0644]
pakfire/server/slave.py [new file with mode: 0644]
pakfire/util.py
po/pakfire.pot
setup.py

index 90d80f1a252fbb84595c0e82063e0f8a35edeb7f..2c328c30735f92e229df8e2d51b1f1d71d68a559 100644 (file)
@@ -12,3 +12,13 @@ slogan = Gluttony
 
 vendor = ipfire
 arch = i686
+
+
+[master]
+server = http://172.28.1.250/api/master
+
+resultdir = /packages
+
+
+[slave]
+server = http://172.28.1.250/api/slave
index ccca46159947cf8c2d00240f0facd06928f8c96d..ecc6df035300424102dc71c57956725a6a57d67b 100644 (file)
@@ -146,7 +146,7 @@ class Pakfire(object):
                finally:
                        b.destroy()
 
-       def dist(self, pkgs, resultdirs=None):
+       def dist(self, pkgs, resultdirs=None, destroy=True):
                self.check_build_mode()
 
                # Select first package out of pkgs.
@@ -186,7 +186,8 @@ class Pakfire(object):
                                # Cleanup all the stuff from pkg.
                                b.cleanup()
                finally:
-                       b.destroy()
+                       if destroy:
+                               b.destroy()
 
        def install(self, requires):
                ds = depsolve.DependencySet(pakfire=self)
@@ -251,7 +252,7 @@ class Pakfire(object):
                return pkgs
 
        def repo_create(self, path, input_paths):
-               repo = repository.LocalRepository(
+               repo = repository.LocalBinaryRepository(
                        self,
                        name="new",
                        description="New repository.",
index eb6b363e56fc077ddfa7b13fdb16773cbfdc04c7..bdac3e88b5eba50d8edff9e33c019af278354e0f 100644 (file)
@@ -238,6 +238,11 @@ class Builder(object):
                return ret
 
        def prepare(self):
+               prepared_tag = ".prepared"
+
+               if os.path.exists(self.chrootPath(prepared_tag)):
+                       return
+
                # Create directory.
                if not os.path.exists(self.path):
                        os.makedirs(self.path)
@@ -272,7 +277,8 @@ class Builder(object):
                # Create neccessary files like /etc/fstab and /etc/mtab.
                files = (
                        "etc/fstab",
-                       "etc/mtab"
+                       "etc/mtab",
+                       prepared_tag,
                )
 
                for file in files:
index 7777edab9dd80840c3a89dcc4c3806922e4ce5ed..18996c6e0f831b5945f4ed414dd23c0742292492 100644 (file)
@@ -5,6 +5,7 @@ import sys
 
 import packages
 import repository
+import server
 import util
 
 from pakfire import Pakfire
@@ -379,9 +380,78 @@ class CliRepo(Cli):
 
 
 class CliMaster(Cli):
-       pass
+       def __init__(self):
+               self.parser = argparse.ArgumentParser(
+                       description = _("Pakfire master command line interface."),
+               )
+
+               self.parse_common_arguments()
+
+               # Add sub-commands.
+               self.sub_commands = self.parser.add_subparsers()
+
+               self.parse_command_update()
+
+               # Finally parse all arguments from the command line and save them.
+               self.args = self.parser.parse_args()
+
+               self.pakfire = Pakfire(
+                       builder = True,
+                       configs = [self.args.config],
+                       disable_repos = self.args.disable_repo,
+               )
+
+               self.master = server.master.Master(self.pakfire)
+
+               self.action2func = {
+                       "update"      : self.handle_update,
+               }
+
+       def parse_command_update(self):
+               # Implement the "update" command.
+               sub_update = self.sub_commands.add_parser("update",
+                       help=_("Update the sources."))
+               sub_update.add_argument("action", action="store_const", const="update")
+
+       def handle_update(self):
+               self.master.update_sources()
 
 
 class CliSlave(Cli):
-       pass
+       def __init__(self):
+               self.parser = argparse.ArgumentParser(
+                       description = _("Pakfire slave command line interface."),
+               )
+
+               self.parse_common_arguments()
+
+               # Add sub-commands.
+               self.sub_commands = self.parser.add_subparsers()
+
+               self.parse_command_keepalive()
+
+               # Finally parse all arguments from the command line and save them.
+               self.args = self.parser.parse_args()
+
+               self.pakfire = Pakfire(
+                       builder = True,
+                       configs = [self.args.config],
+                       disable_repos = self.args.disable_repo,
+               )
+
+               self.slave = server.slave.Slave(self.pakfire)
+
+               self.action2func = {
+                       "keepalive" : self.handle_keepalive,
+               }
+
+       def parse_command_keepalive(self):
+               # Implement the "keepalive" command.
+               sub_keepalive = self.sub_commands.add_parser("keepalive",
+                       help=_("Send a keepalive to the server."))
+               sub_keepalive.add_argument("action", action="store_const",
+                       const="keepalive")
+
+       def handle_keepalive(self):
+               self.slave.keepalive()
 
index 2a730cf8f48e4f3ee24c6515e8eb53d943bc0109..2bb126d598c4aa5b7078dd10255c66d7c4392f42 100644 (file)
@@ -22,6 +22,8 @@ class Config(object):
 
                self._config_repos = {}
                self._distro = {}
+               self._master = {}
+               self._slave = {}
                self._files = []
 
                # Read default configuration files
@@ -65,6 +67,18 @@ class Config(object):
                                self._distro[k] = v
                        config.remove_section("distro")
 
+               # Read master settings from file
+               if "master" in config.sections():
+                       for k,v in config.items("master"):
+                               self._master[k] = v
+                       config.remove_section("master")
+
+               # Read slave settings from file
+               if "slave" in config.sections():
+                       for k,v in config.items("slave"):
+                               self._slave[k] = v
+                       config.remove_section("slave")
+
                # Read repository definitions
                for section in config.sections():
                        if not self._config_repos.has_key(section):
index 0983ed47a9ec8239ce1973e15d6fb90789163735..a8717dcc3a7596940790c0f5ad2ba1c50a04a832 100644 (file)
@@ -9,3 +9,18 @@ from virtual import VirtualPackage
 from listing import PackageListing
 from make import Makefile
 from packager import BinaryPackager
+
+from pakfire.constants import *
+
+def open(pakfire, repo, filename):
+       """
+               Function to open all packages and return the right object.
+
+               Abstractly, this detects if a package is a source package or
+               not.
+       """
+       # XXX We should make this check much better...
+       if filename.endswith(".src.%s" % PACKAGE_EXTENSION):
+               return SourcePackage(pakfire, repo, filename)
+
+       return BinaryPackage(pakfire, repo, filename)
index 8f926c1a0c7d8a38faac6498936a62d4d9281324..baea8ed97601ea1965356fefb5dc50a873f58a3d 100644 (file)
@@ -281,6 +281,10 @@ class Package(object):
        def uuid(self):
                return self.metadata.get("PKG_UUID", None)
 
+       @property
+       def supported_arches(self):
+               return self.metadata.get("PKG_SUPPORTED_ARCHES", "all")
+
        @property
        def _provides(self):
                # Make package identifyable by its name and version/release tuples.
index a3b1a957771bd4b9d0cc3e419040368cb75c8edb..83342c5e7d3e295f4b69509efead14c4aa031a6f 100644 (file)
@@ -15,6 +15,7 @@ import xattr
 import zlib
 
 import pakfire.compress
+from pakfire.util import rm
 import util
 
 from pakfire.constants import *
@@ -104,6 +105,8 @@ class Packager(object):
 
                tar.close()
 
+               rm(self.tempdir)
+
        def create_tarball(self, compress=None):
                tar = InnerTarFile(self.archive_files["data.img"], mode="w")
 
index a3d689948e307d1124cc5c66cc645ca22e9cac6b..12e3dc1bd35a35c28d5a58d37bf63fc842631dfd 100644 (file)
@@ -3,7 +3,7 @@
 import logging
 
 from installed import InstalledRepository
-from local import LocalRepository, LocalBuildRepository
+from local import LocalRepository, LocalBuildRepository, LocalSourceRepository
 from oddments import DummyRepository, FileSystemRepository
 from remote import RemoteRepository
 
index f18c97d950b88beea1e5c6b2c27cc24a5edce1e8..2b2991eae3e33e99ecf24b5414b3c276492142d3 100644 (file)
@@ -101,17 +101,22 @@ class DirectoryIndex(Index):
 
                                file = os.path.join(dir, file)
 
-                               package = packages.BinaryPackage(self.pakfire, self.repo, file)
-
-                               if package.type == "source":
-                                       # Silently skip source packages.
-                                       continue
-
-                               if not package.arch in (self.arch, "noarch"):
-                                       logging.warning("Skipped package with wrong architecture: %s (%s)" \
-                                               % (package.filename, package.arch))
-                                       print package.type
-                                       continue
+                               package = packages.open(self.pakfire, self.repo, file)
+
+                               logging.debug("Found package: %s" % package)
+
+                               if isinstance(package, packages.BinaryPackage):
+                                       if not package.arch in (self.arch, "noarch"):
+                                               logging.warning("Skipped package with wrong architecture: %s (%s)" \
+                                                       % (package.filename, package.arch))
+                                               print package.type
+                                               continue
+
+                               # XXX this is disabled because we could also have source
+                               # repositories. But we should not mix them.     
+                               #if package.type == "source":
+                               #       # Silently skip source packages.
+                               #       continue
 
                                self._packages.append(package)
 
index 588e65b52ce666f0ffe9078fe47f77c7ab15d9d1..5917dcad9ba67a799d64bed466292cd22a80f595 100644 (file)
@@ -13,7 +13,7 @@ from base import RepositoryFactory
 from pakfire.constants import *
 
 class LocalRepository(RepositoryFactory):
-       def __init__(self, pakfire, name, description, path):
+       def __init__(self, pakfire, name, description, path, idx="db"):
                RepositoryFactory.__init__(self, pakfire, name, description)
 
                # Save location of the repository and create it if not existant.
@@ -21,7 +21,11 @@ class LocalRepository(RepositoryFactory):
                if not os.path.exists(self.path):
                        os.makedirs(self.path)
 
-               self.index = index.LocalIndex(self.pakfire, self)
+               if idx == "db":
+                       self.index = index.LocalIndex(self.pakfire, self)
+
+               elif idx == "directory":
+                       self.index = index.DirectoryIndex(self.pakfire, self, self.path)
 
        @property
        def local(self):
@@ -45,7 +49,7 @@ class LocalRepository(RepositoryFactory):
 
                                file = os.path.join(dir, file)
 
-                               pkg = packages.BinaryPackage(self.pakfire, self, file)
+                               pkg = packages.open(self.pakfire, self, file)
                                self._add_package(pkg)
 
        def _add_package(self, pkg):
@@ -63,7 +67,7 @@ class LocalRepository(RepositoryFactory):
 
                pkg_exists = None
                if os.path.exists(repo_filename):
-                       pkg_exists = packages.BinaryPackage(self.pakfire, self, repo_filename)
+                       pkg_exists = packages.open(self.pakfire, self, repo_filename)
 
                        # If package in the repo is equivalent to the given one, we can
                        # skip any further processing.
@@ -92,7 +96,7 @@ class LocalRepository(RepositoryFactory):
 
                # Create new package object, that is connected to this repository
                # and so we can do stuff.
-               pkg = packages.BinaryPackage(self.pakfire, self, repo_filename)
+               pkg = packages.open(self.pakfire, self, repo_filename)
 
                logging.info("Adding package '%s' to repository." % pkg.friendly_name)
                self.index.add_package(pkg)
@@ -104,7 +108,28 @@ class LocalRepository(RepositoryFactory):
                self.index.save(path)
 
 
-class LocalBuildRepository(LocalRepository):
+class LocalBinaryRepository(LocalRepository):
+       @property
+       def packages(self):
+               for pkg in self.index.packages:
+                       # XXX should be changed to "binary" if all packages do support this.
+                       if pkg.type == "source":
+                               continue
+
+                       yield pkg
+
+
+class LocalSourceRepository(LocalRepository):
+       @property
+       def packages(self):
+               for pkg in self.index.packages:
+                       if not pkg.type == "source":
+                               continue
+
+                       yield pkg
+
+
+class LocalBuildRepository(LocalBinaryRepository):
        def __init__(self, pakfire):
                RepositoryFactory.__init__(self, pakfire, "build", "Locally built packages")
 
diff --git a/pakfire/server/__init__.py b/pakfire/server/__init__.py
new file mode 100644 (file)
index 0000000..cab1fd1
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/python
+
+import master
+import slave
+
diff --git a/pakfire/server/master.py b/pakfire/server/master.py
new file mode 100644 (file)
index 0000000..7481a27
--- /dev/null
@@ -0,0 +1,221 @@
+#!/usr/bin/python
+
+import logging
+import os
+import random
+import shutil
+import subprocess
+import xmlrpclib
+
+import pakfire.packages as packages
+import pakfire.repository as repository
+import pakfire.util as util
+from pakfire.constants import *
+
+class Source(object):
+       def __init__(self, master, id, name, path, targetpath, revision, branch):
+               self.master = master
+               self.id = id
+               self.name = name
+               self.path = path
+               self.targetpath = targetpath
+               self.revision = revision
+               self.branch = branch
+
+       @property
+       def pakfire(self):
+               return self.master.pakfire
+
+       def _git(self, cmd):
+               cmd = "cd %s; git %s" % (self.path, cmd)
+
+               logging.debug("Running command: %s" % cmd)
+
+               return subprocess.check_output(["/bin/sh", "-c", cmd])
+
+       def _git_rev_list(self, revision=None):
+               if not revision:
+                       revision = self.revision
+
+               revs = self._git("rev-list %s..origin/%s --no-merges" % (revision, self.branch))
+
+               return reversed(revs.splitlines())
+
+       def _git_changed_files(self, revision1, revision2=""):
+               files = self._git("diff --name-only %s %s" % (revision1, revision2))
+
+               return [os.path.join(self.path, f) for f in files.splitlines()]
+
+       def _git_checkout_revision(self, revision):
+               self._git("checkout %s" % revision)
+
+       def update_revision(self, revision):
+               self._git_checkout_revision(revision)
+
+               # Get list of all changes files between the current revision and
+               # the previous one.
+               files = self._git_changed_files("HEAD^", "HEAD")
+
+               self.update_files([f for f in files if f.endswith(".%s" % MAKEFILE_EXTENSION)])
+
+               # Send update to the server.
+               self.master.update_revision(self, revision)             
+
+       def update_files(self, files):
+               rnd = random.randint(0, 1024**2)
+               tmpdir = "/tmp/pakfire-source-%s" % rnd
+
+               pkgs = []
+               for file in files:
+                       if os.path.exists(file):
+                               pkgs.append(packages.Makefile(self.pakfire, file))
+                       else:
+                               pkg_name = os.path.basename(os.path.dirname(file))
+
+                               # Send deleted package to server.
+                               self.master.package_remove(self, pkg_name)
+
+               if not pkgs:
+                       return
+
+               # XXX This totally ignores the local configuration.
+               self.pakfire.dist(pkgs, destroy=False, resultdirs=[tmpdir,])
+
+               # Create a kind of dummy repository to link the packages against it.
+               repo = repository.LocalSourceRepository(self.pakfire,
+                       "source-%s" % rnd, "Source packages", tmpdir, idx="directory")
+               repo.update(force=True)
+
+               for pkg in repo.get_all():
+                       logging.debug("Processing package: %s" % pkg)
+
+                       pkg_path = "%(name)s/%(epoch)s-%(version)s-%(release)s/%(arch)s" % pkg.info
+
+                       file = os.path.join(self.targetpath, pkg_path, os.path.basename(pkg.filename))
+                       dir  = os.path.dirname(file)
+
+                       print file
+
+                       if os.path.exists(file):
+                               logging.warning("Package does already exist: %s" % file)
+
+                       else:
+                               if not os.path.exists(dir):
+                                       os.makedirs(dir)
+
+                               # Copy the source file to the designated data pool.
+                               shutil.copy2(pkg.filename, file)
+
+                       # Register package in database and get an ID.
+                       pkg_id = self.master.package_add(self, pkg)
+
+                       # Re-read the package metadata (mainly update filenames).
+                       pkg = packages.SourcePackage(self.pakfire, repo, file)
+
+                       self.master.package_file_add(self, pkg_id, pkg)
+
+               util.rm(tmpdir)
+
+       def update(self):
+               # Update files from server.
+               self._git("fetch")
+
+               # If there has been no data, yet we need to import all packages
+               # that are currently checked out.
+               if not self.revision:
+                       self.update_all()
+
+               for rev in self._git_rev_list():
+                       self.update_revision(rev)
+
+       def update_all(self):
+               _files = []
+               for dir, subdirs, files in os.walk(self.path):
+                       for f in files:
+                               if not f.endswith(".%s" % MAKEFILE_EXTENSION):
+                                       continue
+
+                               _files.append(os.path.join(dir, f))
+
+               self.update_files(_files)
+
+
+class Master(object):
+       def __init__(self, pakfire):
+               self.pakfire = pakfire
+
+               server = self.pakfire.config._master.get("server")
+
+               logging.info("Establishing RPC connection to: %s" % server)
+
+               self.conn = xmlrpclib.Server(server)
+
+       def update_sources(self):
+               sources = self.conn.sources_get_all()
+
+               for source in sources:
+                       source = Source(self, **source)
+
+                       source.update()
+
+       def update_revision(self, source, revision):
+               self.conn.sources_update_revision(source.id, revision)
+
+       def package_add(self, source, pkg):
+               logging.info("Adding package: %s" % pkg.friendly_name)
+
+               # Collect data that is sent to the database...
+               info = {
+                       "name"             : pkg.name,
+                       "epoch"            : pkg.epoch,
+                       "version"          : pkg.version,
+                       "release"          : pkg.release,
+                       "groups"           : " ".join(pkg.groups),
+                       "maintainer"       : pkg.maintainer,
+                       "license"          : pkg.license,
+                       "url"              : pkg.url,
+                       "summary"          : pkg.summary,
+                       "description"      : pkg.description,
+                       "supported_arches" : pkg.supported_arches,
+                       "source_id"        : source.id,
+               }
+
+               return self.conn.package_add(info)
+
+       def package_file_add(self, source, pkg_id, pkg):
+               logging.info("Adding package file: %s" % pkg.filename)
+
+               info = {
+                       "path"        : pkg.filename[len(source.path) + 1:],
+                       "source_id"   : source.id,
+                       "type"        : pkg.type,
+                       "arch"        : pkg.arch,
+                       "summary"     : pkg.summary,
+                       "description" : pkg.description,
+                       "requires"    : " ".join(pkg.requires),
+                       "provides"    : "",
+                       "obsoletes"   : "",
+                       "conflicts"   : "",
+                       "url"         : pkg.url,
+                       "license"     : pkg.license,
+                       "maintainer"  : pkg.maintainer,
+                       "size"        : pkg.size,
+                       "hash1"       : pkg.hash1,
+                       "build_host"  : pkg.build_host,
+                       "build_id"    : pkg.build_id,
+                       "build_time"  : pkg.build_time,
+                       "uuid"        : pkg.uuid,
+               }
+
+               if isinstance(pkg, packages.BinaryPackage):
+                       info.update({
+                               "provides"    : " ".join(pkg.provides),
+                               "obsoletes"   : " ".join(pkg.obsoletes),
+                               "conflicts"   : " ".join(pkg.conflicts),
+                       })
+
+               return self.conn.package_file_add(pkg_id, info)
+
+       def package_remove(self, source, pkg):
+               logging.info("Package '%s' has been removed." % pkg)
+
diff --git a/pakfire/server/slave.py b/pakfire/server/slave.py
new file mode 100644 (file)
index 0000000..5692f3b
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+
+import logging
+import os
+import socket
+import xmlrpclib
+
+class Slave(object):
+       def __init__(self, pakfire):
+               self.pakfire = pakfire
+
+               server = self.pakfire.config._slave.get("server")
+
+               logging.info("Establishing RPC connection to: %s" % server)
+
+               self.conn = xmlrpclib.Server(server)
+
+       def keepalive(self):
+               """
+                       Send the server a keep-alive to say that we are still there.
+               """
+               hostname = socket.gethostname()
+               l1, l5, l15 = os.getloadavg()
+
+               logging.info("Sending the server a keepalive: %s" % hostname)
+
+               self.conn.keepalive(hostname, l5)
+
index ced8ca01d76eaf2a3c590bc4367593471d0e4704..a4be7dfef43542798d73c2c243c834dbb1227fa7 100644 (file)
@@ -102,7 +102,7 @@ def do(command, shell=False, chrootPath=None, cwd=None, timeout=0, raiseExc=True
        preexec = ChildPreExec(personality, chrootPath, cwd)
 
        if logger:
-               logger.debug("Executing command: %s" % command)
+               logger.debug("Executing command: %s in %s" % (command, chrootPath or "/"))
 
        try:
                child = None
index aca1645a5e88cc27ee25d034fb5f6a0f07c26135..0e163d2b8c0095ebe170f6b4d1c43c579bb56034 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-03-10 15:19+0100\n"
+"POT-Creation-Date: 2011-04-04 13:33+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,152 +17,168 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: ../pakfire/cli.py:27
+#: ../pakfire/cli.py:28
 #, python-format
 msgid "%s [y/N]"
 msgstr ""
 
-#: ../pakfire/cli.py:36
+#: ../pakfire/cli.py:37
 msgid "Pakfire command line interface."
 msgstr ""
 
-#: ../pakfire/cli.py:43
+#: ../pakfire/cli.py:44
 msgid "The path where pakfire should operate in."
 msgstr ""
 
-#: ../pakfire/cli.py:76
+#: ../pakfire/cli.py:77
 msgid "Enable verbose output."
 msgstr ""
 
-#: ../pakfire/cli.py:79
+#: ../pakfire/cli.py:80
 msgid "Path to a configuration file to load."
 msgstr ""
 
-#: ../pakfire/cli.py:82
+#: ../pakfire/cli.py:83
 msgid "Disable a repository temporarily."
 msgstr ""
 
-#: ../pakfire/cli.py:87
+#: ../pakfire/cli.py:88
 msgid "Install one or more packages to the system."
 msgstr ""
 
-#: ../pakfire/cli.py:89
+#: ../pakfire/cli.py:90
 msgid "Give name of at least one package to install."
 msgstr ""
 
-#: ../pakfire/cli.py:95
+#: ../pakfire/cli.py:96
 msgid "Install one or more packages from the filesystem."
 msgstr ""
 
-#: ../pakfire/cli.py:97
+#: ../pakfire/cli.py:98
 msgid "Give filename of at least one package."
 msgstr ""
 
-#: ../pakfire/cli.py:103
+#: ../pakfire/cli.py:104
 msgid "Update the whole system or one specific package."
 msgstr ""
 
-#: ../pakfire/cli.py:105
+#: ../pakfire/cli.py:106
 msgid "Give a name of a package to update or leave emtpy for all."
 msgstr ""
 
-#: ../pakfire/cli.py:111
+#: ../pakfire/cli.py:112
 msgid "Print some information about the given package(s)."
 msgstr ""
 
-#: ../pakfire/cli.py:113
+#: ../pakfire/cli.py:114
 msgid "Give at least the name of one package."
 msgstr ""
 
-#: ../pakfire/cli.py:119
+#: ../pakfire/cli.py:120
 msgid "Search for a given pattern."
 msgstr ""
 
-#: ../pakfire/cli.py:121
+#: ../pakfire/cli.py:122
 msgid "A pattern to search for."
 msgstr ""
 
-#: ../pakfire/cli.py:127
+#: ../pakfire/cli.py:128
 msgid "Get a list of packages that provide a given file or feature."
 msgstr ""
 
-#: ../pakfire/cli.py:129
+#: ../pakfire/cli.py:130
 msgid "File or feature to search for."
 msgstr ""
 
-#: ../pakfire/cli.py:191
+#: ../pakfire/cli.py:192
 msgid "Pakfire builder command line interface."
 msgstr ""
 
-#: ../pakfire/cli.py:229
+#: ../pakfire/cli.py:230
 msgid "Update the package indexes."
 msgstr ""
 
-#: ../pakfire/cli.py:235
+#: ../pakfire/cli.py:236
 msgid "Build one or more packages."
 msgstr ""
 
-#: ../pakfire/cli.py:237
+#: ../pakfire/cli.py:238
 msgid "Give name of at least one package to build."
 msgstr ""
 
-#: ../pakfire/cli.py:241
+#: ../pakfire/cli.py:242
 msgid "Build the package for the given architecture."
 msgstr ""
 
-#: ../pakfire/cli.py:243 ../pakfire/cli.py:265
+#: ../pakfire/cli.py:244 ../pakfire/cli.py:266
 msgid "Path were the output files should be copied to."
 msgstr ""
 
-#: ../pakfire/cli.py:248
+#: ../pakfire/cli.py:249
 msgid "Go into a shell."
 msgstr ""
 
-#: ../pakfire/cli.py:250
+#: ../pakfire/cli.py:251
 msgid "Give name of a package."
 msgstr ""
 
-#: ../pakfire/cli.py:254
+#: ../pakfire/cli.py:255
 msgid "Emulated architecture in the shell."
 msgstr ""
 
-#: ../pakfire/cli.py:259
+#: ../pakfire/cli.py:260
 msgid "Generate a source package."
 msgstr ""
 
-#: ../pakfire/cli.py:261
+#: ../pakfire/cli.py:262
 msgid "Give name(s) of a package(s)."
 msgstr ""
 
-#: ../pakfire/cli.py:336
-msgid "Pakfire server command line interface."
+#: ../pakfire/cli.py:338
+msgid "Pakfire repo command line interface."
 msgstr ""
 
-#: ../pakfire/cli.py:361
+#: ../pakfire/cli.py:363
 msgid "Repository management commands."
 msgstr ""
 
-#: ../pakfire/cli.py:369
+#: ../pakfire/cli.py:371
 msgid "Create a new repository index."
 msgstr ""
 
-#: ../pakfire/cli.py:370
+#: ../pakfire/cli.py:372
 msgid "Path to the packages."
 msgstr ""
 
-#: ../pakfire/cli.py:371
+#: ../pakfire/cli.py:373
 msgid "Path to input packages."
 msgstr ""
 
+#: ../pakfire/cli.py:385
+msgid "Pakfire master command line interface."
+msgstr ""
+
+#: ../pakfire/cli.py:413
+msgid "Update the sources."
+msgstr ""
+
+#: ../pakfire/cli.py:423
+msgid "Pakfire slave command line interface."
+msgstr ""
+
+#: ../pakfire/cli.py:451
+msgid "Send a keepalive to the server."
+msgstr ""
+
 #: ../pakfire/depsolve.py:220
 msgid "Package"
 msgstr ""
 
-#: ../pakfire/depsolve.py:220 ../pakfire/packages/base.py:72
+#: ../pakfire/depsolve.py:220 ../pakfire/packages/base.py:66
 msgid "Arch"
 msgstr ""
 
-#: ../pakfire/depsolve.py:220 ../pakfire/packages/base.py:73
+#: ../pakfire/depsolve.py:220 ../pakfire/packages/base.py:67
 msgid "Version"
 msgstr ""
 
@@ -170,7 +186,7 @@ msgstr ""
 msgid "Repository"
 msgstr ""
 
-#: ../pakfire/depsolve.py:220 ../pakfire/packages/base.py:75
+#: ../pakfire/depsolve.py:220 ../pakfire/packages/base.py:69
 msgid "Size"
 msgstr ""
 
@@ -224,83 +240,87 @@ msgstr ""
 msgid "Total download size: %s"
 msgstr ""
 
-#: ../pakfire/__init__.py:202 ../pakfire/__init__.py:233
+#: ../pakfire/__init__.py:204 ../pakfire/__init__.py:235
 msgid "Is this okay?"
 msgstr ""
 
-#: ../pakfire/packages/base.py:71
+#: ../pakfire/packages/base.py:65
 msgid "Name"
 msgstr ""
 
-#: ../pakfire/packages/base.py:74
+#: ../pakfire/packages/base.py:68
 msgid "Release"
 msgstr ""
 
-#: ../pakfire/packages/base.py:76
+#: ../pakfire/packages/base.py:70
 msgid "Repo"
 msgstr ""
 
-#: ../pakfire/packages/base.py:77
+#: ../pakfire/packages/base.py:71
 msgid "Summary"
 msgstr ""
 
-#: ../pakfire/packages/base.py:78
+#: ../pakfire/packages/base.py:72
+msgid "Groups"
+msgstr ""
+
+#: ../pakfire/packages/base.py:73
 msgid "URL"
 msgstr ""
 
-#: ../pakfire/packages/base.py:79
+#: ../pakfire/packages/base.py:74
 msgid "License"
 msgstr ""
 
-#: ../pakfire/packages/base.py:82
+#: ../pakfire/packages/base.py:77
 msgid "Description"
 msgstr ""
 
-#: ../pakfire/packages/base.py:88
+#: ../pakfire/packages/base.py:83
 msgid "UUID"
 msgstr ""
 
-#: ../pakfire/packages/base.py:89
+#: ../pakfire/packages/base.py:84
 msgid "Build ID"
 msgstr ""
 
-#: ../pakfire/packages/base.py:90
+#: ../pakfire/packages/base.py:85
 msgid "Build date"
 msgstr ""
 
-#: ../pakfire/packages/base.py:91
+#: ../pakfire/packages/base.py:86
 msgid "Build host"
 msgstr ""
 
-#: ../pakfire/packages/base.py:93
+#: ../pakfire/packages/base.py:88
 msgid "Provides"
 msgstr ""
 
-#: ../pakfire/packages/base.py:98
+#: ../pakfire/packages/base.py:93
 msgid "Requires"
 msgstr ""
 
-#: ../pakfire/repository/index.py:300
+#: ../pakfire/repository/index.py:310
 #, python-format
 msgid "%s: package database"
 msgstr ""
 
-#: ../pakfire/transaction.py:130
+#: ../pakfire/transaction.py:133
 #, python-format
 msgid "Cleanup: %s"
 msgstr ""
 
-#: ../pakfire/transaction.py:244
+#: ../pakfire/transaction.py:247
 #, python-format
 msgid "Installing: %s"
 msgstr ""
 
-#: ../pakfire/transaction.py:249
+#: ../pakfire/transaction.py:252
 #, python-format
 msgid "Updating: %s"
 msgstr ""
 
-#: ../pakfire/transaction.py:259
+#: ../pakfire/transaction.py:262
 #, python-format
 msgid "Removing: %s"
 msgstr ""
index 8338427efad7c2530c783d01186c92a2ffd8258f..808a65d631f9acf8aee3577bf9d4e3414b647fd9 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,13 @@ setup(
        author = "IPFire.org Team",
        author_email = "info@ipfire.org",
        url = "http://redmine.ipfire.org/projects/buildsystem3",
-       packages = ["pakfire", "pakfire.packages", "pakfire.plugins", "pakfire.repository",],
+       packages = [
+               "pakfire",
+               "pakfire.packages",
+               "pakfire.plugins",
+               "pakfire.server",
+               "pakfire.repository",
+       ],
        scripts = [
                "scripts/pakfire",
                "scripts/pakfire-build",