diff --git a/britney.py b/britney.py index bfa1e55..a9dceb1 100644 --- a/britney.py +++ b/britney.py @@ -187,7 +187,7 @@ import operator import apt_pkg from excuse import Excuse -from britney import buildSystem, addBinary, removeBinary +from britney import buildSystem __author__ = 'Fabio Tranchitella' __version__ = '2.0.alpha1' @@ -1556,17 +1556,6 @@ class Britney: binaries = self.binaries['testing'] systems = self.systems - # when a new uninstallable package is discovered, check again all the - # reverse dependencies and if they are uninstallable, too, call itself - # recursively - def add_nuninst(pkg, arch): - if pkg not in nuninst[arch]: - nuninst[arch].append(pkg) - for p in binaries[arch][0][pkg][RDEPENDS]: - r = systems[arch].is_installable(p) - if not r: - add_nuninst(p, arch) - # for all the architectures for arch in self.options.architectures: if requested_arch and arch != requested_arch: continue @@ -1581,7 +1570,7 @@ class Britney: for pkg_name in binaries[arch][0]: r = systems[arch].is_installable(pkg_name) if not r: - add_nuninst(pkg_name, arch) + nuninst[arch].append(pkg_name) # if they are not required, removed architecture-indipendent packages nuninst[arch + "+all"] = nuninst[arch][:] @@ -1963,6 +1952,8 @@ class Britney: for p in source[BINARIES]: binary, parch = p.split("/") if arch and parch != arch: continue + # do not remove binaries which have been hijacked by other sources + if binaries[parch][0][binary][SOURCE] != pkg_name: continue # if a smooth update is possible for the package, skip it if not self.options.compatible and suite == 'unstable' and \ binary not in self.binaries[suite][parch][0] and \ @@ -1985,7 +1976,7 @@ class Britney: del binaries[parch][1][j] # finally, remove the binary package del binaries[parch][0][binary] - removeBinary(self.systems[parch], binary) + self.systems[parch].remove_binary(binary) # remove the source package if not arch: undo['sources'][pkg_name] = source @@ -2001,7 +1992,7 @@ class Britney: key = (j, arch) if key not in affected: affected.append(key) del binaries[arch][0][pkg_name] - removeBinary(self.systems[arch], pkg_name) + self.systems[arch].remove_binary(pkg_name) # add the new binary packages (if we are not removing) if pkg[0] != "-": @@ -2027,10 +2018,10 @@ class Britney: for p in self.get_full_tree(j, parch, 'testing'): key = (p, parch) if key not in affected: affected.append(key) - removeBinary(self.systems[parch], binary) + self.systems[parch].remove_binary(binary) # add/update the binary package binaries[parch][0][binary] = self.binaries[suite][parch][0][binary] - addBinary(self.systems[parch], binary, binaries[parch][0][binary][:PROVIDES] + \ + self.systems[parch].add_binary(binary, binaries[parch][0][binary][:PROVIDES] + \ [", ".join(binaries[parch][0][binary][PROVIDES]) or None]) # register new provided packages for j in binaries[parch][0][binary][PROVIDES]: @@ -2161,58 +2152,41 @@ class Britney: nuninst[arch] = [x for x in nuninst_comp[arch] if x in binaries[arch][0]] nuninst[arch + "+all"] = [x for x in nuninst_comp[arch + "+all"] if x in binaries[arch][0]] broken = nuninst[arch + "+all"] - to_check = [x[0] for x in affected if x[1] == arch] + to_check = [] + # broken packages (first round) - repaired = [] - broken_changed = True - last_broken = None - while broken_changed: - broken_changed = False - for p in to_check: - if p == last_broken: break - if p not in binaries[arch][0]: continue + for p in [x[0] for x in affected if x[1] == arch]: + if p not in binaries[arch][0]: continue + r = systems[arch].is_installable(p) + if not r and p not in broken: + to_check.append(p) + broken.append(p) + if not (skip_archall and binaries[arch][0][p][ARCHITECTURE] == 'all'): + nuninst[arch].append(p) + elif r and p in broken: + to_check.append(p) + broken.remove(p) + if not (skip_archall and binaries[arch][0][p][ARCHITECTURE] == 'all'): + nuninst[arch].remove(p) + + # broken packages (second round, reverse dependencies of the first round) + while to_check: + j = to_check.pop(0) + if j not in binaries[arch][0]: continue + for p in binaries[arch][0][j][RDEPENDS]: + if p in broken or p not in binaries[arch][0]: continue r = systems[arch].is_installable(p) if not r and p not in broken: - last_broken = p broken.append(p) - broken_changed = True + to_check.append(p) if not (skip_archall and binaries[arch][0][p][ARCHITECTURE] == 'all'): nuninst[arch].append(p) - elif r and p in broken: - last_broken = p - repaired.append(p) + elif r and p in nuninst[arch + "+all"]: broken.remove(p) - broken_changed = True + to_check.append(p) if not (skip_archall and binaries[arch][0][p][ARCHITECTURE] == 'all'): nuninst[arch].remove(p) - # broken packages (second round, reverse dependencies of the first round) - l = 0 - broken_changed = True - last_broken = None - while broken_changed: - broken_changed = False - for j in broken + repaired: - if j not in binaries[arch][0]: continue - for p in binaries[arch][0][j][RDEPENDS]: - if p in broken or p not in binaries[arch][0]: continue - r = systems[arch].is_installable(p) - if not r and p not in broken: - l = -1 - last_broken = j - broken.append(p) - broken_changed = True - if not (skip_archall and binaries[arch][0][p][ARCHITECTURE] == 'all'): - nuninst[arch].append(p) - elif r and p in nuninst[arch + "+all"]: - last_broken = p - repaired.append(p) - broken.remove(p) - broken_changed = True - if not (skip_archall and binaries[arch][0][p][ARCHITECTURE] == 'all'): - nuninst[arch].remove(p) - if l != -1 and last_broken == j: break - # if we are processing hints, go ahead if hint: nuninst_comp[arch] = nuninst[arch] @@ -2265,18 +2239,18 @@ class Britney: binary, arch = p.split("/") if "/" in pkg and arch != pkg[pkg.find("/")+1:]: continue del binaries[arch][0][binary] - removeBinary(self.systems[arch], binary) + self.systems[arch].remove_binary(binary) # undo the changes (binaries) for p in undo['binaries'].keys(): binary, arch = p.split("/") if binary[0] == "-": del binaries[arch][0][binary[1:]] - removeBinary(self.systems[arch], binary[1:]) + self.systems[arch].remove_binary(binary[1:]) else: binaries[arch][0][binary] = undo['binaries'][p] - removeBinary(self.systems[arch], binary) - addBinary(self.systems[arch], binary, binaries[arch][0][binary][:PROVIDES] + \ + self.systems[arch].remove_binary(binary) + self.systems[arch].add_binary(binary, binaries[arch][0][binary][:PROVIDES] + \ [", ".join(binaries[arch][0][binary][PROVIDES]) or None]) # undo the changes (virtual packages) @@ -2390,14 +2364,14 @@ class Britney: binary, arch = p.split("/") if "/" in pkg and arch != pkg[pkg.find("/")+1:]: continue del self.binaries['testing'][arch][0][binary] - removeBinary(self.systems[arch], binary) + self.systems[arch].remove_binary(binary) # undo the changes (binaries) for p in undo['binaries'].keys(): binary, arch = p.split("/") if binary[0] == "-": del self.binaries['testing'][arch][0][binary[1:]] - removeBinary(self.systems[arch], binary[1:]) + self.systems[arch].remove_binary(binary[1:]) else: self.binaries['testing'][arch][0][binary] = undo['binaries'][p] # undo the changes (virtual packages) diff --git a/lib/britney-py.c b/lib/britney-py.c index 8723f04..2747bd6 100644 --- a/lib/britney-py.c +++ b/lib/britney-py.c @@ -246,6 +246,106 @@ static PyObject *dpkgpackages_unsatdeps(dpkgpackages *self, PyObject *args) { return res; } + +static PyObject *dpkgpackages_remove_binary(dpkgpackages *self, PyObject *args) { + char *pkg_name; + + (void)self; /* unused */ + + if (!PyArg_ParseTuple(args, "s", &pkg_name)) + return NULL; + + dpkg_collected_package *cpkg = lookup_packagetbl(self->pkgs->packages, pkg_name); + if (cpkg == NULL) return Py_BuildValue("i", 0); + + remove_package(self->pkgs, cpkg); + return Py_BuildValue("i", 1); +} + +static PyObject *dpkgpackages_add_binary(dpkgpackages *self, PyObject *args) { + char *pkg_name; + PyObject *value, *pyString; + + (void)self; /* unused */ + + if (!PyArg_ParseTuple(args, "sO", &pkg_name, &value) || + !PyList_Check(value)) return NULL; + + /* initialize the new package */ + dpkg_package *pkg; + pkg = block_malloc(sizeof(dpkg_package)); + pkg->package = strdup(pkg_name); + pkg->priority = 0; + pkg->details = NULL; + pkg->depends[2] = NULL; + pkg->depends[3] = NULL; + + pyString = PyList_GetItem(value, 0); + if (pyString == NULL) return NULL; + pkg->version = PyString_AsString(pyString); + + pyString = PyList_GetItem(value, 2); + if (pyString == NULL) return NULL; + pkg->source = PyString_AsString(pyString); + + pyString = PyList_GetItem(value, 3); + if (pyString == NULL) return NULL; + pkg->source_ver = PyString_AsString(pyString); + + pyString = PyList_GetItem(value, 4); + if (pyString == NULL) return NULL; + pkg->arch_all = (!strcmp(PyString_AsString(pyString), "all") ? 1 : 0); + + pyString = PyList_GetItem(value, 5); + if (pyString == NULL) return NULL; + if (pyString != Py_None) { + pkg->depends[0] = read_dep_andor(PyString_AsString(pyString)); + } else pkg->depends[0] = NULL; + + pyString = PyList_GetItem(value, 6); + if (pyString == NULL) return NULL; + if (pyString != Py_None) { + pkg->depends[1] = read_dep_andor(PyString_AsString(pyString)); + } else pkg->depends[1] = NULL; + + pyString = PyList_GetItem(value, 7); + if (pyString == NULL) return NULL; + if (pyString != Py_None) { + pkg->conflicts = read_dep_and(PyString_AsString(pyString)); + } else pkg->conflicts = NULL; + + pyString = PyList_GetItem(value, 8); + if (pyString == NULL) return NULL; + if (pyString != Py_None) { + pkg->provides = read_packagenames(PyString_AsString(pyString)); + } else pkg->provides = NULL; + + add_package(self->pkgs, pkg); + + return Py_BuildValue("i", 1); +} + +static PyObject *dpkgpackages_print_providers(dpkgpackages *self, PyObject *args) { + char *pkg_name; + + (void)self; /* unused */ + + if (!PyArg_ParseTuple(args, "s", &pkg_name)) return NULL; + + virtualpkg *list; + virtualpkg **where; + list = lookup_virtualpkgtbl(self->pkgs->virtualpkgs, pkg_name); + where = &list; + printf("Virtual package: %s\n", pkg_name); + while (*where != NULL) { + printf(" + provided by: %s\n", (*where)->value.pkg->pkg->package); + where = &(*where)->next; + } + printf("\n"); + + return Py_BuildValue("i", 1); +} + static PyObject *dpkgpackages_getattr(dpkgpackages *self, char *name) { static struct PyMethodDef dpkgsources_methods[] = { { "is_present", (binaryfunc) dpkgpackages_ispresent, @@ -268,6 +368,14 @@ static PyObject *dpkgpackages_getattr(dpkgpackages *self, char *name) { METH_VARARGS, NULL }, { "unsatisfiable_deps", (binaryfunc) dpkgpackages_unsatdeps, METH_VARARGS, NULL }, + + { "remove_binary", (binaryfunc) dpkgpackages_remove_binary, + METH_VARARGS, NULL }, + { "add_binary", (binaryfunc) dpkgpackages_add_binary, + METH_VARARGS, NULL }, + { "print_providers", (binaryfunc) dpkgpackages_print_providers, + METH_VARARGS, NULL }, + { NULL, NULL, 0, NULL } }; @@ -889,7 +997,7 @@ static PyObject *build_system(PyObject *self, PyObject *args) { /* initialize the new package */ dpkg_package *pkg; pkg = block_malloc(sizeof(dpkg_package)); - pkg->package = PyString_AsString(key); + pkg->package = strdup(PyString_AsString(key)); pkg->priority = 0; pkg->details = NULL; pkg->depends[2] = NULL; @@ -949,86 +1057,6 @@ static PyObject *build_system(PyObject *self, PyObject *args) { return (PyObject *)res; } -static PyObject *remove_binary(PyObject *self, PyObject *args) { - char *pkg_name; - dpkgpackages *pkgs; - - (void)self; /* unused */ - - if (!PyArg_ParseTuple(args, "Os", &pkgs, &pkg_name)) - return NULL; - - dpkg_collected_package *cpkg = lookup_packagetbl(pkgs->pkgs->packages, pkg_name); - if (cpkg == NULL) return Py_BuildValue("i", 0); - - remove_package(pkgs->pkgs, cpkg); - return Py_BuildValue("i", 1); -} - -static PyObject *add_binary(PyObject *self, PyObject *args) { - char *pkg_name; - dpkgpackages *pkgs; - PyObject *value, *pyString; - - (void)self; /* unused */ - - if (!PyArg_ParseTuple(args, "OsO", &pkgs, &pkg_name, &value) || - !PyList_Check(value)) return NULL; - - /* initialize the new package */ - dpkg_package *pkg; - pkg = block_malloc(sizeof(dpkg_package)); - pkg->package = pkg_name; - pkg->priority = 0; - pkg->details = NULL; - pkg->depends[2] = NULL; - pkg->depends[3] = NULL; - - pyString = PyList_GetItem(value, 0); - if (pyString == NULL) return NULL; - pkg->version = PyString_AsString(pyString); - - pyString = PyList_GetItem(value, 2); - if (pyString == NULL) return NULL; - pkg->source = PyString_AsString(pyString); - - pyString = PyList_GetItem(value, 3); - if (pyString == NULL) return NULL; - pkg->source_ver = PyString_AsString(pyString); - - pyString = PyList_GetItem(value, 4); - if (pyString == NULL) return NULL; - pkg->arch_all = (!strcmp(PyString_AsString(pyString), "all") ? 1 : 0); - - pyString = PyList_GetItem(value, 5); - if (pyString == NULL) return NULL; - if (pyString != Py_None) { - pkg->depends[0] = read_dep_andor(PyString_AsString(pyString)); - } else pkg->depends[0] = NULL; - - pyString = PyList_GetItem(value, 6); - if (pyString == NULL) return NULL; - if (pyString != Py_None) { - pkg->depends[1] = read_dep_andor(PyString_AsString(pyString)); - } else pkg->depends[1] = NULL; - - pyString = PyList_GetItem(value, 7); - if (pyString == NULL) return NULL; - if (pyString != Py_None) { - pkg->conflicts = read_dep_and(PyString_AsString(pyString)); - } else pkg->conflicts = NULL; - - pyString = PyList_GetItem(value, 8); - if (pyString == NULL) return NULL; - if (pyString != Py_None) { - pkg->provides = read_packagenames(PyString_AsString(pyString)); - } else pkg->provides = NULL; - - add_package(pkgs->pkgs, pkg); - - return Py_BuildValue("i", 1); -} - /************************************************************************** * module initialisation @@ -1041,8 +1069,6 @@ static PyMethodDef britneymethods[] = { { "versioncmp", apt_versioncmp, METH_VARARGS, NULL }, { "buildSystem", build_system, METH_VARARGS, NULL }, - { "removeBinary", remove_binary, METH_VARARGS, NULL }, - { "addBinary", add_binary, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; diff --git a/lib/example.py b/lib/example.py index 48026a1..9a8bd63 100755 --- a/lib/example.py +++ b/lib/example.py @@ -21,7 +21,7 @@ packages = {'phpldapadmin': ['1.0', 'web', 'phpldapadmin', '1.0', 'all', '', 'ap system = britney.buildSystem('i386', packages) print system.is_installable('phpldapadmin'), system.packages -britney.removeBinary(system, 'apache2') +system.remove_binary('apache2') print system.is_installable('phpldapadmin'), system.packages -britney.addBinary(system, 'apache2', ['2.0', 'web', 'apache2', '2.0', 'i386', '', '', 'phpldapadmin (<= 1.0~)', '', [], []]) +system.add_binary('apache2', ['2.0', 'web', 'apache2', '2.0', 'i386', '', '', 'phpldapadmin (<= 1.0~)', '', [], []]) print system.is_installable('phpldapadmin'), system.packages