cachegroup.cc 6.99 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
/*
 * cachegroup.cc - Wrapper around pkgCache::GrpIterator
 *
 * Copyright 2011 Julian Andres Klode <jak@debian.org>
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */
#include <Python.h>
#include "apt_pkgmodule.h"
#include "generic.h"
#include <apt-pkg/pkgcache.h>

struct PyGroup : CppPyObject<pkgCache::GrpIterator> {
    pkgCache::PkgIterator current;
    int nextIndex;
};

static PyObject *group_new(PyTypeObject *type,PyObject *args,
                                  PyObject *kwds)
{
    PyObject *pyCache;
    char *name;
    char *kwlist[] = {"cache", "name", NULL};
    if (PyArg_ParseTupleAndKeywords(args, kwds, "O!s", kwlist,
                                    &PyCache_Type, &pyCache,
                                    &name) == 0)
        return 0;

    pkgCache *cache = GetCpp<pkgCache *>(pyCache);

    pkgCache::GrpIterator grp = cache->FindGrp(name);

    if (!grp.end()) {
        return PyGroup_FromCpp(grp, true, pyCache);
    } else {
        PyErr_SetString(PyExc_KeyError, name);
        return NULL;
    }
}

static const char group_find_package_doc[] =
    "find_package(architecture: str) -> Package\n\n"
    "Return a package for the given architecture, or None if none exists";
static PyObject *group_find_package(PyObject *self,PyObject *args)
{
    pkgCache::GrpIterator grp = GetCpp<pkgCache::GrpIterator>(self);
    PyObject *owner = GetOwner<pkgCache::GrpIterator>(self);
    
    char *architecture;
    if (PyArg_ParseTuple(args, "s", &architecture) == 0)
        return 0;

    pkgCache::PkgIterator pkg = grp.FindPkg(architecture);

    if (pkg.end()) {
        Py_RETURN_NONE;
    } else {
        return PyPackage_FromCpp(pkg, true, owner ? owner : self);
    }
}

static const char group_find_preferred_package_doc[] =
    "find_preferred_package(prefer_non_virtual: bool = True) -> Package\n\n"
    "Return a package for the best architecture, either the native one\n"
    "or the first found one. If none exists, return None. If non_virtual\n"
    "is True, prefer non-virtual packages over virtual ones.";
static PyObject *group_find_preferred_package(PyObject *self,PyObject *args,
                                              PyObject *kwds)
{
    pkgCache::GrpIterator grp = GetCpp<pkgCache::GrpIterator>(self);
    PyObject *owner = GetOwner<pkgCache::GrpIterator>(self);
    char nonvirtual = 1;
    char *kwlist[] = {"prefer_non_virtual", NULL};
    if (PyArg_ParseTupleAndKeywords(args, kwds, "|b", kwlist, &nonvirtual) == 0)
        return 0;
    pkgCache::PkgIterator pkg = grp.FindPreferredPkg(nonvirtual);

    if (pkg.end()) {
        Py_RETURN_NONE;
    } else {
        return PyPackage_FromCpp(pkg, true, owner);
    }
}

static PyMethodDef group_methods[] = {
    {"find_package",group_find_package,METH_VARARGS,group_find_package_doc},
    {"find_preferred_package",(PyCFunction) group_find_preferred_package,
     METH_VARARGS|METH_KEYWORDS,group_find_preferred_package_doc},
    {}
};

static PyObject *group_seq_item(PyObject *pySelf,Py_ssize_t index)
{
    PyGroup *self = static_cast<PyGroup *>(pySelf);
    pkgCache::GrpIterator grp = GetCpp<pkgCache::GrpIterator>(self);
    PyObject *owner = GetOwner<pkgCache::GrpIterator>(self);

    if (self->nextIndex > index || self->nextIndex == 0)  {
        self->nextIndex = 1;
        new (&self->current) pkgCache::PkgIterator(grp.PackageList());
    }
        
    if (self->nextIndex != index + 1) {
        while (self->nextIndex <= index && !self->current.end()) {
            self->current = grp.NextPkg(self->current);
            self->nextIndex++;
        }
    }

    if (self->current.end())
        return PyErr_Format(PyExc_IndexError, "Out of range: %zd", index);

    return PyPackage_FromCpp(self->current, true, owner);
}


static PySequenceMethods group_as_sequence =
{
   0,
   0,                // concat
   0,                // repeat
   group_seq_item,
   0,                // slice
   0,                // assign item
   0                 // assign slice
};


static const char group_doc[] = "Group(cache, name)\n\n"
    "Group of packages with the same name.\n\n"
    "Provides access to all packages sharing a name. Can be used this\n"
    "like a list, or by using the special find_*() methods. If you use\n"
    "it as a sequence, make sure to access it linearly, as this uses a\n"
    "linked list internally.";
PyTypeObject PyGroup_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "apt_pkg.Group",                     // tp_name
    sizeof(PyGroup),                     // tp_basicsize
    0,                                   // tp_itemsize
    // Methods
    CppDealloc<pkgCache::GrpIterator>,   // tp_dealloc
    0,                                   // tp_print
    0,                                   // tp_getattr
    0,                                   // tp_setattr
    0,                                   // tp_compare
    0,                                   // tp_repr
    0,                                   // tp_as_number
    &group_as_sequence,                  // tp_as_sequence
    0,                                   // tp_as_mapping
    0,                                   // tp_hash
    0,                                   // tp_call
    0,                                   // tp_str
    0,                                   // tp_getattro
    0,                                   // tp_setattro
    0,                                   // tp_as_buffer
    Py_TPFLAGS_DEFAULT,                  // tp_flags
    group_doc,                           // tp_doc
    0,                                   // tp_traverse
    0,                                   // tp_clear
    0,                                   // tp_richcompare
    0,                                   // tp_weaklistoffset
    0,                                   // tp_iter
    0,                                   // tp_iternext
    group_methods,                       // tp_methods
    0,                                   // tp_members
    0,                                   // tp_getset
    0,                                   // tp_base
    0,                                   // tp_dict
    0,                                   // tp_descr_get
    0,                                   // tp_descr_set
    0,                                   // tp_dictoffset
    0,                                   // tp_init
    0,                                   // tp_alloc
    group_new,                           // tp_new
};